commit 003be1952262ccc8eed917cdc760ee860fdaf31f Author: bing Date: Fri Apr 3 11:32:07 2026 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa98179 --- /dev/null +++ b/.gitignore @@ -0,0 +1,122 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +/build +/.cache +/Third/QxOrm/lib +**/.vscode/ +**/build + +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +*.qbs.user* +CMakeLists.txt.user* +CMakeLists.txt.user + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + +# Directories with generated files +.moc/ +.obj/ +.pch/ +.rcc/ +.uic/ +/build*/ +.VSCodeCounter +bin +.vs +CMakeSettings.json +CMakeUserPresets.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..efcb118 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,676 @@ +############################################################################# +## +## 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 +## +############################################################################# + +cmake_minimum_required(VERSION 3.10) + +project(XdlOrm VERSION 1.5.0 LANGUAGES CXX) + +# Include Conan generated files +if(EXISTS ${CMAKE_BINARY_DIR}/conan_toolchain.cmake) + include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake) +endif() + +# Include QxOrm library configuration file (should be included by all projects which depend on QxOrm) +include(./XdlOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(QX_HEADERS + ./include/QxPrecompiled.h + ./include/QxMemLeak/bool_array.h + ./include/QxMemLeak/class_level_lock.h + ./include/QxMemLeak/cont_ptr_utils.h + ./include/QxMemLeak/debug_new.h + ./include/QxMemLeak/fast_mutex.h + ./include/QxMemLeak/fixed_mem_pool.h + ./include/QxMemLeak/mem_leak.h + ./include/QxMemLeak/mem_pool_base.h + ./include/QxMemLeak/object_level_lock.h + ./include/QxMemLeak/pctimer.h + ./include/QxMemLeak/set_assign.h + ./include/QxMemLeak/static_assert.h + ./include/QxMemLeak/static_mem_pool.h + ./include/QxSingleton/IxSingleton.h + ./include/QxSingleton/QxSingleton.h + ./include/QxSingleton/QxSingletonX.h + ./include/QxSingleton/QxSingletonInit.h + ./include/QxFactory/IxFactory.h + ./include/QxFactory/QxFactory.h + ./include/QxFactory/QxFactoryX.h + ./include/QxCommon/QxConfig.h + ./include/QxCommon/QxMacro.h + ./include/QxCommon/QxHashValue.h + ./include/QxCommon/QxBool.h + ./include/QxCommon/QxCache.h + ./include/QxCommon/QxPropertyBag.h + ./include/QxCommon/QxSimpleCrypt.h + ./include/QxCommon/QxAnyCastDynamic.h + ./include/QxCommon/QxException.h + ./include/QxCommon/QxExceptionCode.h + ./include/QxCommon/QxAny.h + ./include/QxConvert/QxConvert.h + ./include/QxConvert/QxConvert_Impl.h + ./include/QxConvert/QxConvert_Export.h + ./include/QxRegister/IxClass.h + ./include/QxRegister/QxClass.h + ./include/QxRegister/QxClassX.h + ./include/QxRegister/QxClassName.h + ./include/QxRegister/QxRegister.h + ./include/QxRegister/QxRegisterInternalHelper.h + ./include/QxRegister/IxTypeInfo.h + ./include/QxRegister/QxRegisterQtProperty.h + ./include/QxRegister/QxVersion.h + ./include/QxCollection/IxCollection.h + ./include/QxCollection/QxCollection.h + ./include/QxCollection/QxCollectionIterator.h + ./include/QxCollection/QxForeach.h + ./include/QxDataMember/IxDataMember.h + ./include/QxDataMember/IxDataMemberX.h + ./include/QxDataMember/QxDataMember.h + ./include/QxDataMember/QxDataMemberX.h + ./include/QxDataMember/QxDataMember_QObject.h + ./include/QxDataMember/QxDataMember_PImpl.h + ./include/QxDao/IxSqlQueryBuilder.h + ./include/QxDao/QxSqlQueryBuilder.h + ./include/QxDao/QxSqlQueryHelper.h + ./include/QxDao/QxSqlQuery.h + ./include/QxDao/QxSqlDatabase.h + ./include/QxDao/IxSqlRelation.h + ./include/QxDao/QxSqlRelation.h + ./include/QxDao/QxSqlRelationParams.h + ./include/QxDao/QxSqlRelation_ManyToMany.h + ./include/QxDao/QxSqlRelation_ManyToOne.h + ./include/QxDao/QxSqlRelation_OneToMany.h + ./include/QxDao/QxSqlRelation_OneToOne.h + ./include/QxDao/QxSqlRelation_RawData.h + ./include/QxDao/QxDao.h + ./include/QxDao/QxDao_Impl.h + ./include/QxDao/QxDaoStrategy.h + ./include/QxDao/QxDaoPointer.h + ./include/QxDao/QxDao_IsDirty.h + ./include/QxDao/QxSoftDelete.h + ./include/QxDao/QxSqlError.h + ./include/QxDao/QxSession.h + ./include/QxDao/QxDateNeutral.h + ./include/QxDao/QxTimeNeutral.h + ./include/QxDao/QxDateTimeNeutral.h + ./include/QxDao/IxDao_Helper.h + ./include/QxDao/IxPersistable.h + ./include/QxDao/IxPersistableCollection.h + ./include/QxDao/IxPersistableList.h + ./include/QxDao/QxSqlJoin.h + ./include/QxDao/QxSqlRelationLinked.h + ./include/QxDao/QxDaoAsync.h + ./include/QxDao/QxSqlSaveMode.h + ./include/QxDao/QxDaoThrowable.h + ./include/QxDao/QxSqlElement/IxSqlElement.h + ./include/QxDao/QxSqlElement/QxSqlCompare.h + ./include/QxDao/QxSqlElement/QxSqlElement.h + ./include/QxDao/QxSqlElement/QxSqlElementTemp.h + ./include/QxDao/QxSqlElement/QxSqlEmbedQuery.h + ./include/QxDao/QxSqlElement/QxSqlExpression.h + ./include/QxDao/QxSqlElement/QxSqlFreeText.h + ./include/QxDao/QxSqlElement/QxSqlIn.h + ./include/QxDao/QxSqlElement/QxSqlIsBetween.h + ./include/QxDao/QxSqlElement/QxSqlIsNull.h + ./include/QxDao/QxSqlElement/QxSqlLimit.h + ./include/QxDao/QxSqlElement/QxSqlSort.h + ./include/QxDao/QxSqlGenerator/IxSqlGenerator.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.h + ./include/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.h + ./include/QxDao/QxRepository/IxRepository.h + ./include/QxDao/QxRepository/QxRepository.h + ./include/QxDao/QxRepository/QxRepositoryX.h + ./include/QxDao/QxMongoDB/QxMongoDB_Helper.h + ./include/QxSerialize/QxArchive.h + ./include/QxSerialize/QxClone.h + ./include/QxSerialize/QxDump.h + ./include/QxSerialize/QxSerializeFastCompil.h + ./include/QxSerialize/QxSerializeInvoker.h + ./include/QxSerialize/QxSerializeMacro.h + ./include/QxSerialize/QxSerialize.h + ./include/QxSerialize/QxSerializeQDataStream.h + ./include/QxSerialize/QxSerializeCheckInstance.h + ./include/QxSerialize/QxSerializeQJson.h + ./include/QxSerialize/boost/class_export/qx_boost_class_export.h + ./include/QxSerialize/boost/portable_binary/portable_archive_exception.hpp + ./include/QxSerialize/boost/portable_binary/portable_iarchive.hpp + ./include/QxSerialize/boost/portable_binary/portable_oarchive.hpp + ./include/QxSerialize/boost/QxSerializeInclude.h + ./include/QxSerialize/boost/QxSerialize_shared_ptr.h + ./include/QxSerialize/boost/QxSerialize_tuple.h + ./include/QxSerialize/boost/QxSerialize_unordered_map.h + ./include/QxSerialize/boost/QxSerialize_unordered_set.h + ./include/QxSerialize/boost/QxExportDllMacroHpp.h + ./include/QxSerialize/boost/QxExportDllMacroCpp.h + ./include/QxSerialize/boost/QxExportDllBoostArchive.h + ./include/QxSerialize/boost/QxImportDllBoostArchive.h + ./include/QxSerialize/Qt/QxSerialize_QBrush.h + ./include/QxSerialize/Qt/QxSerialize_QByteArray.h + ./include/QxSerialize/Qt/QxSerialize_QColor.h + ./include/QxSerialize/Qt/QxSerialize_QDate.h + ./include/QxSerialize/Qt/QxSerialize_QDateTime.h + ./include/QxSerialize/Qt/QxSerialize_QFont.h + ./include/QxSerialize/Qt/QxSerialize_QHash.h + ./include/QxSerialize/Qt/QxSerialize_QImage.h + ./include/QxSerialize/Qt/QxSerialize_QFlags.h + ./include/QxSerialize/Qt/QxSerialize_QLinkedList.h + ./include/QxSerialize/Qt/QxSerialize_QList.h + ./include/QxSerialize/Qt/QxSerialize_QMap.h + ./include/QxSerialize/Qt/QxSerialize_QMatrix.h + ./include/QxSerialize/Qt/QxSerialize_QObject.h + ./include/QxSerialize/Qt/QxSerialize_QPair.h + ./include/QxSerialize/Qt/QxSerialize_QPicture.h + ./include/QxSerialize/Qt/QxSerialize_QPixmap.h + ./include/QxSerialize/Qt/QxSerialize_QPoint.h + ./include/QxSerialize/Qt/QxSerialize_QRect.h + ./include/QxSerialize/Qt/QxSerialize_QRegExp.h + ./include/QxSerialize/Qt/QxSerialize_QRegion.h + ./include/QxSerialize/Qt/QxSerialize_QScopedPointer.h + ./include/QxSerialize/Qt/QxSerialize_QSharedPointer.h + ./include/QxSerialize/Qt/QxSerialize_QSize.h + ./include/QxSerialize/Qt/QxSerialize_QString.h + ./include/QxSerialize/Qt/QxSerialize_QTime.h + ./include/QxSerialize/Qt/QxSerialize_QUrl.h + ./include/QxSerialize/Qt/QxSerialize_QUuid.h + ./include/QxSerialize/Qt/QxSerialize_QVariant.h + ./include/QxSerialize/Qt/QxSerialize_QVector.h + ./include/QxSerialize/Qt/QxSerialize_QWeakPointer.h + ./include/QxSerialize/Qt/QxSerialize_QMultiHash.h + ./include/QxSerialize/Qt/QxSerialize_QMultiMap.h + ./include/QxSerialize/Qt/QxSerialize_QStringList.h + ./include/QxSerialize/Qt/QxSerialize_QSqlError.h + ./include/QxSerialize/Qx/QxSerialize_QxCollection.h + ./include/QxSerialize/Qx/QxSerialize_QxDaoPointer.h + ./include/QxSerialize/std/QxSerialize_std_tuple.h + ./include/QxSerialize/std/QxSerialize_std_shared_ptr.h + ./include/QxSerialize/std/QxSerialize_std_unique_ptr.h + ./include/QxSerialize/std/QxSerialize_std_unordered_map.h + ./include/QxSerialize/std/QxSerialize_std_unordered_set.h + ./include/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.h + ./include/QxSerialize/QxBoostSerializeHelper/QxBoostInitGuid.h + ./include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeHelper.h + ./include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelper.h + ./include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_all_include.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_optional.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_scoped_ptr.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_shared_ptr.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_tuple.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_map.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_set.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QFlags.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QScopedPointer.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QSharedPointer.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_QWeakPointer.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_list.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_map.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_pair.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_set.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_shared_ptr.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_tuple.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unique_ptr.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_map.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_set.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_std_vector.h + ./include/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.h + ./include/QxSerialize/QJson/QxSerializeQJson_all_include.h + ./include/QxSerialize/QJson/QxSerializeQJson_boost_scoped_ptr.h + ./include/QxSerialize/QJson/QxSerializeQJson_boost_shared_ptr.h + ./include/QxSerialize/QJson/QxSerializeQJson_boost_tuple.h + ./include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_map.h + ./include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_set.h + ./include/QxSerialize/QJson/QxSerializeQJson_IxParameter.h + ./include/QxSerialize/QJson/QxSerializeQJson_IxService.h + ./include/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.h + ./include/QxSerialize/QJson/QxSerializeQJson_IxPersistable.h + ./include/QxSerialize/QJson/QxSerializeQJson_QBrush.h + ./include/QxSerialize/QJson/QxSerializeQJson_QColor.h + ./include/QxSerialize/QJson/QxSerializeQJson_QFlags.h + ./include/QxSerialize/QJson/QxSerializeQJson_QFont.h + ./include/QxSerialize/QJson/QxSerializeQJson_QHash.h + ./include/QxSerialize/QJson/QxSerializeQJson_QImage.h + ./include/QxSerialize/QJson/QxSerializeQJson_QLinkedList.h + ./include/QxSerialize/QJson/QxSerializeQJson_QList.h + ./include/QxSerialize/QJson/QxSerializeQJson_QMap.h + ./include/QxSerialize/QJson/QxSerializeQJson_QMatrix.h + ./include/QxSerialize/QJson/QxSerializeQJson_QMultiHash.h + ./include/QxSerialize/QJson/QxSerializeQJson_QMultiMap.h + ./include/QxSerialize/QJson/QxSerializeQJson_QObject.h + ./include/QxSerialize/QJson/QxSerializeQJson_QPair.h + ./include/QxSerialize/QJson/QxSerializeQJson_QPicture.h + ./include/QxSerialize/QJson/QxSerializeQJson_QPixmap.h + ./include/QxSerialize/QJson/QxSerializeQJson_QPoint.h + ./include/QxSerialize/QJson/QxSerializeQJson_QRect.h + ./include/QxSerialize/QJson/QxSerializeQJson_QRegExp.h + ./include/QxSerialize/QJson/QxSerializeQJson_QRegion.h + ./include/QxSerialize/QJson/QxSerializeQJson_QScopedPointer.h + ./include/QxSerialize/QJson/QxSerializeQJson_QSharedPointer.h + ./include/QxSerialize/QJson/QxSerializeQJson_QSize.h + ./include/QxSerialize/QJson/QxSerializeQJson_QSqlError.h + ./include/QxSerialize/QJson/QxSerializeQJson_QStringList.h + ./include/QxSerialize/QJson/QxSerializeQJson_QUrl.h + ./include/QxSerialize/QJson/QxSerializeQJson_QVector.h + ./include/QxSerialize/QJson/QxSerializeQJson_QWeakPointer.h + ./include/QxSerialize/QJson/QxSerializeQJson_QVariantHash.h + ./include/QxSerialize/QJson/QxSerializeQJson_QVariantMap.h + ./include/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxCollection.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxDaoPointer.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.h + ./include/QxSerialize/QJson/QxSerializeQJson_QxTransaction.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_list.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_map.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_pair.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_set.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_shared_ptr.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_tuple.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_unique_ptr.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_unordered_map.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_unordered_set.h + ./include/QxSerialize/QJson/QxSerializeQJson_std_vector.h + ./include/QxRestApi/QxRestApi.h + ./include/QxTraits/get_base_class.h + ./include/QxTraits/get_primary_key.h + ./include/QxTraits/get_class_name.h + ./include/QxTraits/get_class_name_primitive.h + ./include/QxTraits/is_boost_intrusive_ptr.h + ./include/QxTraits/is_boost_scoped_ptr.h + ./include/QxTraits/is_boost_shared_ptr.h + ./include/QxTraits/is_boost_weak_ptr.h + ./include/QxTraits/is_qt_shared_data_ptr.h + ./include/QxTraits/is_qt_shared_ptr.h + ./include/QxTraits/is_qt_scoped_ptr.h + ./include/QxTraits/is_qt_weak_ptr.h + ./include/QxTraits/is_smart_ptr.h + ./include/QxTraits/is_boost_unordered_map.h + ./include/QxTraits/is_boost_unordered_set.h + ./include/QxTraits/is_container.h + ./include/QxTraits/is_qt_hash.h + ./include/QxTraits/is_qt_linked_list.h + ./include/QxTraits/is_qt_list.h + ./include/QxTraits/is_qt_map.h + ./include/QxTraits/is_qt_multi_hash.h + ./include/QxTraits/is_qt_multi_map.h + ./include/QxTraits/is_qt_set.h + ./include/QxTraits/is_qt_vector.h + ./include/QxTraits/is_qt_variant_compatible.h + ./include/QxTraits/is_qx_collection.h + ./include/QxTraits/is_std_list.h + ./include/QxTraits/is_std_map.h + ./include/QxTraits/is_std_set.h + ./include/QxTraits/is_std_vector.h + ./include/QxTraits/is_container_base_of.h + ./include/QxTraits/is_container_key_value.h + ./include/QxTraits/is_container_to_pod.h + ./include/QxTraits/is_ptr_base_of.h + ./include/QxTraits/is_ptr_to_pod.h + ./include/QxTraits/is_qx_pod.h + ./include/QxTraits/is_qx_registered.h + ./include/QxTraits/is_smart_ptr_base_of.h + ./include/QxTraits/is_smart_ptr_to_pod.h + ./include/QxTraits/archive_wide_traits.h + ./include/QxTraits/archive_printable.h + ./include/QxTraits/remove_attr.h + ./include/QxTraits/remove_smart_ptr.h + ./include/QxTraits/construct_ptr.h + ./include/QxTraits/construct_null_qvariant.h + ./include/QxTraits/get_sql_type.h + ./include/QxTraits/generic_container.h + ./include/QxTraits/is_valid_primary_key.h + ./include/QxTraits/is_qx_dao_ptr.h + ./include/QxTraits/is_equal.h + ./include/QxTraits/qt_meta_object.h + ./include/QxTraits/qx_traits.h + ./include/QxTraits/is_std_shared_ptr.h + ./include/QxTraits/is_std_unique_ptr.h + ./include/QxTraits/is_std_unordered_map.h + ./include/QxTraits/is_std_unordered_set.h + ./include/QxTraits/is_std_weak_ptr.h + ./include/QxFunction/IxFunction.h + ./include/QxFunction/QxFunction_0.h + ./include/QxFunction/QxFunction_1.h + ./include/QxFunction/QxFunction_2.h + ./include/QxFunction/QxFunction_3.h + ./include/QxFunction/QxFunction_4.h + ./include/QxFunction/QxFunction_5.h + ./include/QxFunction/QxFunction_6.h + ./include/QxFunction/QxFunction_7.h + ./include/QxFunction/QxFunction_8.h + ./include/QxFunction/QxFunction_9.h + ./include/QxFunction/QxFunctionError.h + ./include/QxFunction/QxFunctionInclude.h + ./include/QxFunction/QxFunctionMacro.h + ./include/QxFunction/QxParameters.h + ./include/QxService/IxParameter.h + ./include/QxService/IxService.h + ./include/QxService/QxClientAsync.h + ./include/QxService/QxConnect.h + ./include/QxService/QxServer.h + ./include/QxService/QxService.h + ./include/QxService/QxThread.h + ./include/QxService/QxThreadPool.h + ./include/QxService/QxTools.h + ./include/QxService/QxTransaction.h + ./include/QxHttpServer/QxHttpRequest.h + ./include/QxHttpServer/QxHttpResponse.h + ./include/QxHttpServer/QxHttpServer.h + ./include/QxHttpServer/QxHttpTransaction.h + ./include/QxHttpServer/QxHttpCookie.h + ./include/QxHttpServer/QxHttpSession.h + ./include/QxHttpServer/QxHttpSessionManager.h + ./include/QxValidator/IxValidator.h + ./include/QxValidator/IxValidatorX.h + ./include/QxValidator/QxInvalidValue.h + ./include/QxValidator/QxInvalidValueX.h + ./include/QxValidator/QxValidator.h + ./include/QxValidator/QxValidatorError.h + ./include/QxValidator/QxValidatorFct.h + ./include/QxValidator/QxValidatorX.h + ./include/QxModelView/IxModel.h + ./include/QxModelView/QxModel.h + ./include/QxModelView/QxNestedModel.h + ./include/QxModelView/QxModelService.h + ./include/QxModelView/QxModelRowCompare.h + ./include/QxExtras/QxBoostOptionalOnly.h + ./include/QxExtras/QxStdOptional.h + ./include/QxOrm.h + ./include/QxOrm_Impl.h + ./include/QxMemLeak.h + ./include/QxDaoRepository.h + ./include/QxModelView.h + ./include/QxServices.h +) + +# To reduce compilation times, it is recommended to define _QX_UNITY_BUILD compilation option +# More details in QxOrm.cmake configuration file, section 'Unity Build' +if(_QX_UNITY_BUILD) + + set(QX_SRCS + ./src/all.cpp + ) + +else() # _QX_UNITY_BUILD + + set(QX_SRCS + ./src/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.cpp + ./src/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.cpp + ./src/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.cpp + ./src/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.cpp + ./src/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_IxService.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QBrush.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QColor.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QFont.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QImage.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QMatrix.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QObject.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QPicture.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QPixmap.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QPoint.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QRect.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QRegExp.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QRegion.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QSize.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QSqlError.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QStringList.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.cpp + ./src/QxSerialize/QJson/QxSerializeQJson_QxTransaction.cpp + ./src/QxMemLeak/bool_array.cpp + ./src/QxMemLeak/debug_new.cpp + ./src/QxMemLeak/mem_pool_base.cpp + ./src/QxMemLeak/static_mem_pool.cpp + ./src/QxSingleton/IxSingleton.cpp + ./src/QxSingleton/QxSingletonX.cpp + ./src/QxSingleton/QxSingletonInit.cpp + ./src/QxFactory/IxFactory.cpp + ./src/QxFactory/QxFactoryX.cpp + ./src/QxCollection/QxCollection.cpp + ./src/QxCommon/QxBool.cpp + ./src/QxDao/QxSession.cpp + ./src/QxDao/IxDao_Helper.cpp + ./src/QxDao/IxPersistable.cpp + ./src/QxDao/IxPersistableCollection.cpp + ./src/QxDao/IxPersistableList.cpp + ./src/QxDao/QxSqlRelationLinked.cpp + ./src/QxCommon/QxCache.cpp + ./src/QxCommon/QxSimpleCrypt.cpp + ./src/QxConvert/QxConvert_Export.cpp + ./src/QxRegister/IxClass.cpp + ./src/QxRegister/QxClassX.cpp + ./src/QxDataMember/IxDataMember.cpp + ./src/QxDataMember/IxDataMemberX.cpp + ./src/QxDataMember/QxDataMember_QObject.cpp + ./src/QxTraits/unit_test_is_smart_ptr.cpp + ./src/QxTraits/unit_test_is_container.cpp + ./src/QxDao/IxSqlQueryBuilder.cpp + ./src/QxDao/QxSqlDatabase.cpp + ./src/QxDao/IxSqlRelation.cpp + ./src/QxDao/QxSqlQuery.cpp + ./src/QxDao/QxDaoAsync.cpp + ./src/QxDao/QxSqlRelationParams.cpp + ./src/QxDao/QxSoftDelete.cpp + ./src/QxDao/QxDateNeutral.cpp + ./src/QxDao/QxDateTimeNeutral.cpp + ./src/QxDao/QxTimeNeutral.cpp + ./src/QxDao/QxSqlElement/IxSqlElement.cpp + ./src/QxDao/QxSqlElement/QxSqlCompare.cpp + ./src/QxDao/QxSqlElement/QxSqlElementTemp.cpp + ./src/QxDao/QxSqlElement/QxSqlEmbedQuery.cpp + ./src/QxDao/QxSqlElement/QxSqlExpression.cpp + ./src/QxDao/QxSqlElement/QxSqlFreeText.cpp + ./src/QxDao/QxSqlElement/QxSqlIn.cpp + ./src/QxDao/QxSqlElement/QxSqlIsBetween.cpp + ./src/QxDao/QxSqlElement/QxSqlIsNull.cpp + ./src/QxDao/QxSqlElement/QxSqlLimit.cpp + ./src/QxDao/QxSqlElement/QxSqlSort.cpp + ./src/QxDao/QxSqlGenerator/IxSqlGenerator.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.cpp + ./src/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.cpp + ./src/QxDao/QxRepository/IxRepository.cpp + ./src/QxDao/QxRepository/QxRepositoryX.cpp + ./src/QxDao/QxMongoDB/QxMongoDB_Helper.cpp + ./src/QxSerialize/QxSerializeCheckInstance.cpp + ./src/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.cpp + ./src/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.cpp + ./src/QxSerialize/boost/QxExportDllBoostArchive.cpp + ./src/QxSerialize/Qt/QxSerialize_QBrush.cpp + ./src/QxSerialize/Qt/QxSerialize_QByteArray.cpp + ./src/QxSerialize/Qt/QxSerialize_QColor.cpp + ./src/QxSerialize/Qt/QxSerialize_QDate.cpp + ./src/QxSerialize/Qt/QxSerialize_QDateTime.cpp + ./src/QxSerialize/Qt/QxSerialize_QFont.cpp + ./src/QxSerialize/Qt/QxSerialize_QImage.cpp + ./src/QxSerialize/Qt/QxSerialize_QMatrix.cpp + ./src/QxSerialize/Qt/QxSerialize_QObject.cpp + ./src/QxSerialize/Qt/QxSerialize_QPicture.cpp + ./src/QxSerialize/Qt/QxSerialize_QPixmap.cpp + ./src/QxSerialize/Qt/QxSerialize_QPoint.cpp + ./src/QxSerialize/Qt/QxSerialize_QRect.cpp + ./src/QxSerialize/Qt/QxSerialize_QRegExp.cpp + ./src/QxSerialize/Qt/QxSerialize_QRegion.cpp + ./src/QxSerialize/Qt/QxSerialize_QSize.cpp + ./src/QxSerialize/Qt/QxSerialize_QString.cpp + ./src/QxSerialize/Qt/QxSerialize_QStringList.cpp + ./src/QxSerialize/Qt/QxSerialize_QTime.cpp + ./src/QxSerialize/Qt/QxSerialize_QUrl.cpp + ./src/QxSerialize/Qt/QxSerialize_QUuid.cpp + ./src/QxSerialize/Qt/QxSerialize_QVariant.cpp + ./src/QxSerialize/Qt/QxSerialize_QSqlError.cpp + ./src/QxRestApi/QxRestApi.cpp + ./src/QxService/IxParameter.cpp + ./src/QxService/IxService.cpp + ./src/QxService/QxConnect.cpp + ./src/QxService/QxServer.cpp + ./src/QxService/QxThread.cpp + ./src/QxService/QxThreadPool.cpp + ./src/QxService/QxTools.cpp + ./src/QxService/QxTransaction.cpp + ./src/QxHttpServer/QxHttpRequest.cpp + ./src/QxHttpServer/QxHttpResponse.cpp + ./src/QxHttpServer/QxHttpServer.cpp + ./src/QxHttpServer/QxHttpTransaction.cpp + ./src/QxHttpServer/QxHttpCookie.cpp + ./src/QxHttpServer/QxHttpSession.cpp + ./src/QxHttpServer/QxHttpSessionManager.cpp + ./src/QxValidator/IxValidator.cpp + ./src/QxValidator/IxValidatorX.cpp + ./src/QxValidator/QxInvalidValue.cpp + ./src/QxValidator/QxInvalidValueX.cpp + ./src/QxModelView/IxModel.cpp + ./src/QxModelView/QxNestedModel.cpp + ./src/QxModelView/QxModelRowCompare.cpp + ./src/main.cpp + ) + +endif() # _QX_UNITY_BUILD + +set(QX_INLS + ./inl/QxCollection/QxCollection.inl + ./inl/QxCollection/QxCollectionIterator.inl + ./inl/QxConvert/QxConvert_FromString.inl + ./inl/QxConvert/QxConvert_FromVariant.inl + ./inl/QxConvert/QxConvert_FromJson.inl + ./inl/QxConvert/QxConvert_Qt.inl + ./inl/QxConvert/QxConvert_ToString.inl + ./inl/QxConvert/QxConvert_ToVariant.inl + ./inl/QxConvert/QxConvert_ToJson.inl + ./inl/QxConvert/QxConvert_WithIndex.inl + ./inl/QxDao/QxDao_Count.inl + ./inl/QxDao/QxDao_CreateTable.inl + ./inl/QxDao/QxDao_DeleteAll.inl + ./inl/QxDao/QxDao_DeleteById.inl + ./inl/QxDao/QxDao_ExecuteQuery.inl + ./inl/QxDao/QxDao_Exist.inl + ./inl/QxDao/QxDao_FetchAll.inl + ./inl/QxDao/QxDao_FetchAll_WithRelation.inl + ./inl/QxDao/QxDao_FetchById.inl + ./inl/QxDao/QxDao_FetchById_WithRelation.inl + ./inl/QxDao/QxDao_Helper.inl + ./inl/QxDao/QxDao_Helper_Container.inl + ./inl/QxDao/QxDao_Insert.inl + ./inl/QxDao/QxDao_Insert_WithRelation.inl + ./inl/QxDao/QxDao_Save.inl + ./inl/QxDao/QxDao_Save_WithRelation.inl + ./inl/QxDao/QxDao_Save_WithRelation_Recursive.inl + ./inl/QxDao/QxDao_Trigger.inl + ./inl/QxDao/QxDao_Update.inl + ./inl/QxDao/QxDao_Update_Optimized.inl + ./inl/QxDao/QxDao_Update_WithRelation.inl + ./inl/QxDao/QxSqlQueryHelper_CreateTable.inl + ./inl/QxDao/QxSqlQueryHelper_DeleteById.inl + ./inl/QxDao/QxSqlQueryHelper_Exist.inl + ./inl/QxDao/QxSqlQueryHelper_FetchAll.inl + ./inl/QxDao/QxSqlQueryHelper_FetchAll_WithRelation.inl + ./inl/QxDao/QxSqlQueryHelper_FetchById.inl + ./inl/QxDao/QxSqlQueryHelper_FetchById_WithRelation.inl + ./inl/QxDao/QxSqlQueryHelper_Insert.inl + ./inl/QxDao/QxSqlQueryHelper_Update.inl + ./inl/QxDataMember/QxDataMember.inl + ./inl/QxDataMember/QxDataMemberX.inl + ./inl/QxFactory/QxFactory.inl + ./inl/QxRegister/QxClass.inl + ./inl/QxSerialize/QxArchive.inl + ./inl/QxSerialize/QxSerializeInvoker.inl + ./inl/QxSingleton/QxSingleton.inl +) + +if(_QX_STATIC_BUILD) + add_library(XdlOrm STATIC ${QX_SRCS} ${QX_HEADERS} ${QX_INLS}) +else() + add_library(XdlOrm SHARED ${QX_SRCS} ${QX_HEADERS} ${QX_INLS}) +endif() + +target_compile_definitions(XdlOrm PRIVATE -D_QX_BUILDING_QX_ORM) + +target_include_directories(XdlOrm + PUBLIC + $ + $ + $ + $ +) + +if(NOT TARGET xdlorm::xdlorm) + add_library(xdlorm::xdlorm ALIAS XdlOrm) +endif() + +if(COMMAND target_precompile_headers) + target_precompile_headers(XdlOrm PRIVATE ./include/QxPrecompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(XdlOrm ${QX_LIBRARIES}) + +# set_target_properties(XdlOrm PROPERTIES +# ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/build/UI/Main +# RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/build/UI/Main +# LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/lib" +# ) + +# To sort all files by folder in MSVC and XCode solution +qx_auto_source_group("${QX_SRCS};${QX_HEADERS};${QX_INLS}") + +# Define CMAKE_INSTALL_PREFIX variable to put the location where to copy all files +install(TARGETS XdlOrm DESTINATION lib) +install(DIRECTORY ./include/ DESTINATION include) +install(DIRECTORY ./inl/ DESTINATION inl) diff --git a/README.md b/README.md new file mode 100644 index 0000000..647449f --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# QxOrm 库 - 官方仓库 +[QxOrm 库](https://www.qxorm.com/) 是一个为 C++ Qt 开发者提供的**对象关系映射 (ORM)** 和**对象文档映射 (ODM)** 数据库库。主要功能包括: +- [持久化](https://www.qxorm.com/qxorm_en/manual.html#manual_30):支持最常见的数据库,如 SQLite、MySQL、PostgreSQL、Oracle、MS SQL Server、[MongoDB](https://www.qxorm.com/qxorm_en/manual.html#manual_95)(支持 1-1、1-n、n-1 和 n-n 关系); +- [序列化](https://www.qxorm.com/qxorm_en/manual.html#manual_60):JSON、二进制和 XML 格式; +- [反射](https://www.qxorm.com/qxorm_en/manual.html#manual_70)(或[内省](https://www.qxorm.com/qxorm_en/manual.html#manual_70)):动态访问类定义,检索属性并调用类方法; +- [HTTP Web 服务器](https://www.qxorm.com/qxorm_en/manual.html#manual_96):独立的多线程 HTTP 1.1 Web 服务器(支持 SSL/TLS、持久连接、Cookie、会话、分块响应、URL 调度/路由); +- [JSON API](https://www.qxorm.com/qxorm_en/manual.html#manual_97):与 C++/Qt 以外的其他技术(REST Web 服务、QML 应用程序、脚本语言)的互操作性。 + +## 文档 +QxOrm 网站提供了[用户手册](https://www.qxorm.com/qxorm_en/manual.html)。 + +本文档的目标是提供一个用户指南,学习如何使用 QxOrm 库的功能。本手册面向正在寻找解决方案来管理 C++/Qt 中持久数据层的开发人员和软件架构师。理解本文档需要 C++ 和数据库方面的技术技能。 + +**注意:** 本手册/用户指南中描述的所有功能都可以通过 **QxEntityEditor 应用程序**(QxOrm 库的图形编辑器、数据模型设计器和源代码生成器)快速轻松地定义。QxOrm 网站上提供了[专门针对 QxEntityEditor 应用程序的文档](https://www.qxorm.com/qxorm_en/manual_qxee.html)。 + +## QxEntityEditor 应用程序 +[QxEntityEditor](https://www.qxorm.com/qxorm_en/manual_qxee.html) 是 QxOrm 库的图形编辑器:**QxEntityEditor 提供了一种图形化方式来管理数据模型**。 +QxEntityEditor 是多平台的(适用于 Windows、Linux 和 Mac OS X),并为所有环境生成原生代码:桌面(Windows、Linux、Mac OS X)、嵌入式和移动设备(Android、iOS、Windows Phone、Raspberry Pi 等)。 +QxOrm 网站上提供了[QxEntityEditor 应用程序的用户手册(文档)](https://www.qxorm.com/qxorm_en/manual_qxee.html)。 + +QxEntityEditor 基于插件,提供了多种导入/导出数据模型的方法: +- [自动生成 C++ 持久类](https://www.qxorm.com/qxorm_en/manual_qxee.html#cpp_export_settings)(在 QxOrm 上下文中注册); +- [自动生成 DDL SQL 脚本](https://www.qxorm.com/qxorm_en/manual_qxee.html#ddl_export_settings)(数据库架构),适用于 SQLite、MySQL、PostgreSQL、Oracle 和 MS SQL Server; +- 管理每个项目版本的架构演变(ALTER TABLE、ADD COLUMN、DROP INDEX 等); +- 通过网络传输数据模型并[快速创建客户端/服务器应用程序](https://www.qxorm.com/qxorm_en/manual_qxee.html#cpp_services_export_settings),使用 [QxService 模块](https://www.qxorm.com/doxygen/html/group___qx_service.html); +- [导入现有数据库结构](https://www.qxorm.com/qxorm_en/manual_qxee.html#wnd_mysql_import)(使用 ODBC 连接或原生驱动程序),适用于 SQLite、MySQL、PostgreSQL、Oracle 和 MS SQL Server 数据库; +- 因为每个项目都不同,QxEntityEditor 提供了多种方法来自定义生成的文件(尤其是 [JavaScript 引擎和集成调试器](https://www.qxorm.com/qxorm_en/manual_qxee.html#js_engine))。 + +![QxEntityEditor 应用程序](https://www.qxorm.com/qxentityeditor/resource/qxee_sample_small.png) + +## 依赖项 +默认情况下,QxOrm 库仅依赖于 [Qt 框架](https://www.qt.io/) 中的 [QtCore](https://doc.qt.io/qt-5/qtcore-index.html) 和 [QtSql](https://doc.qt.io/qt-5/qtsql-index.html) 库。 +如果启用 [QxOrm HTTP Web 服务器](https://www.qxorm.com/qxorm_en/manual.html#manual_96) 功能,那么 QxOrm 库还将依赖于 [QtNetwork](https://doc.qt.io/qt-5/qtnetwork-index.html) 库。 +某些功能需要 [boost](https://www.boost.org/) 依赖项(默认禁用)。 + +## 作者 +QxOrm 由 XDL 团队开发,该团队自 2003 年以来一直是软件开发工程师。 + +## 许可证 +QxOrm 是一个 C++ 库,可在双重许可证下使用: +- [GNU/GPLv3 许可证](https://www.qxorm.com/qxorm_en/resource/license.gpl3.txt):开源且免费(用于开发开源项目或评估 QxOrm 库); +- [专有许可证](https://www.qxorm.com/qxorm_en/download_details.php),用于分发基于 QxOrm 库的应用程序,不受 GNU/GPLv3 许可证的任何限制。 + +## Conan 打包方法 +### 安装 Conan +首先,确保您已安装 Conan 包管理器。如果尚未安装,可以从 [Conan 官方网站](https://conan.io/downloads.html) 下载并安装。 + +### 构建和安装包 +1. 克隆仓库并进入项目目录: + ```bash + git clone <仓库地址> + cd XdlOrm + ``` + +2. 构建并安装包到本地 Conan 缓存: + ```bash + conan create . --profile:build default --profile:host default + ``` + +3. 或者,直接在项目目录中构建: + ```bash + conan build . --profile:build default --profile:host default + ``` + +### 在项目中使用 +在您的项目的 `conanfile.py` 中添加依赖: +```python +requires = [ + "xdlorm/1.0.0" +] +``` + +或者,使用 `conan install` 命令安装: +```bash +conan install . --build=missing +``` + +### 配置选项 +QxOrm 库提供了以下 Conan 选项: +- `shared`:是否构建为共享库(默认:False) +- `enable_boost`:是否启用 Boost 支持(默认:False) +- `enable_boost_serialization`:是否启用 Boost 序列化(默认:False) +- `enable_qt_gui`:是否启用 Qt GUI 支持(默认:False) +- `enable_qt_network`:是否启用 Qt Network 支持(默认:False) +- `enable_mongodb`:是否启用 MongoDB 支持(默认:False) +- `no_json`:是否禁用 JSON 序列化(默认:False) +- `unity_build`:是否启用 Unity 构建(默认:False) + +例如,构建共享库并启用 Boost 支持: +```bash +conan create . --profile:build default --profile:host default -o xdlorm:shared=True -o xdlorm:enable_boost=True +``` \ No newline at end of file diff --git a/XdlOrm.cmake b/XdlOrm.cmake new file mode 100644 index 0000000..5e05625 --- /dev/null +++ b/XdlOrm.cmake @@ -0,0 +1,384 @@ +############################################################################# +## +## 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 +## +############################################################################# + +# QxOrm.cmake is the configuration file for QxOrm library if you are using CMake as build tool +# QxOrm.cmake file is equivalent to QxOrm.pri configuration file for qmake projects +# QxOrm.cmake file should be included by all projects which depend on QxOrm library +# QxOrm.cmake file contains some settings to enable/disable QxOrm library features +# QxOrm.cmake file also tries to find Qt and boost libraries required by QxOrm library + +if(NOT QXORM_CMAKE_CONFIG_FILE_INCLUDED) + set(QXORM_CMAKE_CONFIG_FILE_INCLUDED TRUE) + + ########################################### + # QxOrm library options / features # + ########################################### + + option(_QX_ENABLE_BOOST "If you enable _QX_ENABLE_BOOST option, then QxOrm library will support some boost header-only classes like boost::optional, boost::shared_ptr, boost::unordered_map, etc..." OFF) + option(_QX_ENABLE_QT_GUI "If you enable _QX_ENABLE_QT_GUI option, then QxOrm library will be able to serialize Qt Gui objects (QBrush, QColor, QFont, QImage, QMatrix, QPicture, QPixmap, QRegion)" OFF) + option(_QX_ENABLE_QT_NETWORK "If you enable _QX_ENABLE_QT_NETWORK option, then QxService and QxHttpServer modules of QxOrm library will be available (network transactions to transfer persistent data layer + standalone multi-threaded HTTP 1.1 web server)" OFF) + option(_QX_ENABLE_MONGODB "If you enable _QX_ENABLE_MONGODB option, then QxOrm library will be able to use mongoc driver to store all QxOrm registered classes in a MongoDB database" OFF) + option(_QX_STATIC_BUILD "Enable _QX_STATIC_BUILD option to build QxOrm as a static library" OFF) + option(_QX_NO_JSON "If you enable _QX_NO_JSON option, then QxOrm library will not provide JSON serialization engine" OFF) + option(_QX_UNITY_BUILD "If you enable _QX_UNITY_BUILD option, then QxOrm library will be built faster (using only 1 'all.cpp' source file)" OFF) + option(_QX_USE_QSTRINGBUILDER "If you enable _QX_USE_QSTRINGBUILDER option, then QxOrm library will define QT_USE_QSTRINGBUILDER compilation option of Qt library to provide some optimizations with QString class" OFF) + + ########################################### + # QxOrm library requires a C++11 compiler # + ########################################### + + # Qt framework requires a C++11 compiler since version Qt 5.7 + # So for all previous Qt versions, we need to define CONFIG += c++11 + # Please note that QxOrm library doesn't require a full compliant C++11 compiler : for example, QxOrm library can be built and used with MSVC 2012, GCC 4.5 or Clang 3.2 + + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + + ###################### + # QxOrm Library Path # + ###################### + + set(QXORM_DIR ${CMAKE_CURRENT_LIST_DIR}) + set(QXORM_INCLUDE_DIR ${QXORM_DIR}/include) + include_directories(${QXORM_INCLUDE_DIR}) + + ########################################### + # Boost Header-Only Dependency (optional) # + ########################################### + + # Since QxOrm 1.4.4, QxOrm library doesn't depend on boost framework anymore (the boost dependency has been fully removed, replaced by some C++11 features) + # So QxOrm library is now a pure Qt library which depends only on QtCore and QtSql by default + # QxOrm library still supports some boost classes (boost smart-pointers, unordered containers, boost::optional, etc...) : you have to define _QX_ENABLE_BOOST compilation option to enable these features + + ###################################### + # Boost Library Configuration / Path # + ###################################### + + if(_QX_ENABLE_BOOST) + + add_definitions(-D_QX_ENABLE_BOOST) + set(QX_BOOST_DIR "" CACHE STRING "Define where boost library is located, or leave QX_BOOST_DIR parameter empty and define a BOOST_ROOT environment variable") + + if(NOT QX_BOOST_DIR STREQUAL "") + set(BOOST_ROOT ${QX_BOOST_DIR}) + endif() + + find_package(Boost 1.38.0 REQUIRED) + + if(NOT Boost_FOUND) + message(FATAL_ERROR "boost library not found : please define where boost library is located using QX_BOOST_DIR parameter, or leave QX_BOOST_DIR parameter empty and define a BOOST_ROOT environment variable") + endif() + + include_directories(${Boost_INCLUDE_DIRS}) + + endif() # _QX_ENABLE_BOOST + + ########################### + # Qt Library Dependencies # + ########################### + + # Use Qt from Conan or system + set(QX_QT_DIR "" CACHE STRING "Define where Qt library is located if CMake doesn't find it by default") + + if(NOT QX_QT_DIR STREQUAL "") + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${QX_QT_DIR}) + endif() + + # Find Qt (either Qt6 or Qt5) + find_package(Qt6 QUIET COMPONENTS Core) + if(NOT Qt6_FOUND) + find_package(Qt5 COMPONENTS Core REQUIRED) + set(QT_VERSION_MAJOR 5) + else() + set(QT_VERSION_MAJOR 6) + endif() + + if(_QX_ENABLE_QT_GUI AND _QX_ENABLE_QT_NETWORK) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Network REQUIRED) + set(QX_LIBRARIES Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Sql Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network) + elseif(_QX_ENABLE_QT_GUI) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui REQUIRED) + set(QX_LIBRARIES Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Sql Qt${QT_VERSION_MAJOR}::Gui) + elseif(_QX_ENABLE_QT_NETWORK) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Network REQUIRED) + set(QX_LIBRARIES Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Sql Qt${QT_VERSION_MAJOR}::Network) + else() # (_QX_ENABLE_QT_GUI AND _QX_ENABLE_QT_NETWORK) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql REQUIRED) + set(QX_LIBRARIES Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Sql) + endif() # (_QX_ENABLE_QT_GUI AND _QX_ENABLE_QT_NETWORK) + + if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + endif() # (${QT_VERSION_MAJOR} GREATER_EQUAL 6) + + ####################################### + # MongoDB Driver Library Dependencies # + ####################################### + + if(_QX_ENABLE_MONGODB) + + add_definitions(-D_QX_ENABLE_MONGODB) + + set(QX_MONGOC_INCLUDE "$ENV{MONGOC_INCLUDE}") + if(NOT QX_MONGOC_INCLUDE STREQUAL "") + + include_directories("$ENV{BSON_INCLUDE}") + include_directories("${QX_MONGOC_INCLUDE}") + + link_directories("$ENV{BSON_LIB}") + link_directories("$ENV{MONGOC_LIB}") + + set(QX_LIBRARIES ${QX_LIBRARIES} bson-1.0 mongoc-1.0) + + else() # (NOT QX_MONGOC_INCLUDE STREQUAL "") + + find_package(libbson-1.0 REQUIRED) + find_package(libmongoc-1.0 REQUIRED) + + include_directories(${BSON_INCLUDE_DIRS}) + include_directories(${MONGOC_INCLUDE_DIRS}) + + set(QX_LIBRARIES ${QX_LIBRARIES} ${BSON_LIBRARIES} ${MONGOC_LIBRARIES}) + + endif() # (NOT QX_MONGOC_INCLUDE STREQUAL "") + + endif() # _QX_ENABLE_MONGODB + + ############################## + # Build Mode Debug / Release # + ############################## + + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS + $<$:_QX_MODE_DEBUG> + $<$:_QX_MODE_RELEASE> + $<$:_QX_MODE_RELEASE> + $<$:_QX_MODE_RELEASE> + $<$:_QX_MODE_RELEASE> + $<$:_QX_MODE_RELEASE> + ) + + ######################### + # No Precompiled Header # + ######################### + + # By default, CMake doesn't support precompiled headers natively, so _QX_NO_PRECOMPILED_HEADER compilation option is defined with CMake + # There is a project named 'cotire' (compile time reducer) which is not deployed with CMake but can be used to support precompiled headers, more details here : https://github.com/sakra/cotire + # Moreover, some versions of MinGW on Windows have a bug with large precompiled headers (for example, MinGW GCC 4.8) + # More detais about this problem here : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56926 + # And here : http://stackoverflow.com/questions/10841306/cc1plus-exe-crash-when-using-large-precompiled-header-file + # To fix the crash during compilation, you have to disable precompiled headers : just enable the following compilation option _QX_NO_PRECOMPILED_HEADER + # Note : there is a side effect disabling precompiled headers => compilation times are considerably increased ! + # Other note : to reduce compilation times, it is recommended to define _QX_UNITY_BUILD compilation option + + if(NOT COMMAND target_precompile_headers) + add_definitions(-D_QX_NO_PRECOMPILED_HEADER) + endif() # (NOT COMMAND target_precompile_headers) + + ############################## + # QxOrm Library Static Build # + ############################## + + # To create only 1 EXE including Qt, boost serialization (optional) and QxOrm libraries without any dependency : + + if(_QX_STATIC_BUILD) + add_definitions(-D_QX_STATIC_BUILD) + endif() + + ############################################################ + # Boost Serialization Shared Library Dependency (optional) # + ############################################################ + + # By default, QxOrm library doesn't depend on boost::serialization shared library, but it is possible to enable it defining the compilation option : _QX_ENABLE_BOOST_SERIALIZATION + # Without this compilation option, QxOrm is a much lighter library, generated binaries based on QxOrm are smaller, and QxOrm depends only on Qt binaries (and boost header files) + # But in this case, serialization features are limited (based on QDataStream and QJson engines) : limited qx::clone, no XML serialization, limited binary serialization, limited QxService module (network transactions), etc... + # If you define _QX_ENABLE_BOOST_SERIALIZATION compilation option, then boost serialization is enabled with XML and binary engine by default (see _QX_ENABLE_BOOST_SERIALIZATION_BINARY and _QX_ENABLE_BOOST_SERIALIZATION_XML for more details) + # Note : if you are not using serialization functions in projects based on QxOrm library, then you can define or not _QX_ENABLE_BOOST_SERIALIZATION compilation option without changing any line of your source code + # Other note : to persist containers in database (not relationships, for example : std::vector), without _QX_ENABLE_BOOST_SERIALIZATION it is stored as QByteArray (based on QDataStream engine), with _QX_ENABLE_BOOST_SERIALIZATION it is stored as XML (based on boost serialization XML engine) => so be careful, in this case it is not compatible + + if(_QX_ENABLE_BOOST) + + option(_QX_ENABLE_BOOST_SERIALIZATION "If you enable _QX_ENABLE_BOOST_SERIALIZATION option, then QxOrm library will provide a serialization engine based on boost::serialization (you have to build boost::serialization shared libray to use this feature)" OFF) + + if(_QX_ENABLE_BOOST_SERIALIZATION) + + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION) + + option(_QX_ENABLE_BOOST_SERIALIZATION_BINARY "Enable boost::serialization binary engine" ON) + option(_QX_ENABLE_BOOST_SERIALIZATION_XML "Enable boost::serialization XML engine" ON) + option(_QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC "Enable boost::serialization polymorphic engine" OFF) + option(_QX_ENABLE_BOOST_SERIALIZATION_TEXT "Enable boost::serialization text engine" OFF) + option(_QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY "Enable boost::serialization portable binary engine" OFF) + option(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY "Enable boost::serialization wide binary engine" OFF) + option(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT "Enable boost::serialization wide text engine" OFF) + option(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML "Enable boost::serialization wide XML engine" OFF) + + if(_QX_ENABLE_BOOST_SERIALIZATION_BINARY) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_BINARY) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_XML) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_XML) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_TEXT) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_TEXT) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT) + endif() + + if(_QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML) + add_definitions(-D_QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML) + endif() + + find_package(Boost 1.38.0 REQUIRED COMPONENTS serialization) + + if(NOT Boost_SERIALIZATION_FOUND) + message(FATAL_ERROR "boost::serialization library not found (with _QX_ENABLE_BOOST_SERIALIZATION option enabled, QxOrm library depends on boost::serialization binary)") + endif() + + set(QX_LIBRARIES ${QX_LIBRARIES} ${Boost_SERIALIZATION_LIBRARY}) + + endif() # _QX_ENABLE_BOOST_SERIALIZATION + endif() # _QX_ENABLE_BOOST + + ############################ + # Qt Gui Module Dependency # + ############################ + + # By default, QxOrm library doesn't depend on Qt Gui shared library + # If you want to serialize Qt Gui objects (QBrush, QColor, QFont, QImage, QMatrix, QPicture, QPixmap, QRegion), then you have to define _QX_ENABLE_QT_GUI compilation option + + if(_QX_ENABLE_QT_GUI) + add_definitions(-D_QX_ENABLE_QT_GUI) + endif() # _QX_ENABLE_QT_GUI + + ################################ + # Qt Network Module Dependency # + ################################ + + # By default, QxOrm library doesn't depend on Qt Network shared library => it means that QxService module (network transactions to transfer your persistent layer) and QxHttpServer module (standalone multi-threaded HTTP 1.1 web server) are not enabled by default + # To enable these features (QxService and QxHttpServer modules), just define the compilation option : _QX_ENABLE_QT_NETWORK + # For more details about QxService module, a tutorial (qxClientServer) is available on QxOrm website : https://www.qxorm.com/qxorm_en/tutorial_2.html + # For more details about QxHttpServer module, a manual is available on QxOrm website : https://www.qxorm.com/qxorm_en/manual.html#manual_96 + + if(_QX_ENABLE_QT_NETWORK) + add_definitions(-D_QX_ENABLE_QT_NETWORK) + endif() # _QX_ENABLE_QT_NETWORK + + ################################ + # No JSON Serialization Engine # + ################################ + + # QxOrm library supports JSON serialization : this feature is enabled by default if you are not working with Qt4 (JSON engine requires Qt5) + # To disable this feature, you can define the compilation option : _QX_NO_JSON + # Using _QX_NO_JSON compilation option, qx::serialization::json namespace will be not available + + if(_QX_NO_JSON) + add_definitions(-D_QX_NO_JSON) + endif() + + ########################################## + # Unity Build : Reduce Compilation Times # + ########################################## + + # QxOrm provides a way to compile the library faster using the Unity Build system : http://stackoverflow.com/questions/543697/include-all-cpp-files-into-a-single-compilation-unit + # To enable QxOrm Unity Build feature, just define the _QX_UNITY_BUILD compilation option + # This compilation option changes the make file : instead of compiling each *.cpp files separately, QxOrm is compiled using a unique 'all.cpp' file (which #include all QxOrm *.cpp files) + # Note : your environment must have enough memory to support this compilation option, and your compiler must support it too, otherwise your compiler can crash with a memory error + # Other note : C++ projects generated by QxEntityEditor application support this compilation option => this is a way to reduce compilation times of C++ persistent classes generated by QxEntityEditor + # Other note : if you define _QX_UNITY_BUILD compilation option, it can be interesting too to define the _QX_NO_PRECOMPILED_HEADER compilation option to reduce compilation times (it depends on number of other *.cpp files to compile, like moc files for example) + + if(_QX_UNITY_BUILD) + add_definitions(-D_QX_UNITY_BUILD) + if(WIN32 AND MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -bigobj") + elseif(WIN32 AND MINGW) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj") + endif() # WIN32 AND MSVC + endif() # _QX_UNITY_BUILD + + ########################################## + # More Efficient Qt QString Construction # + ########################################## + + # Qt provides some optimizations for QString class (construction, concatenation, etc...) + # More details about these optimizations are available on Qt web site : http://doc.qt.io/qt-5/qstring.html#more-efficient-string-construction + # To enable these optimizations, you can define QT_USE_QSTRINGBUILDER compilation option + + if(_QX_USE_QSTRINGBUILDER) + add_definitions(-DQT_USE_QSTRINGBUILDER) + endif() + + ############################# + # Compiler / Linker Options # + ############################# + + if(WIN32) + if(MSVC) + if(MSVC_VERSION LESS 1700) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:NOREF") + endif() # MSVC_VERSION LESS 1700 + elseif(MINGW) + # For MinGW : we need to add these linker flags because of some issues to dll export extern template instantiations from shared library + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-export-all-symbols -Wl,-enable-auto-import") + endif() # MSVC + endif() # WIN32 + + #################################################### + # Macro To Source Group By Folder For MSVC / XCode # + #################################################### + + macro(qx_auto_source_group QX_ALL_FILES) + foreach(QX_FILE ${QX_ALL_FILES}) + get_filename_component(QX_PARENT_DIR "${QX_FILE}" DIRECTORY) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" QX_GROUP "${QX_PARENT_DIR}") + string(REPLACE "./" "" QX_GROUP "${QX_GROUP}") + string(REPLACE "/" "\\" QX_GROUP "${QX_GROUP}") + source_group("${QX_GROUP}" FILES "${QX_FILE}") + endforeach() + endmacro() # qx_auto_source_group + +endif() # QXORM_CMAKE_CONFIG_FILE_INCLUDED diff --git a/doc/doxygen/html/.gitignore b/doc/doxygen/html/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/doc/doxygen/html/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/doc/doxygen/index.html b/doc/doxygen/index.html new file mode 100644 index 0000000..e493cf1 --- /dev/null +++ b/doc/doxygen/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/doc/doxygen/qxorm.doxygen b/doc/doxygen/qxorm.doxygen new file mode 100644 index 0000000..ff5f0cf --- /dev/null +++ b/doc/doxygen/qxorm.doxygen @@ -0,0 +1,1761 @@ +# Doxyfile 1.7.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = QxOrm + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.5.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "C++ Object Relational Mapping library" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = ../qxorm_en/resource/logo_qxorm.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../../include + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = _QX_ENABLE_QT_GUI:= \ + _QX_ENABLE_QT_NETWORK:= \ + _QX_ENABLE_BOOST:= \ + _QX_ENABLE_BOOST_SERIALIZATION:= \ + _QX_SERIALIZE_POLYMORPHIC:=1 \ + _QX_SERIALIZE_BINARY:=1 \ + _QX_SERIALIZE_TEXT:=1 \ + _QX_SERIALIZE_XML:=1 \ + _QX_SERIALIZE_PORTABLE_BINARY:=1 \ + _QX_SERIALIZE_WIDE_BINARY:=1 \ + _QX_SERIALIZE_WIDE_TEXT:=1 \ + _QX_SERIALIZE_WIDE_XML:=1 \ + _QX_USE_MEM_LEAK_DETECTION:=1 + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..362f370 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,18 @@ + + + +QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor (data model designer and source code generator) + + + + + diff --git a/doc/php/add_download.php b/doc/php/add_download.php new file mode 100644 index 0000000..de44941 --- /dev/null +++ b/doc/php/add_download.php @@ -0,0 +1,31 @@ + + + +alert('" . $errors . "');"; } + if ($nb_errors == 0) + { + $_POST['created_by'] = nl2br(htmlentities(stripslashes($_POST['created_by']))); + $_POST['message_text'] = nl2br(htmlentities(stripslashes($_POST['message_text']))); + $createdby = "

**** Downloaded by " . $_POST['created_by'] . " (" . date(d."/".m."/"."Y") . " " . date(H.":".i) . ")

"; + $msg = "

" . $_POST['message_text'] . "

"; + $filename = "./version_1.5.0.php"; + while ((file_exists($filename)) && (! is_writable($filename)) && ($try_count < 200)) { usleep(100000); $try_count++; } + $fp = fopen($filename, "a"); + fputs($fp, "\n"); + fputs($fp, $createdby); + fputs($fp, "\n"); + fputs($fp, $msg); + fclose($fp); + } + echo ""; +?> + + + + diff --git a/doc/php/add_download.php5 b/doc/php/add_download.php5 new file mode 100644 index 0000000..952793f --- /dev/null +++ b/doc/php/add_download.php5 @@ -0,0 +1,39 @@ + + + **** " . date(d."/".m."/"."Y") . " " . date(H.":".i) . " ****"; + while ((file_exists($file_log)) && (! is_writable($file_log)) && ($try_count < 200)) + { usleep(100000); $try_count++; } + $fp = fopen($file_log, "a"); + fputs($fp, "\n"); + fputs($fp, $text_log); + fclose($fp); + } + catch (Exception $exc) { echo '

' . $exc->getMessage() . '

'; } + + echo '

If your download does not start automatically within 5 seconds, please click here to manually download the file.

'; + echo '
'; + echo '

QxOrm and QxEntityEditor home page

'; + + echo ''; + } + else if ($is_valid) + { + echo '

File to download ' . $file_to_download . ' does not exist !

'; + echo '
'; + echo '

QxOrm and QxEntityEditor home page

'; + } + ?> + + diff --git a/doc/qxentityeditor/resource/qxee_all_views.jpg b/doc/qxentityeditor/resource/qxee_all_views.jpg new file mode 100644 index 0000000..6671596 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_all_views.jpg differ diff --git a/doc/qxentityeditor/resource/qxee_cpp_preview.png b/doc/qxentityeditor/resource/qxee_cpp_preview.png new file mode 100644 index 0000000..9bce3ae Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_cpp_preview.png differ diff --git a/doc/qxentityeditor/resource/qxee_database.png b/doc/qxentityeditor/resource/qxee_database.png new file mode 100644 index 0000000..4fddce2 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_database.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_clone.png b/doc/qxentityeditor/resource/qxee_entity_clone.png new file mode 100644 index 0000000..101fcc5 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_clone.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_colors.png b/doc/qxentityeditor/resource/qxee_entity_colors.png new file mode 100644 index 0000000..a50e0b8 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_colors.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_delete.png b/doc/qxentityeditor/resource/qxee_entity_delete.png new file mode 100644 index 0000000..4e21556 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_delete.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_modify.png b/doc/qxentityeditor/resource/qxee_entity_modify.png new file mode 100644 index 0000000..9421e33 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_modify.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_new.png b/doc/qxentityeditor/resource/qxee_entity_new.png new file mode 100644 index 0000000..cfc179e Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_new.png differ diff --git a/doc/qxentityeditor/resource/qxee_entity_settings.png b/doc/qxentityeditor/resource/qxee_entity_settings.png new file mode 100644 index 0000000..91f1465 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_entity_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_enum_colors.png b/doc/qxentityeditor/resource/qxee_enum_colors.png new file mode 100644 index 0000000..bc58ad2 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_enum_colors.png differ diff --git a/doc/qxentityeditor/resource/qxee_enum_settings.png b/doc/qxentityeditor/resource/qxee_enum_settings.png new file mode 100644 index 0000000..99156a2 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_enum_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp.png b/doc/qxentityeditor/resource/qxee_export_cpp.png new file mode 100644 index 0000000..96c56cf Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_model_view.png b/doc/qxentityeditor/resource/qxee_export_cpp_model_view.png new file mode 100644 index 0000000..9b8c3a7 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_model_view.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_model_view_output.png b/doc/qxentityeditor/resource/qxee_export_cpp_model_view_output.png new file mode 100644 index 0000000..86e21e2 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_model_view_output.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_output.png b/doc/qxentityeditor/resource/qxee_export_cpp_output.png new file mode 100644 index 0000000..a84e73c Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_output.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_services.png b/doc/qxentityeditor/resource/qxee_export_cpp_services.png new file mode 100644 index 0000000..6898e79 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_services.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_services_output.png b/doc/qxentityeditor/resource/qxee_export_cpp_services_output.png new file mode 100644 index 0000000..8274979 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_services_output.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app.png b/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app.png new file mode 100644 index 0000000..5d620d4 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app_output.png b/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app_output.png new file mode 100644 index 0000000..b309c8c Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_cpp_services_server_app_output.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_ddl.png b/doc/qxentityeditor/resource/qxee_export_ddl.png new file mode 100644 index 0000000..c9bcbba Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_ddl.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_plugins.png b/doc/qxentityeditor/resource/qxee_export_plugins.png new file mode 100644 index 0000000..359f4c6 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_plugins.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_print.png b/doc/qxentityeditor/resource/qxee_export_print.png new file mode 100644 index 0000000..6bc4fea Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_print.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_source_control_settings.png b/doc/qxentityeditor/resource/qxee_export_source_control_settings.png new file mode 100644 index 0000000..11f218d Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_source_control_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_export_xml_json.png b/doc/qxentityeditor/resource/qxee_export_xml_json.png new file mode 100644 index 0000000..ab5e427 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_export_xml_json.png differ diff --git a/doc/qxentityeditor/resource/qxee_global_settings.png b/doc/qxentityeditor/resource/qxee_global_settings.png new file mode 100644 index 0000000..ee0b785 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_global_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_json.png b/doc/qxentityeditor/resource/qxee_import_json.png new file mode 100644 index 0000000..6956669 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_json.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_mysql.png b/doc/qxentityeditor/resource/qxee_import_mysql.png new file mode 100644 index 0000000..a21acba Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_mysql.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_odbc.png b/doc/qxentityeditor/resource/qxee_import_odbc.png new file mode 100644 index 0000000..170d293 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_odbc.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_plugins.png b/doc/qxentityeditor/resource/qxee_import_plugins.png new file mode 100644 index 0000000..0dc6fd4 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_plugins.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_postgresql.png b/doc/qxentityeditor/resource/qxee_import_postgresql.png new file mode 100644 index 0000000..aaf30cf Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_postgresql.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_source_control.png b/doc/qxentityeditor/resource/qxee_import_source_control.png new file mode 100644 index 0000000..5570a42 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_source_control.png differ diff --git a/doc/qxentityeditor/resource/qxee_import_sqlite.png b/doc/qxentityeditor/resource/qxee_import_sqlite.png new file mode 100644 index 0000000..66b5daf Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_import_sqlite.png differ diff --git a/doc/qxentityeditor/resource/qxee_js_debug.png b/doc/qxentityeditor/resource/qxee_js_debug.png new file mode 100644 index 0000000..1c64e5e Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_js_debug.png differ diff --git a/doc/qxentityeditor/resource/qxee_license.png b/doc/qxentityeditor/resource/qxee_license.png new file mode 100644 index 0000000..07dba8b Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_license.png differ diff --git a/doc/qxentityeditor/resource/qxee_linux.png b/doc/qxentityeditor/resource/qxee_linux.png new file mode 100644 index 0000000..20a4191 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_linux.png differ diff --git a/doc/qxentityeditor/resource/qxee_linux_small.png b/doc/qxentityeditor/resource/qxee_linux_small.png new file mode 100644 index 0000000..83812db Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_linux_small.png differ diff --git a/doc/qxentityeditor/resource/qxee_logo.png b/doc/qxentityeditor/resource/qxee_logo.png new file mode 100644 index 0000000..debe477 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_logo.png differ diff --git a/doc/qxentityeditor/resource/qxee_logo_small.png b/doc/qxentityeditor/resource/qxee_logo_small.png new file mode 100644 index 0000000..801d582 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_logo_small.png differ diff --git a/doc/qxentityeditor/resource/qxee_macosx.png b/doc/qxentityeditor/resource/qxee_macosx.png new file mode 100644 index 0000000..8753919 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_macosx.png differ diff --git a/doc/qxentityeditor/resource/qxee_macosx_small.png b/doc/qxentityeditor/resource/qxee_macosx_small.png new file mode 100644 index 0000000..afacb2c Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_macosx_small.png differ diff --git a/doc/qxentityeditor/resource/qxee_namespace_colors.png b/doc/qxentityeditor/resource/qxee_namespace_colors.png new file mode 100644 index 0000000..e93d71b Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_namespace_colors.png differ diff --git a/doc/qxentityeditor/resource/qxee_namespace_menu.png b/doc/qxentityeditor/resource/qxee_namespace_menu.png new file mode 100644 index 0000000..673120b Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_namespace_menu.png differ diff --git a/doc/qxentityeditor/resource/qxee_namespace_rename.png b/doc/qxentityeditor/resource/qxee_namespace_rename.png new file mode 100644 index 0000000..e8227df Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_namespace_rename.png differ diff --git a/doc/qxentityeditor/resource/qxee_naming_convention.png b/doc/qxentityeditor/resource/qxee_naming_convention.png new file mode 100644 index 0000000..2a884f5 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_naming_convention.png differ diff --git a/doc/qxentityeditor/resource/qxee_organize_diagram_layout.png b/doc/qxentityeditor/resource/qxee_organize_diagram_layout.png new file mode 100644 index 0000000..96cb22d Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_organize_diagram_layout.png differ diff --git a/doc/qxentityeditor/resource/qxee_plugin_scripts.png b/doc/qxentityeditor/resource/qxee_plugin_scripts.png new file mode 100644 index 0000000..2a53b11 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_plugin_scripts.png differ diff --git a/doc/qxentityeditor/resource/qxee_plugins_about.png b/doc/qxentityeditor/resource/qxee_plugins_about.png new file mode 100644 index 0000000..997e0cf Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_plugins_about.png differ diff --git a/doc/qxentityeditor/resource/qxee_post_it.png b/doc/qxentityeditor/resource/qxee_post_it.png new file mode 100644 index 0000000..20ef62b Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_post_it.png differ diff --git a/doc/qxentityeditor/resource/qxee_post_it_colors.png b/doc/qxentityeditor/resource/qxee_post_it_colors.png new file mode 100644 index 0000000..d1eb8b9 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_post_it_colors.png differ diff --git a/doc/qxentityeditor/resource/qxee_project_list.png b/doc/qxentityeditor/resource/qxee_project_list.png new file mode 100644 index 0000000..ba4a11e Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_project_list.png differ diff --git a/doc/qxentityeditor/resource/qxee_project_new.png b/doc/qxentityeditor/resource/qxee_project_new.png new file mode 100644 index 0000000..4ffb168 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_project_new.png differ diff --git a/doc/qxentityeditor/resource/qxee_project_settings_01.png b/doc/qxentityeditor/resource/qxee_project_settings_01.png new file mode 100644 index 0000000..f8e1a97 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_project_settings_01.png differ diff --git a/doc/qxentityeditor/resource/qxee_project_settings_02.png b/doc/qxentityeditor/resource/qxee_project_settings_02.png new file mode 100644 index 0000000..2107822 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_project_settings_02.png differ diff --git a/doc/qxentityeditor/resource/qxee_property_settings.png b/doc/qxentityeditor/resource/qxee_property_settings.png new file mode 100644 index 0000000..b2b9d0f Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_property_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_property_settings_access.png b/doc/qxentityeditor/resource/qxee_property_settings_access.png new file mode 100644 index 0000000..d418709 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_property_settings_access.png differ diff --git a/doc/qxentityeditor/resource/qxee_relation_settings.png b/doc/qxentityeditor/resource/qxee_relation_settings.png new file mode 100644 index 0000000..f91a399 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_relation_settings.png differ diff --git a/doc/qxentityeditor/resource/qxee_relation_settings_access.png b/doc/qxentityeditor/resource/qxee_relation_settings_access.png new file mode 100644 index 0000000..dc3e5f9 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_relation_settings_access.png differ diff --git a/doc/qxentityeditor/resource/qxee_sample.png b/doc/qxentityeditor/resource/qxee_sample.png new file mode 100644 index 0000000..31fb624 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_sample.png differ diff --git a/doc/qxentityeditor/resource/qxee_sample_old.png b/doc/qxentityeditor/resource/qxee_sample_old.png new file mode 100644 index 0000000..1eba857 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_sample_old.png differ diff --git a/doc/qxentityeditor/resource/qxee_sample_small.png b/doc/qxentityeditor/resource/qxee_sample_small.png new file mode 100644 index 0000000..eca696a Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_sample_small.png differ diff --git a/doc/qxentityeditor/resource/qxee_sample_small_old.png b/doc/qxentityeditor/resource/qxee_sample_small_old.png new file mode 100644 index 0000000..ffc5cdc Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_sample_small_old.png differ diff --git a/doc/qxentityeditor/resource/qxee_source_control_output_directory.png b/doc/qxentityeditor/resource/qxee_source_control_output_directory.png new file mode 100644 index 0000000..129084f Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_source_control_output_directory.png differ diff --git a/doc/qxentityeditor/resource/qxee_splitter.png b/doc/qxentityeditor/resource/qxee_splitter.png new file mode 100644 index 0000000..4ecc897 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_splitter.png differ diff --git a/doc/qxentityeditor/resource/qxee_tag_project_state_01.png b/doc/qxentityeditor/resource/qxee_tag_project_state_01.png new file mode 100644 index 0000000..67098cf Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_tag_project_state_01.png differ diff --git a/doc/qxentityeditor/resource/qxee_tag_project_state_02.png b/doc/qxentityeditor/resource/qxee_tag_project_state_02.png new file mode 100644 index 0000000..d3ea5ec Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_tag_project_state_02.png differ diff --git a/doc/qxentityeditor/resource/qxee_windows.png b/doc/qxentityeditor/resource/qxee_windows.png new file mode 100644 index 0000000..bc8b369 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_windows.png differ diff --git a/doc/qxentityeditor/resource/qxee_windows_small.png b/doc/qxentityeditor/resource/qxee_windows_small.png new file mode 100644 index 0000000..d28d7a7 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_windows_small.png differ diff --git a/doc/qxentityeditor/resource/qxee_zoom.png b/doc/qxentityeditor/resource/qxee_zoom.png new file mode 100644 index 0000000..5196a46 Binary files /dev/null and b/doc/qxentityeditor/resource/qxee_zoom.png differ diff --git a/doc/qxorm_en/customer.html b/doc/qxorm_en/customer.html new file mode 100644 index 0000000..b556f4b --- /dev/null +++ b/doc/qxorm_en/customer.html @@ -0,0 +1,492 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Our customers + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+
+ Note : QxOrm library is an open-source software downloaded every day : so it's not possible to + give a list of all users and all applications based on QxOrm library.
+ Here are some companies which use QxOrm library and QxEntityEditor application in their commercial + products :
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AGCO + + AGCO :
+ AGCO Corporation is an American agricultural equipment manufacturer based in Duluth, Georgia, + United States. As a leading global manufacturer of agricultural equipment, AGCO offers a full + line of tractors, combines, hay tools, sprayers, forage and tillage equipment, which are + distributed through more than 3,100 independent dealers and distributors in more than 140 + countries worldwide. +
+ [Description based on Wikipedia webpage] + +

+
+ ENSCO + + ENSCO :
+ ENSCO, Inc. is a provider of engineering services, products, and advanced technologies for + national security, transportation safety and asset management, information sciences, data + management including information management systems for weather monitoring, aerospace and + avionics, and R and D for private corporations and local, state, and federal agencies and + governments, including the United States Department of Defense. +
+ [Description based on Wikipedia webpage] + +

+
+ Smiths Detection + + Smiths Detection :
+ Smiths Group plc is a British multinational diversified engineering company headquartered in + London, United Kingdom. It has operations in over 50 countries and employs around 23,550 + staff.
+ Smiths Group has five divisions : Smiths Detection is the world's largest manufacturer of + sensors for the detection of explosives, weapons, chemical agents, biohazards, narcotics and + contraband. +
+ [Description based on Wikipedia webpage] + +

+
+ Veran Medical + + Veran Medical :
+ Veran Medical Technologies is focused on comprehensive oncology program. + Veran's technology is defining the new standard in early definitive diagnosis of cancer, + providing your hospital with a comprehensive navigation solution. + Established in 2005, Veran Medical Technologies is a privately held soft tissue navigation + company focused on the early diagnosis of cancer. +
+ Veran's mission is to extend life through earlier diagnosis and the delivery of minimally + invasive therapies for interventional oncology procedures with unique navigation + technologies. +
+ Veran is dedicated to increasing patient survival while providing cost effective healthcare + solutions that defined the next standard of care. +

+
+ Altran AIS + + Altran AIS :
+ Altran Technologies, SA is a global consulting firm founded in 1982 in France. Altran + operates primarily in high technology and innovation consultancy, which account for nearly + 75% of its turnover. Administrative and information consultancy accounts for 20% of its + turnover with strategy and management consulting making up the rest. +
+ [Description based on Wikipedia webpage] + +

+
+ Intermountain Healthcare + + Intermountain Healthcare + :
+ Intermountain Health Care, Inc., officially doing business as Intermountain Healthcare, is a + non-profit healthcare system and is the largest healthcare provider in the Intermountain + West. Until 2005 it was known as Intermountain Health Care or more commonly IHC; it is now + often referred to as simply Intermountain for short. Intermountain Healthcare provides + hospital and other medical services in Utah and Idaho and also offers integrated managed care + under the insurance brand SelectHealth. Intermountain Healthcare is headquartered in Salt + Lake City, Utah, and (as of 2014) employed over 33,000 people. +
+ [Description based on Wikipedia webpage] + +

+
+ GSI Electronics Inc. + + GSI Electronics Inc. + :
+ GSI Electronics Inc. develops, manufactures and distributes innovative technological products + for the agricultural industry. GSI Electronics Inc. unique expertise allows them to offer + accurate, simple and diverse electronic, data processing and mechanical solutions for + improving agricultural production. +

+
+ Sagemcom + + Sagemcom :
+ A French high-tech group of international dimensions, Sagemcom operates on the broadband + (digital home, set-top boxes, Internet routers, telephony and multimedia terminals), telecoms + and energy (smartgrid and energy management) and retail. +

+
+ Motius + + Motius :
+ Motius is a unique German R&D company. It solves technical problems and develops products for + international customers through a pool of elite senior students, academic researchers and + young engineers. +

+
+ GSVitec + + GSVitec :
+ Production of high-speed video and measurement data acquisition devices and software.
+ Production of High Power LED light solutions especially for high speed video. Production and + design of High Power custom LED solutions (crash test, military, r&d).
+ Software solutions for synchronous high speed data and video acquisition and recording.
+

+
+ Promenade Software + + Promenade Software :
+ Promenade Software is a company comprised of highly skilled, experienced software engineers. + Whether it is for a medical device, avionics test system, or other sensitive system, + Promenade Software knows that their work is critical. + Critical to your company, your customer, and everyone involved. Promenade Software has the + skills and ready-made tools to deliver your product reliably and efficiently. +
+ Unlike other software service providers, Promenade Software took the time to create the + ready-made libraries and test tools that increase your system's quality, while saving you + money and development time. +

+
+ IVE mbH + + IVE mbH :
+ Since founding IVE mbH, Consulting Company for Traffic and Railway Engineering Ltd., in 1998 + IVE proficiently supports clients from the development of first ideas to the final + realisation and the practical use of projects. + Based on transport and railway expertise, IVE mbH derives concepts and future-oriented + sustainable solutions responding to the problems of clients, strengthening their position and + preparing them for the global competition. +

+
+ NauchPribor + + NauchPribor :
+ NauchPribor is a high-tech company aimed on developing and producing low dose x-ray devices + for medical and security fields.
+ Founded more than 40 years ago, now this company is one of the most advanced in + business.
+ It has customers from all over the world. Headquartered resides in Orel, Russia.
+

+
+ Tang + + Tang :
+ Tang A/S develops a PMS system for the veterinary business.
+ Their products are selling in Denmark, Norway and Sweden.
+

+
+
+ All organization names, logos and trademarks used in this web page are for identification purposes only. + All trademarks and logos are the property of their respective owners. +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/download.html b/doc/qxorm_en/download.html new file mode 100644 index 0000000..1d43e1c --- /dev/null +++ b/doc/qxorm_en/download.html @@ -0,0 +1,1254 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Download + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
QxOrm is a C++ library available under a dual license : +
    +
  • GNU/GPLv3 license : open-source and + free (to develop an open-source project or to evaluate QxOrm library) ;
  • +
  • Proprietary license to distribute an application based on + QxOrm library without any restrictions of GNU/GPLv3 license.
  • +
+ + + + + + + + + +
Download QxOrm + + + Download QxOrm 1.5.0 (source + test + documentation)
+ This version has been tested with Visual Studio on Windows, GCC on Linux and Mac + OS X, MinGW on Windows, and Clang on Mac OS X : a C++11 compiler is required. +
+
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+

QxEntityEditor is a graphic editor for QxOrm library : QxEntityEditor + provides a graphic way to manage the data model.
+ QxEntityEditor is multi-platform (available for Windows, Linux and Mac OS X) and generates native + code for all environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android, iOS, Windows + Phone, Raspberry Pi, etc.). +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QxEntityEditorQxEntityEditor 1.2.8 - Windows 32 bitsQxEntityEditorQxEntityEditor 1.2.8 - Windows 64 bits
QxEntityEditorQxEntityEditor 1.2.8 - Windows 32 bits (portable)QxEntityEditorQxEntityEditor 1.2.8 - Windows 64 bits (portable)
QxEntityEditorQxEntityEditor 1.2.8 - Linux 32 bitsQxEntityEditorQxEntityEditor 1.2.8 - Linux 64 bits
QxEntityEditorQxEntityEditor 1.2.8 - Mac OS X
+

+

Note : by default, QxEntityEditor application is limited to 5 entities per + project. + To get a license key and create unlimited entities per project, please contact us using this e-mail : ic-east.com. + Price of a QxEntityEditor license key : 500€ (per developer, 12 months of free + updates).
+
+ A user manual (documentation) for QxEntityEditor application is + available. +

+ QxEntityEditor +

+
+

+ QxOrm is based on Qt framework : +

+ + + + + + + + + +
QtQt : cross-platform application development framework : GUI (QtGui), + network (QtNetwork), XML (QtXml), database (QtSql)...
+ Qt provides excellent support and documentation. Using Qt, you can write simple and powerful C++ + code.
+ Qt is produced by Digia's Qt Development Frameworks division and is available under LGPL license.
+ QxOrm is compatible with many Qt's objects : QObject, QString, QDate, QTime, QDateTime, QList, + QHash, QSharedPointer, QScopedPointer...
+ It is recommended to install the latest version of Qt available at the following address : http://www.qt.io/
+

+ +
+ Here are all changes logs of QxOrm library and QxEntityEditor application : + +
+ QxOrm library history : + + + + + + + +
+ +

Changes in version 1.5.0:

+
+ - Fix qx::dao::fetch_by_id_with_relation() when a table alias is used (table alias is now used in + the WHERE part instead of table name)
+ - Fix qx::IxDataMember::getType() method when used in a multi-thread environment
+ - New method qx::IxSqlRelation::linkRelationKeyTo() for MongoDB database to simulate lazy loading + for relationships (GitHub #107)
+ - Fix qx::QxSqlDatabase and multi-thread issue when the OS assigns an old and destroyed thread + identifier to a new one (GitHub #42) + add method qx::QxSqlDatabase::removeDatabaseByThread() to + call at the end of a thread execution
+ - Fix qx::QxSimpleCrypt class with Qt version >= 5.10 and error "Attempted to overwrite a + QRandomGenerator to system() or global()"
+ - Fix database not opened using async queries (GitHub #109)
+
+ +

Changes in version 1.4.9:

+
+ - Fix compilation issue with Qt 6.2+ (due to Qt JIRA : https://bugreports.qt.io/browse/QTBUG-92910), + more details in GitHub issue #54
+ - Support QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of + C++ instances in database (new optional parameter 'bUseExecBatch' available for functions : + qx::dao::insert, qx::dao::update, qx::dao::delete_by_id)
+ - New method in qx::QxSqlQuery class named setFctOnBeforeSqlPrepare() to define a custom callback + function to modify SQL query before preparing in database
+ - New callbacks functions available in qx::IxDataMember interface to customize SQL generated per + data member (see an example in ./test/qxBlogCompositeKey/src/blog.cpp file)
+ - Fix an issue in qx::QxSqlRelationLinked::hierarchyResolveOutput() which could call + getIdFromQuery() for nothing, which could generate some warnings in Qt SQL driver (for example : + QPSQLResult::data: column XX out of range)
+ - Fix a compilation issue of QxRestApi and QxHttpTransaction modules with Qt QStringBuilder option + enabled (GitHub issues #50, #83)
+ - Improve SQL DISTINCT to support relationships (unit test available in qxBlog sample project)
+ - New feature to fetch relationships only in LEFT OUTER/INNER JOIN and WHERE clauses (so no columns + in SELECT part) : use {NULL} syntax to define no relation columns in SELECT part (unit test + available in qxBlog sample project)
+ - Fix a crash which could occur using qx::QxSession and multi-threaded environment
+ - Add a new parameter caseSensitive (default value : false) to the method + qx::QxSqlQuery::getSqlResultAt()
+ - Fix an issue with JSON REST API (QxRestApi module) and MongoDB database (more details in GitHub + issue #70)
+ - Improve qx::QxClassX::registerAllClasses() : init all validator instances (can fix some issues in + a multi-thread environment)
+ - New settings available in the qx::QxSqlDatabase singleton class + (setSqlDelimiterForTableNameAlias() and setSqlDelimiterForColumnNameAlias()) to add delimiters to + SQL aliases (more details in GitHub issue #57)
+ - Fix linking error which could occur with Qt6 and MSVC2019 (should fix GitHub issues #98, #91, #89, + #90, #62, #65)
+ - Fix all checks with QT_VERSION (using macro QT_VERSION_CHECK), should fix checks from Qt 5.10 to + Qt 5.15 (GitHub issue #81)
+
+ +

Changes in version 1.4.8:

+
+ - Support Qt6 (tested with MSVC 2019 + CMake 3.19 on Windows) ==> QxOrm library is compatible + with Qt4, Qt5 and Qt6
+ - Support PIMPL idiom for persistent classes (useful to reduce compilation times, to provide a + stable ABI, ascendant compatibility for shared libraries, to reduce binaries size)
+ - Documentation about PIMPL idiom for persistent classes : + https://www.qxorm.com/qxorm_en/manual.html#manual_455
+ - New sample project named qxBlogPImpl in ./test/ directory of QxOrm package to show how to + implement persistent classes using the PIMPL idiom
+ - Possibility to ignore soft delete behavior during a session execution (useful to fetch logical + deleted instances for example) : qx::QxSession::ignoreSoftDelete()
+ - Fix SQL DISTINCT keyword in qx::QxSqlQuery class (when DISTINCT is used, then the primary key is + not fetched)
+ - Fix an issue which could happen after enabling _QX_ENABLE_QT_NETWORK compilation option (due to + QT_NO_SSL/QT_NO_OPENSSL used in QxThread.cpp file)
+ - Fix an issue in qx::QxSqlDatabase and multi-thread context when a thread identifier is reused + (GitHub issue #42)
+ - Add new behavior to qx::QxSession class with setAutoRollbackWhenDestroyed() option : if true, then + database rollback is called when session instance destructor (or close() method) is invoked (instead + of commit by default, GitHub issue #43)
+
+ +

Changes in version 1.4.7:

+
+ - Fix a MongoDB issue with qx::dao::fetch_by_id_with_relation() (wrong id fetched)
+ - Fix an issue with qx::dao::fetch_all when a custom list of columns with the primary key is + used
+ - Fix identifier JSON serialization for MongoDB with properties registered as Q_PROPERTY (Qt + property meta system)
+ - Fix a crash (seg fault) using qx::IxPersistable with multiple inheritance (for example QObject + + qx::IxPersistable) due to some static_cast to void * in QxFactory module (fix also for QxService + module and multiple inheritance)
+ - Remove automatic relationship lazy fetch when not requested in query
+ - Fix an issue with QJson and QDataStream serialization when class doesn't contain any identifier + (so not a database class) and is a wrapper of another registered class (can have same address + pointer as parent)
+ - Improve qx::QxSqlQuery::freeText() method to add custom text to build SQL query : support + placeholders (add second parameter const QVariantList & values)
+ - Improve performance in a multi-threads environment (mutex in qx::IxSqlQueryBuilder)
+ - New setting to display more details (execution times) in qx::dao functions logs (to enable this + new feature : qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true))
+ - Improve MongoDB integration to fetch a list of items : build C++ instances as soon as possible + without putting data in a buffer (better performance + less memory usage)
+ - Improve MongoDB integration : support qx::dao::delete_by_query() function with MongoDB aggregation + framework
+ - Improve qx::QxSqlQuery class (or its qx_query alias) : new addJoinQuery() method to insert SQL + sub-queries inside LEFT OUT JOIN / INNER JOIN (more details in documentation here : + https://www.qxorm.com/qxorm_en/manual.html#manual_3855)
+ - Improve qx::QxSqlQuery class : new constructors with placeholders support + new methods to embed + SQL sub-queries (in_Select, notIn_Select, isEqualTo_Select, isNotEqualTo_Select)
+ - Improve qx::QxCollection class : qx::QxCollection is now a thread-safe container (fix for example + QxModelView module when model is fetched in a different thread than the view)
+
+ +

Changes in version 1.4.6:

+
+ - New QxHttpServer module : C++/Qt standalone multi-threaded HTTP 1.1 web server (support SSL/TLS, + persistent connections, cookies, sessions, chunked responses, URL dispatcher/routing, no other + dependency except QtNetwork) : https://www.qxorm.com/qxorm_en/manual.html#manual_96
+ - New QxRestApi module : provide a REST API to send requests in JSON format from external + application (web services), from web-site (written in Angular for example), from QML or from + scripting langage (like Python) : https://www.qxorm.com/qxorm_en/manual.html#manual_97
+ - With QxHttpServer and QxRestApi modules, QxOrm library can now be used to create web applications, + especially single-page applications (SPA) with famous Javascript frameworks like AngularJS, React, + Meteor.js, etc...
+ - New project example named qxBlogRestApi : QML application with a list of REST requests to show how + to send JSON queries from Javascript to QxRestApi module + HTTP web server application to show how + to create web applications using QxHttpServer module
+ - QxRestApi module supports : all CRUD operations, complex queries, several levels of relationships, + custom JSON output format, call dynamically native C++ functions registered in QxOrm context, + instance validation, call custom database queries
+ - Improve JSON serialization engine : possibility to define a custom filter to not export all + properties (https://www.qxorm.com/qxorm_en/manual.html#manual_606)
+ - Possibility to define a custom SQL table alias for complex queries with relationships using syntax + <my_table_alias> (https://www.qxorm.com/qxorm_en/manual.html#manual_3850)
+ - Improve SQL generator for Oracle database : manage last insert id using RETURNING INTO syntax (thx + to Romain Macureau and Abdennour Boutrig)
+ - Fix an issue with stored procedure and output parameters
+ - New function available : qx::dao::count_with_relation<T>()
+ - Fix JSON serialization in multi-thread environment
+ - Change JSON QDateTime and QTime serialization format : use Qt::ISODateWithMs instead of + Qt::ISODate (Qt 5.8 or +)
+ - Improve QxService module : support SSL/TLS secure connections + keep-alive connections
+ - Remove *.suo files (MSVC++ temporary project files) from QxOrm package
+
+ +

Changes in version 1.4.5:

+
+ - Support MongoDB database : QxOrm library becomes a C++/Qt Object Document Mapper ODM library !
+ - For more details about MongoDB integration, see QxOrm manual + (https://www.qxorm.com/qxorm_en/manual.html#manual_95) and new sample project available in + ./test/qxBlogMongoDB/ directory
+ - QxOrm library is now available on GitHub (official repository) : + https://github.com/QxOrm/QxOrm
+ - Fix an issue in qx::IxSqlQueryBuilder class when QxOrm library is used in a multi-thread + environment
+ - Support latest version of boost (1.66)
+ - Update boost portable binary serialization classes to version 5.1 (provided by + https://archive.codeplex.com/?p=epa)
+ - Fix an issue building SQL query for Oracle database (doesn't support AS keyword for table + alias)
+ - Improve qx::QxClassX::registerAllClasses() function : possibility to initialize all relations + (useful to work with introspection engine)
+ - Improve qx::IxPersistable interface : provide new methods toJson() / fromJson()
+ - Improve documentation/website : change http://www.qxorm.com by https://www.qxorm.com + everywhere
+ - Fix fetching relations with soft delete putting SQL condition in the JOIN part instead of WHERE + part
+ - Fix SQL generator for Oracle database : use new limit/pagination syntax (version Oracle > + 12.1)
+ - Improve SQL generator interface : add 'onBeforeSqlPrepare()' method to modify/log SQL queries in + custom classes
+ - Add an option in qx::QxSqlDatabase class to format SQL query (pretty-printing) before logging it + (can be customized creating a qx::dao::detail::IxSqlGenerator sub-class)
+ - Fix an issue with boost/std::optional (to manage NULL database values) and some databases : if + optional is empty, then create a NULL QVariant based on QVariant::Type
+ - Add an option in qx::QxSqlDatabase class to insert square brackets (or any other delimiters) in + SQL queries for table name and/or column name (to support specific database keywords)
+ - Improve introspection engine : add getType() method in qx::IxDataMember interface to get C++ type + of a property dynamically
+ - Improve qx::QxSqlDatabase singleton settings class to make easier working with several databases : + now there are 3 levels of settings : global >> per thread >> per database (see + 'bJustForCurrentThread' and 'pJustForThisDatabase' optional parameters in all setXXXX() methods)
+ - Fix QxOrm.pri for MinGW compiler on Windows : an issue could occurred to export some symbols from + shared library (some Qt signals for example)
+ - Add an option in qx::QxSqlDatabase singleton class to display only slow SQL queries (see + setTraceSqlOnlySlowQueriesDatabase() and setTraceSqlOnlySlowQueriesTotal() methods)
+
+ +

Changes in version 1.4.4:

+
+ QxOrm library doesn't depend on boost framework anymore (the boost dependency has been fully + removed, replaced by some C++11 features).
+ So QxOrm library is now a pure Qt library which depends only on QtCore and QtSql by default.
+ For backward compatibility, QxOrm library still supports some boost classes (boost smart-pointers, + unordered containers, boost::optional, etc...) : you have to define _QX_ENABLE_BOOST compilation + option to enable these features.
+
+ Main advantages are :
+ - QxOrm becomes a much lighter library
+ - easier to install (because you don't have to deal with boost anymore)
+ - reduce compilation times
+ - reduce output binary size
+
+ Thx also to Jimmy Taker for several improvments and new features in QxModelView module !
+
+ - QxOrm library now requires a C++11 compiler (please note that QxOrm doesn't require a full + compliant C++11 compiler : for example, QxOrm can be built and used with MSVC 2012, GCC 4.5 or Clang + 3.2)
+ - Implement PIMPL idiom for some QxOrm classes to reduce compilation times and output binary + size
+ - New class named qx::any to replace boost::any (basic implementation of boost::any written by + Kevlin Henney)
+ - qx_shared_ptr alias doesn't exist anymore : it is replaced everywhere by std::shared_ptr
+ - QxModelView module : all models based on qx::IxModel class can now be sorted (on all columns), + please note that you can also use QSortFilterProxyModel Qt class to sort your model
+ - QxModelView module - qx::QxModel<T> : fix setData() with e_auto_update_on_field_change + option when an error occurred saving data in database, now previous value is restored if an error + occurred
+ - QxModelView module - qx::IxModel : fix setHeaderData() using it with default role (Qt::EditRole) + changes the header in a header view (role Qt::DisplayRole)
+ - QxModelView module - qx::IxModel : if a description is registered in QxOrm context, then it is + displayed in header for each property
+ - QxModelView module : new feature available to add automatically an empty row at the end of the + table to insert quickly new items (setShowEmptyLine() method)
+ - QxModelView module : possibility to define an intermediate base class between qx::IxModel and + qx::QxModel<T> to provide your own model features, for example imagine you develop a drag&drop + feature in a class named IxModelDragDrop, you can now create a QxOrm model like this (see the second + template parameter) : qx::IxModel * pModel = new qx::QxModel<MyPersistantClass, + IxModelDragDrop>();
+ - QxOrm.pro : fix DESTDIR parameter on Windows
+ - QxOrm.pri and QxOrm.cmake : add a section to enable QT_USE_QSTRINGBUILDER to optimize QString + operations
+ - QxOrm library is now tested with MSVC 2015 compiler (support all MSVC versions from 2012)
+ - Fix a bug in QxSqlError.h file with a qPrintable() call on a temporary object
+ - Provide more details in logs after executing a SQL query : time to execute query in database + + time to fetch C++ instances
+ - Support std::optional<T> (if your compiler supports C++17 features) to manage NULL database + value : new header available named <QxExtras/QxStdOptional.h> to include just after + <QxOrm.h> header file (ideally in a precompiled header)
+
+ +

Changes in version 1.4.3:

+
+ - Support CMake : new CMakeLists.txt file added to build QxOrm library with CMake
+ - Improve SQL error messages when qx::dao functions return a database error
+ - New parameter in singleton class qx::QxSqlDatabase to log SQL bound values + (setTraceSqlBoundValues) : by default, bound values are logged when an error occurred
+ - New syntax to select columns to not fetch : -{ col_1, col_2, etc... }
+ - New function qx::dao::call_query_without_prepare() to execute specific SQL queries without + prepared statement
+ - Improve QxModelView module : all QxOrm models (based on qx::IxModel interface) can be serialized + to JSON format (including all relationships levels) : this is now another way to work with + relationships and QML (thanks to JSON.parse() and JSON.stringify() javascript functions) without + using nested models concept (so without using QxEntityEditor model/view generated classes)
+ - Improve qxBlogModelView sample project and QxOrm manual to show how to access to relationships + data in QML (nested models or JSON)
+ - Fix a memory leak in qx::QxSqlRelation class
+ - Reduce output binary size (~20%) and compilation times (~20%) to build persistent classes based on + QxOrm library
+ - Support unity build concept to reduce compilation times to build QxOrm library and C++ persistent + classes generated by QxEntityEditor application : for more details, see _QX_UNITY_BUILD compilation + option in QxOrm.pri or QxOrm.cmake configuration file
+ - Improve QxConvert module : possibility to store in database complex QVariant properties which + contain QVariantMap, QVariantHash or QVariantList types (JSON format)
+ - Fix an issue with some databases when a foreign key is also a part of the primary key
+ - Fix an issue with QSharedPointer and boost::serialization when a same raw pointer is shared by + several QSharedPointer during deserialization process
+
+ +

Changes in version 1.4.2:

+
+ - Support JSON serialization : each C++ class registered in QxOrm context can be + serialized/deserialized in JSON format (JSON feature requires Qt5)
+ - For more details about JSON serialization, read QxOrm manual here : + https://www.qxorm.com/qxorm_en/manual.html#manual_606
+ - With JSON serialization and QxService module : it is now possible to create REST Web Services to + send data to a javascript engine (web pages for example)
+ - Fix some compilation errors with recent (and less permissive) compilers and latest versions of + boost and Qt
+ - Fix relationship initialization assertion with complex, deep and circular relationships in large + database schema
+ - Improve QDataStream serialization : should be faster now and fix an issue with circular instances + dependencies
+ - Fix a bug fetching 1-n and n-n relationships when root is a container of stack objects (it worked + only with pointers or smart-pointers, for example : QList<blog> vs + QList<std::shared_ptr<blog>>)
+ - Improve qx::dump() function : possibility to display a C++ instance state in XML or JSON + format
+
+ +

Changes in version 1.4.1:

+
+ !!! IMPORTANT NOTE ABOUT THIS VERSION !!! : it is strongly recommended to read the QxOrm.pri + configuration file of this new version (compilation options have changed compared to previous + versions).
+ Now, by default, QxOrm library is a much lighter library : QxOrm depends only on QtCore and + QtSql (boost serialization is now optional and not required by default).
+ By default, serialization engine is now based on Qt QDataStream class (but you can still enable + boost serialization defining _QX_ENABLE_BOOST_SERIALIZATION compilation option in QxOrm.pri + configuration file).
+ So now, with default options :
+ - QxOrm 1.4.1 is much easier to install because you don't have to deal with boost serialization + extra dependency ;
+ - QxOrm 1.4.1 shared library is 3X smaller than 1.3.2 version ;
+ - Generated binaries which depends on QxOrm library are 25% smaller ;
+ - If you are not using serialization functions in current projects based on QxOrm library, then you + can define or not _QX_ENABLE_BOOST_SERIALIZATION compilation option without changing any line of + your source code.
+
+ Here are all other changes of version 1.4.1:
+ - Improve relationships engine : possibility to select columns to fetch using syntax : my_relation { + col_1, col_2, etc... }
+ - Improve QxTraits module to reduce compilation times and build smaller binaries
+ - Improve QxOrm website adding possibility to search and replacing the old FAQ by a more organized + manual (user guide)
+ - New compilation option _QX_ENABLE_BOOST_SERIALIZATION to enable boost serialization dependency + (read QxOrm.pri configuration file for more details)
+ - New compilation option _QX_ENABLE_QT_NETWORK to enable QxService module (transfer persistent layer + over network) : read QxOrm.pri configuration file for more details
+ - New compilation option _QX_NO_RTTI to build QxOrm library without C++ RTTI type information
+ - Support QDataStream Qt serialization engine (used by default when _QX_ENABLE_BOOST_SERIALIZATION + compilation option is not defined)
+ - Improve qx_query class (SQL queries) : new method (named customOperator()) which gives the + possibility to define a custom operator (for example <@ for PostgreSQL ltree type)
+ - Fix a program startup issue due to 'static initialization order fiasco' creating singletons (it + was an issue with some compilers during the shared library link process)
+ - New namespace qx::dao::throwable : same functions as qx::dao namespace, but they throw a + qx::dao::sql_error exception when a SQL error occurred (instead of returning a QSqlError + instance)
+ - Add a qAssertMsg() macro to put a more explicit error message when throwing an assertion
+ - Include all *.inl files (template implementation) in QxOrm.pro project file : QtCreator can now + index these *.inl files in its project treeview
+ - Rename QxStringCvt to QxConvert : so if you persist custom types to database, you have to rename + from QxStringCvt_FromVariant, QxStringCvt_ToVariant to QxConvert_FromVariant, + QxConvert_ToVariant
+
+ +

Changes in version 1.3.2:

+
+ - Support C++11 types (need to set compilation options in QxOrm.pri config file to enable these + features)
+ - With _QX_CPP_11_SMART_PTR compilation option : std::unique_ptr, std::shared_ptr, std::weak_ptr
+ - With _QX_CPP_11_CONTAINER compilation option : std::unordered_map, std::unordered_set, + std::unordered_multimap, std::unordered_multiset
+ - With _QX_CPP_11_TUPLE compilation option : std::tuple
+
+ +

Changes in version 1.3.1:

+
+ - New class qx::QxModelService<T, S> in QxModelView module to connect a Qt model to services + to execute client-server requests (can be used with QML and QtWidgets views)
+ - Add some useful methods to qx::IxModel class and fix several issues with the QxModelView + module
+ - Support last version of MinGW with large precompiled header bug : new compilation option + _QX_NO_PRECOMPILED_HEADER (to enable in QxOrm.pri file)
+ - Fix issue when loading several shared libraries on Windows with services registered in QxService + module
+ - Fix the qx::QxSqlQuery serialization process used by QxService module to send requests over + network
+ - Fix an issue with qx::QxCollection<Key, Value> class when inserting an item at last + position
+
+ +

Changes in version 1.2.9:

+
+ - Improve nested models in QxModelView module to be able to use several relationships levels in + QML
+
+ +

Changes in version 1.2.8:

+
+ - New function qx::model_view::create_nested_model (QxModelView module) used by QxEntityEditor to + manage complex data structure to work with relationships in QML views and Qt model/view + architecture
+ - New section in the QxOrm.pri file with some tips to reduce output binaries size
+ - Fix the call of triggers to have the inserted ID inside the trigger function with PostgreSQL
+
+ +

Changes in version 1.2.7:

+
+ - New module QxModelView : now, all classes registered in QxOrm context can be used with Qt + model/view architecture (Qt widgets and/or QML views)
+ - qx::IxModel interface provides an easy way to work on QML with QxOrm library and interact with + databases
+ - For more details about the new module QxModelView, goto the FAQ : 'How to use QxModelView module + to interact with Qt model/view architecture (Qt widgets and/or QML views) ?'
+ - New function qx::dao::save_with_relation_recursive(), useful to save a full tree structure for + example
+ - Remove the dependency on the STL compatibility functions in Qt (QT_NO_STL), which may not be + available (thanks to KDE Plasma Media Center team for the patch)
+ - Support database table defined into a schema (using qx::IxDataMember::setName() function)
+
+ +

Changes in version 1.2.6:

+
+ - First version full compatible with QxEntityEditor application : the graphic editor for QxOrm + library !
+ - For more details about QxEntityEditor, go to QxOrm website : https://www.qxorm.com/
+ - Thanks to the recent release of Qt 5.2, QxOrm library can now be used on Android and iOS
+ - Improve relationships and triggers engine
+ - Triggers onBeforeFetch() and onAfterFetch() called when fetching relationships
+ - Fix release mode detection during compilation : should improve performance on some + environments
+ - Add serialization for QSqlError, qx::QxSqlQuery, qx::QxInvalidValue and qx::QxInvalidValueX + classes
+
+ +

Changes in version 1.2.5:

+
+ - New license : go to download page of QxOrm website for more details
+ - Support Qt5
+ - New compiler supported : Clang (tested on Mac OS X)
+ - Now each QxOrm version will be tested in 32-bit and 64-bit mode
+ - Improve QxOrm introspection engine : possibility to register static class methods
+ - Improve QxService module : now it's easy to add an authentication process on server side
+ - New class qx::exception to get error code + error description with services methods throwing an + exception
+ - New settings available in QxOrm.pri config file (whithout changing QxConfig.h file)
+ - Possibility to implement specifics database SQL functions overriding qx_query class
+ - Fix an issue when fetching multiple levels of relationship and NULL pointers
+ - Fix a bug with MS SQL Server database and update queries using auto-increment id
+
+ +

Changes in version 1.2.4:

+
+ - New relationship engine to fetch easily many levels of relationships per query
+ - For more details about this new engine, goto the FAQ : 'How to use relationship engine to fetch + datas from many tables ?'
+ - Add 2 functions : qx::dao::execute_query and qx::dao::call_query to call a stored procedure or a + custom SQL query
+ - For more details about this new feature, goto the FAQ : 'How to execute a stored procedure or a + custom SQL query ?'
+ - Add support for boost::optional type to manage NULL database value without using QVariant type
+ - New class : qx::QxDaoAsync to make easier to execute queries in asynchronous way + (multi-thread)
+ - For more details about this new class, goto the FAQ : 'How to use qx::QxDaoAsync class to execute + queries in asynchronous way (multi-thread) ?'
+
+ +

Changes in version 1.2.3:

+
+ - New interface 'qx::IxPersistable' (abstract class) to simplify polymorphism using QxOrm + library
+ - For more details about this new interface, goto the FAQ : 'How to use qx::IxPersistable interface + ?'
+ - New methods into 'qx::IxCollection' interface to iterate over each items without knowing its + type
+ - New option into 'QxOrm.pri' file to build QxOrm library statically (see '_QX_STATIC_BUILD' + option)
+ - New triggers : 'qx::dao::on_before_fetch' and 'qx::dao::on_after_fetch' (for more details, goto + the FAQ : 'How to define a Trigger with QxOrm ?')
+ - Add 'std::type_info' class information to introspection engine
+ - Some minor bugs fixed ('qx::dao::sql_error' exception message, SQL query column alias, mutex, + etc.)
+
+ +

Changes in version 1.2.2:

+
+ - New module to provide a validation engine : QxValidator module
+ - For more details about QxValidator module, goto the FAQ of QxOrm library : 'How to use QxValidator + module to validate automatically an instance ?'
+ - Fix last insert ID with PostgreSQL using 'RETURNING' keyword : fetch inserted ID instead of + OID
+ - Improve SQL generator providing the good SQL type for all databases
+ - Add support for special database keywords using '[', ']' and '"' characters
+
+ +

Changes in version 1.2.1:

+
+ - Improve 'qx::QxSqlQuery' class : new engine to build queries without writing SQL, for more + details, see the FAQ 'How to build a query without writing SQL with the class qx::QxSqlQuery ?'
+ - Improve 'qx::QxSession' class : provide persistent methods (CRUD) without using 'qx::dao::xxx' + functions, for more details, see the FAQ 'How to use a session (qx::QxSession class) to manage + automatically database transactions (using C++ RAII) ?'
+ - Implement 'repository' pattern to provide a common interface for persistent methods (CRUD) with 3 + new classes : 'qx::IxRepository', 'qx::QxRepository<T>' and 'qx::QxRepositoryX'
+ - Possibility to serialize a QVariant 'UserType' with serialization engine of QxOrm library
+ - Improve thread-safe 'qx::cache' : add insertion date-time into the cache to verify that an element + must be updated or not, for more details, see the FAQ 'How to use the cache (functions into + namespace qx::cache) of QxOrm library ?'
+ - FAQ updated on QxOrm website with now 28 questions and answers
+
+ +

Changes in version 1.1.9:

+
+ - Possibility to register automatically Qt meta-properties (using Q_PROPERTY macro) to QxOrm context + without writing mapping function per class (void qx::register_class<T>())
+ - Strong integration with Qt introspection/moc engine : for more details about this new feature, + goto the FAQ 'How to register automatically Qt meta-properties to QxOrm context ?'
+ - Improve introspection/reflection engine : see the FAQ (How to use introspection engine (or + reflection engine) of QxOrm library ?) for more details
+ - Possibility to add meta-data (using a property bag) to introspection engine : see 'IxClass', + 'IxDataMember' and 'IxFunction' classes for more details
+ - Add function 'qx::QxClassX::dumpSqlSchema()' to explain how to create your own SQL schema based on + C++ classes
+ - New class 'qx::QxSimpleCrypt' to provide encryption/decryption (thanks very much to Andre Somers) + : so it's now possible to store encrypted data into database without using an external library
+ - QxService module : new feature to encrypt/decrypt data before transfering it over network
+
+ +

Changes in version 1.1.8:

+
+ - QxOrm library can now be used on Mac (thanks very much to Dominique Billet) : see + 'osx_build_all_debug.sh' and 'osx_build_all_release.sh' scripts to build QxOrm library and all + samples in './test/' directory
+ - Add 'qx::QxSession' class : define a session to manage automatically database transactions (using + C++ RAII), see the FAQ for more details
+ - Add 'qx::QxDateNeutral', 'qx::QxTimeNeutral' and 'qx::QxDateTimeNeutral' classes : helper classes + to store date-time value into database under neutral format => cross database compatibility
+
+ +

Changes in version 1.1.7:

+
+ - Add soft delete behavior : see the FAQ (How to define a soft delete behavior ?) for more details + about this new feature
+ - Add functions into namespace 'qx::dao' to update an element with a SQL condition : + update_by_query, update_optimized_by_query, etc.
+ - Fix a bug when QVariant type is used for a property of a persistent class : so, it's now possible + to insert NULL value into database
+
+ +

Changes in version 1.1.6:

+
+ - QxOrm library online documentation available : 'https://www.qxorm.com/doxygen/index.html'
+ - Possibility to disable QtGui dependency using compilation option in 'QxConfig.h' file : + _QX_ENABLE_QT_GUI_DEPENDENCY
+ - Possibility to disable QtNetwork dependency (so QxService module too) using compilation option in + 'QxConfig.h' file : _QX_ENABLE_QT_NETWORK_DEPENDENCY
+ - Provide a new macro to register abstract class into QxOrm context : + QX_REGISTER_ABSTRACT_CLASS()
+
+ +

Changes in version 1.1.5:

+
+ - New feature available : 'QxService' module to create C++ application server
+ - 'QxService' provides an easy and powerful way to create services and to transfer data over + network
+ - New tutorial available to explain how 'QxService' module works
+ - New sample available at './test/qxClientServer' directory
+ - QxOrm can be built with 'CONFIG += no_keywords' flag in '*.pro' files
+ - Bug fix with 'qx::dao::create_table<>' function and relation 'many-to-many'
+ - QxOrm should now build fine with GCC <= 4.2
+
+ +

Changes in version 1.1.4:

+
+ - New parameter in functions 'qx::dao::fetch_by_id', 'qx::dao::fetch_all', 'qx::dao::fetch_by_query' + and 'qx::dao::update' to define a list of properties to fetch/update (by default, all properties are + fetched/updated)
+ - Support multi-columns primary key (composite key) : see sample './test/qxBlogCompositeKey/'
+ - Improve strategy of inheritance : QxOrm supports 'Concrete Table Inheritance' strategy ('Concrete + Table Inheritance' becomes default strategy)
+ - New smart-pointer 'qx::dao::ptr<T>' based on Qt 'QSharedPointer<T>' to provide 2 new + features : 'is dirty' and 'update optimized'
+ - 'qx::dao::ptr<T>' can be used with a simple object and with many containers (stl, boost, Qt + and 'qx::QxCollection' containers)
+ - 'qx::dao::ptr<T>' keeps original values from database and provides a 'isDirty()' method to + retrieve all properties changed
+ - 'qx::dao::update_optimized' must be used with 'qx::dao::ptr<T>' to save into database only + properties changed
+
+ +

Changes in version 1.1.3:

+
+ - This version works fine with MinGW on Windows
+
+ +

Changes in version 1.1.2:

+
+ - License LGPL
+ - Fix compilation problems on Linux and boost > 1.38
+ - Fix sql query with MySql database
+ - Disable assert when qx::dao functions return an error
+
+ +

Changes in version 1.1.1:

+
+ - This version supports Visual Studio 2010
+
+ +

Changes in version 1.1.0:

+
+ - First release
+
+

+
+ QxEntityEditor application history : + + + + + + + +
+ +

Changes in version QxEntityEditor 1.2.8:

+
+ - New export plugin 'QxEESourceControlExport' : export a *.qxee QxEntityEditor project file to a + list of JSON files which can be easily check-in in a source control repository (Git, Perforce, CVS, + etc...)
+ - New import plugin 'QxEESourceControlImport' : import a list of JSON files (generated using + 'QxEESourceControlExport' export plugin) inside a *.qxee QxEntityEditor project file
+ - These 2 new plugins allow a team development to work simultaneously on a same *.qxee + QxEntityEditor project file
+ - A typical workflow could be (with 2 developers named dev A and dev B) :
+ * dev A and dev B work on a same *.qxee QxEntityEditor project file
+ * dev A create/modify/change some entities in QxEntityEditor application
+ * dev B create/modify/change other entities in QxEntityEditor application
+ * dev A and dev B export the *.qxee project file using the new 'QxEESourceControlExport' export + plugin
+ * Once exported, dev A and dev B check-in the JSON files inside the source control manager (Git, + Perforce, CVS, etc...) on their own branch
+ * dev A and dev B integrate from their own branch to the DEV (or MAIN or MASTER) branch (if there + are some conflicts to resolve, it should be easy because JSON files are easy to read and + understand)
+ * dev A and dev B can now get latest JSON files from the DEV (or MAIN or MASTER) branch : these JSON + files contain both modifications from dev A and dev B
+ * dev A and dev B can import these JSON files inside QxEntityEditor application using the new + 'QxEESourceControlImport' import plugin
+ - These 2 new plugins can be executed using command line (like all other QxEntityEditor plugins), + here are 2 examples :
+ * Export : QxEntityEditor --no_gui --project="C:\Temp\qxBlog.qxee" --plugin=QxEESourceControlExport + --QxEESourceControlExport_path="C:\Temp\source_control\"
+ * Import : QxEntityEditor --no_gui --project="C:\Temp\qxBlog.qxee" --plugin=QxEESourceControlImport + --QxEESourceControlImport_path="C:\Temp\source_control\qxBlog.qxee.export.json"
+
+ +

Changes in version QxEntityEditor 1.2.7:

+
+ - Fix an issue with MySQL database schema import process when MySQL server is configured to answer + with column names in UPPERCASE (may fix other imports depending on specific database + configuration)
+
+ +

Changes in version QxEntityEditor 1.2.6:

+
+ - Support PIMPL (private implementation or d-pointer) idiom in the C++ export plugin
+ - Documentation about PIMPL idiom for persistent classes : + https://www.qxorm.com/qxorm_en/manual_qxee.html#cpp_export_settings_parameters
+ - Fix import database schema for PostgreSQL version 12 and +
+ - Fix some assertions on macOS and linux versions due to libavoid library compiled without NDEBUG + compilation option (should improve performance too)
+ - Add CMake 'target_precompile_headers' command for generated CMakeLists.txt files to support + precompiled headers building with CMake (reduce compilation times)
+
+ +

Changes in version QxEntityEditor 1.2.5:

+
+ - Fix an issue with fonts on macOS Catalina 10.15
+ - Add command line parameter --font : define application font with syntax + <family>||<pointSize>||<weight>||<italic> (only <family> is required), + for example : Courier New||14
+ - Add command line parameter --style_sheet : define application style sheet (more details here : + https://doc.qt.io/qt-5/stylesheet-reference.html), for example : QWidget { background-color: black + }
+ - Fix meta-data (property bag) C++ export : keep same order between several C++ exports (this is now + easier to check differences between 2 C++ exports using WinMerge or any other comparison/diff + tool)
+
+ +

Changes in version QxEntityEditor 1.2.4:

+
+ - New feature in Javascript engine to customize exports : include QxRestApi module to query *.qxee + project file
+ - Fix a property/relation sorting issue in C++ export after importing a database schema (which could + be annoying to make some C++ files diffs between 2 exports)
+ - Fix a crash which could occurred sometimes importing a new table on an existing schema
+
+ +

Changes in version QxEntityEditor 1.2.3:

+
+ - Fix a crash which appears sometimes with complex database schema to draw relationships (orthogonal + way)
+ - Improve QxEntityEditor command line parameters : possibility to import/export without using GUI + (useful to manage a Jenkins server for example)
+ - For more details about command line parameters, go to QxEntityEditor documentation : + https://www.qxorm.com/qxorm_en/manual_qxee.html#qxee_command_line
+
+ +

Changes in version QxEntityEditor 1.2.2:

+
+ - Fix an issue after importing a project (from database or JSON file) which forced user to refresh + or reload current project
+ - Improve performance (fetching less data from database) when loading relationships from generated + persistent classes (bLoadFromDatabase parameter)
+ - Change model/view export plugin to take into account some improvments available in the new version + of QxOrm library
+ - Support changes of new QxOrm version : remove boost dependency by default and enable C++11 + features
+ - Improve Javascript engine to customize exports : add 3 functions available in js script to get all + QxEntityEditor settings (at global level, project level and plugin level)
+ - Check entities schema before exporting to C++ project : if a design error is detected, then + display a message to user
+ - Fix SQL type field in property settings : now you can put parenthesis (for example VARCHAR(255) is + now allowed)
+ - DDL export for MySQL (and MariaDB) : add ` character to escape column name and table name
+ - Add full path to project in recent projects list and main window title bar
+ - Now it is easier to select a relationship from entities diagram with a simple click on it
+
+ +

Changes in version QxEntityEditor 1.2.1:

+
+ - Support CMake : each C++ project generated by QxEntityEditor (persistent classes, services, + model/view) provide a CMakeLists.txt file to build with CMake
+ - New online QxEntityEditor manual (user guide) available at : + https://www.qxorm.com/qxorm_en/manual_qxee.html
+ - Improve Javascript engine to customize export generated files : add a parameter named + 'output_location' to know where generated files are located + add functions to get a list of all + entities/enums of a project (see ./samples/custom_script.js file for more details)
+ - Improve database import process (SQLite, MySQL/MariaDB, PostgreSQL, Oracle and MSSQLServer) : fix + an issue importing composite foreign keys + foreign keys embedded in primary key ==> so it is now + possible to import more complex database schema
+ - Improve DDL database schema export process : fix an issue with 1-1 relationship + manage composite + keys
+ - New menu "Naming convention" to provide a fast way to rename all entities/properties/enums + (without breaking mapping to database) : support snake_case, camelCase and PascalCase (or upper + camel case), this new menu can be useful after an import from database process for example
+ - Each screen of QxEntityEditor provides now a fast access to the online manual (user guide) in its + associated topic (new button "Documentation" + shortcut pressing F1 key everywhere)
+ - New buttons undo/redo in the main QxEntityEditor toolbar to undo or redo actions done on entities, + enumerations, comments, layout (undo/redo feature can be disabled to improve performance on large + projects)
+ - Support _QX_UNITY_BUILD compilation option to reduce compilation times of generated C++ projects + (recommended with CMake which doesn't support natively precompiled headers)
+ - Fix an issue importing a relationship where target entity doesn't have a primary key
+ - Fix an issue with C++ services export plugin and JSON serialization : "Unable to create nude + pointer for input parameter"
+ - Fix an issue with abstract entities and C++ model/view export plugin and C++ services export + plugin
+ - Possibility to put hexadecimal values to define an enumeration
+ - New Javascript sample file in directory ./samples/ named q_property.js to show how to add + automatically Q_PROPERTY definition for each property generated by QxEntityEditor
+
+ +

Changes in version QxEntityEditor 1.1.9:

+
+ - New import plugin to connect to MySQL or MariaDB database without having to deal with ODBC + settings
+ - New import plugin to connect to PostgreSQL database without having to deal with ODBC settings
+ - New import plugin to load a QxEntityEditor project from a JSON file
+ - Fix SQLite import process to manage composite keys
+ - Improve Javascript engine to customize export process : new types available by script to manage + files and directories + possibility to get/set environment variables (read custom_script.js file in + ./samples/ directory for script examples)
+ - Improve Javascript engine to customize export process : new events/actions available by script : + PLUGIN_EXPORT_START, PLUGIN_EXPORT_END, AFTER_CLOSING_FILE
+ - New message box displayed if directory doesn't exist when starting an export process (to create it + automatically)
+ - Fix an issue with the "Tag project state" function (project historic) : each tag double the size + of a *.qxee project file (now each tag is optimized)
+ - Fix C++ services export process when C++11 features are enabled in QxOrm.pri configuration + file
+ - Possibility to export a *.qxee project file to a JSON text file (can be useful to store a text + representation in a source control, like Perforce, VSS, CVS, Git, etc...)
+ - Possibility to use an environment variable to define QxOrm library location (using the same syntax + as qmake, for example $$(QXORM_DIR))
+
+ +

Changes in version QxEntityEditor 1.1.8:

+
+ - Improve import plugins : reduce import process time : now, you can import hundred of entities in + few seconds into a QxEntityEditor project
+ - Relationship n-1 : possibility to define a database column name different than the relationship + name
+ - New file qxBlogExec.zip in the ./samples/ directory of QxEntityEditor package : this is a C++/Qt + example project which depends on the qxBlog.qxee generated files
+ - Improve import by ODBC plugin screen : new schema/namespace level in the list of tables/views + treeview
+ - Fix a performance issue to load large diagram with new style to draw relationships : you can now + load quickly a project with hundred of entities
+ - Add new C++11 types to manage relationships, decoration, collection (std::shared_ptr, + std::unordered_map and std::unordered_set) : C++11 features must be enabled in QxOrm.pri config file + to use these classes
+ - Import process more permissive : possibility to import tables without primary key and tables + without column
+
+ +

Changes in version QxEntityEditor 1.1.7:

+
+ - New Navigator window (under project treeview) : useful to navigate over large diagram
+ - New way to draw relationships (orthogonal lines between 2 entities) + display the relationship + type on each side (there is an option to use the old drawing style from previous version)
+ - Possibility to define a background color by namespace : useful to group all entities in the + diagram associated to a same namespace
+ - New feature to customize entities/enumerations/notes colors at several levels
+ - Define items colors at project level (menu Tools >> Project settings >> Colors + tab)
+ - Define items colors at namespace level (right-click on the diagram >> Define colors by + namespace)
+ - Define colors at item level : right-click on an item (entity, enumeration or comment) >> + Define item colors
+ - New action to organize automatically the diagram layout, useful after an import process for + example (menu View >> Organize diagram layout)
+ - Improve the DDL SQL export plugin : new option to export relationships as foreign keys constraints + in database
+ - Support the new compilation option _QX_NO_PRECOMPILED_HEADER of QxOrm library (workaround for a + known bug of recent versions of MinGW on Windows and large precompiled header)
+ - Import database by ODBC plugin : fix the import from MS SQL Server database when tables are not + located in the default schema (dbo)
+ - QxEntityEditor Mac OS X version : fix an issue to load the QxEEPrinter plugin
+ - Export plugin to C++ model/view project : new option to generate models based on the new QxOrm + library class qx::QxModelService<T, S> (models based on services to execute client-server + requests)
+
+ +

Changes in version QxEntityEditor 1.1.6:

+
+ - New javascript engine to customize the C++ and DDL SQL export process writing your own custom + script
+ - Integrated debugger to debug your own custom javascript files (for example, putting a breakpoint + or logging some traces)
+ - New plugin to print the entities diagram as a PNG image file and PDF file
+ - New property parameter UNIQUE (in property params window) used by the DDL SQL generator to create + the database schema
+ - Improve nested models in QxModelView module to be able to use several relationships levels in + QML
+ - Possibility to change the order in the list of properties and list of relationships of an + entity
+ - Change encoding of generated files : now files are UTF-8
+ - Possibility to put a relative path to the QxEntityEditor project file (*.qxee file) in each plugin + location settings
+
+ +

Changes in version QxEntityEditor 1.1.5:

+
+ - New C++ model/view export plugin to manage complex data structure to work with relationships in + QML views and Qt model/view architecture (using QxModelView module of QxOrm library)
+ - Now, with this new export plugin, working on QML with C++ entities has never been so easy !
+ - New function, menu "Tools >> Plugins scripts", to define your own custom scripts + before/after a plugin execution
+ - New command line parameter --log_sql to trace all SQL queries executed by QxEntityEditor : a + QxEntityEditor project file (*.qxee) is just a SQLite database, so it's easy to write your own + script to customize some default behaviour
+ - New option in the C++ export plugin to generate or not the custom directory with all custom files + for each entity
+ - Scrollbar available in the entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.4:

+
+ - Improve import by ODBC plugin to manage relationship, schema and composite key for SQLite, MySQL, + PostgreSQL, Oracle and MS SQL Server databases
+ - New import from SQLite plugin to import SQLite database structure into QxEntityEditor project + without having to create an ODBC DSN connexion
+ - Improve C++ export plugin : add a set of useful methods in generated classes + option to manage + relative path to QxOrm library
+ - New menu to rename a namespace (move all entities to another namespace) and delete a list of + entities by namespace
+ - Fix a bug when executing QxEntityEditor in command line (no GUI)
+ - Add a viewer mode to open a QxEntityEditor project with unlimited entities count without having a + license key (read-only mode)
+
+ +

Changes in version QxEntityEditor 1.1.3 (first official release):

+
+ - New plugin to transfer your data model over network and create quickly client/server applications, + using QxService module
+ - New options to define entity, enum and comment width in entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.2 (BETA):

+
+ - New plugin to generate DDL SQL script (database schema) for SQLite, MySQL, PostgreSQL, Oracle and + MS SQL Server databases
+ - The new DDL SQL plugin manages automatically schema evolution for each project version (ALTER + TABLE, ADD COLUMN, DROP INDEX, etc.)
+ - Add post-it or comments in the entities viewer
+ - Option to display or not property type in the entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.1 (BETA):

+
+ - First BETA version of QxEntityEditor application
+ - Provide a graphic way to manage the data model for QxOrm library
+ - Multi-platform (available for Windows, Linux and Mac OS X) and generate native code for all + environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android, iOS, Windows Phone, + Raspberry Pi, etc.)
+ - Based on plugins and provides many ways to import/export the data model
+ - Generate C++ persistent classes automatically (registered in QxOrm context)
+
+

+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/download_details.php b/doc/qxorm_en/download_details.php new file mode 100644 index 0000000..9ef1611 --- /dev/null +++ b/doc/qxorm_en/download_details.php @@ -0,0 +1,161 @@ + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor (data model designer and source code generator) + + + + + + + + + + + + + + + + +
QxOrm + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) +
+ +
+
+ Manual (2) +
+ +
+
ForumOur customers
+
+ + + + + + + + + + +
QxOrm >> Download details + + + + + + + + + +
Current version : QxOrm 1.5.0 - QxOrm library online class documentation - GitHub
QxEntityEditor 1.2.8
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + +
QxOrm library is available with full source code and can be used free of charge under the terms of the GNU General Public License (GPL) version 3. +

+ From Wikipedia : The GNU General Public License (GNU GPL or GPL) is the most widely used free software license, which guarantees end users (individuals, organizations, companies) the freedoms to use, study, share (copy), and modify the software. Software that ensures that these rights are retained is called free software. The GPL grants the recipients of a computer program the rights of the Free Software Definition and uses copyleft to ensure the freedoms are preserved whenever the work is distributed, even when the work is changed or added to. The GPL is a copyleft license, which means that derived works can only be distributed under the same license terms. +

+ If the GPLv3 license is too restrictive for your project, you can purchase the QxOrm Proprietary License (QXPL). Additional benefits of the QxOrm Proprietary License include : +
    +
  • Application source code stays private ;
  • +
  • High compatibility with different commercial and open-source licenses ;
  • +
  • Possibility to use QxOrm without delivering the full source of the library code to end users ;
  • +
  • Possibility to keep own modifications to QxOrm private ;
  • +
  • Possibility to create products without mentioning QxOrm to the end users ;
  • +
  • Protection against reverse engineering of the product.
  • +
+
qt_ambassador
+ QxOrm library has been accepted into the Qt Ambassador Program +
+ The QxOrm QXPL license is a per project (or per application) license, no matter developers count working on the project, and no matter deployed instances count of your software (royalty-free). + For example, if you develop 3 differents applications based on QxOrm library, then you have to purchase 3 differents QXPL licenses (one per project).
+
+ Price of a QxOrm Proprietary License : 400€.
+
+ If you have any questions, or if you want to purchase the QXPL license, please contact us using this e-mail : ic-east.com.
+
+ Download QxOrm 1.5.0 +
+ +
+
+

+ + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + diff --git a/doc/qxorm_en/faq.html b/doc/qxorm_en/faq.html new file mode 100644 index 0000000..934ece5 --- /dev/null +++ b/doc/qxorm_en/faq.html @@ -0,0 +1,3606 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Faq + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+ + qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ What is QxOrm ?

+ + + + + + + + + +
+ QxOrm is a C++ library designed to provide Object Relational Mapping (ORM) feature to C++ + users.
+ QxOrm is developed by XDL Team, a software development engineer since 2003.
+
+ QxOrm provides many functionalities starting from a simple C++ setting function by class + : +
    +
  • + persistence + : communication with databases (support 1-1, 1-n, n-1 and n-n + relationships) +
  • +
  • + serialization + : binary, XML and JSON format +
  • +
  • + reflection + (or + introspection + ) : access to classes definitions, retrieve properties and call classes methods +
  • +
+
+
+ What is QxEntityEditor ?

+ + + + + + + + + +
+ QxEntityEditor is a graphic editor for QxOrm library : QxEntityEditor provides a + graphic way to manage the data model.
+ QxEntityEditor is multi-platform (available for Windows, Linux and Mac OS X) and generates + native code for all environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android, + iOS, Windows Phone, Raspberry Pi, etc.).
+ A presentation video of QxEntityEditor application is + available.
+
+ QxEntityEditor is based on plugins and provides many ways to import/export your data model : +
    +
  • generate C++ persistent classes automatically (registered in QxOrm context) ;
  • +
  • generate DDL SQL script automatically (database schema) for SQLite, MySQL, PostgreSQL, Oracle + and MS SQL Server ;
  • +
  • manage schema evolution for each project version (ALTER TABLE, ADD COLUMN, DROP + INDEX, etc.) ;
  • +
  • transfer your data model over network and create quickly client/server applications, using QxService module ;
  • +
  • import existing database structure (using ODBC connection) for SQLite, MySQL, PostgreSQL, Oracle + and MS SQL Server databases ;
  • +
  • because each project is different, QxEntityEditor provides several ways to customize generated + files (especially a javascript engine and an integrated debugger).
  • +
+ QxEntityEditor +

+ QxEntityEditor is developed by XDL Team, a software development engineer since 2003.
+

+
+
+ How to contact QxOrm to report a bug or ask a question ?

+ + + + + + + + + +
+ If you find a bug or if you have a question about QxOrm library, you can send an e-mail to : + support@qxorm.com.
+ A forum dedicated to QxOrm is available here. +
+

+ How to install and build QxOrm library ?

+ + + + + + + + + +
+ A tutorial to install a development environment with QxOrm library on + Windows is available.
+
+ QxOrm uses qmake process from Qt library to create makefile and build the + project.
+ qmake is portable and multi-platform, so it works perfectly on Windows, Linux (Unix) and + Mac.
+ To build QxOrm library, just execute following commands :
+ qmake
+ make debug
+ make release
+
+ On Windows, *.vcproj and *.sln files are available for Visual C++ 2008, + Visual C++ 2010 and Visual C++ 2012.
+ *.pro files are readable by Qt Creator, and some plugins are available to interface to + other C++ IDE.
+ mingw_build_all_debug.bat and mingw_build_all_release.bat scripts in the directory + ./tools/ can quickly built QxOrm library and all tests with MinGW compiler on + Windows.
+ gcc_build_all_debug.sh and gcc_build_all_release.sh scripts in the directory + ./tools/ can quickly built QxOrm library and all tests with GCC compiler on + Linux.
+ osx_build_all_debug.sh and osx_build_all_release.sh scripts in the directory + ./tools/ can quickly built QxOrm library and all tests on Mac (thanks very much to + Dominique Billet).
+
+ Note : depending on your development environment, it may be necessary to modify + QxOrm.pri file to set boost package configuration :
+ QX_BOOST_INCLUDE_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/include)
+ QX_BOOST_LIB_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/lib_shared)
+ QX_BOOST_LIB_SERIALIZATION_DEBUG = "boost_serialization-vc90-mt-gd-1_42"
+ QX_BOOST_LIB_SERIALIZATION_RELEASE = "boost_serialization-vc90-mt-1_42"
+
+

+ What are the databases supported by QxOrm ?

+ + + + + + + + + +
+ QxOrm uses the engine QtSql of Qt based on a system of plug-in.
+ A detailed list of supported databases is available on the website of Qt here.
The plug-in ODBC + (QODBC) ensures compatibility with many databases.
For optimal performances, it is possible + to use a plug-in specific to a database : +
    +
  • QMYSQL : MySQL +
  • +
  • QPSQL : PostgreSQL (versions 7.3 and above) +
  • +
  • QOCI : Oracle Call Interfaces Driver +
  • +
  • QSQLITE : SQLite version 3 +
  • +
  • QDB2 : IBM DB2 (version 7.1 and above) +
  • +
  • QIBASE : Borland InterBase +
  • +
  • QTDS : Sybase Adaptive Server +
  • +
+
+
+ Why QxOrm is dependent on two libraries : boost and Qt ?

+ + + + + + + + + +
+ QxOrm uses many functionalities available in excellent libraries : boost and + Qt.
+ In addition, these two libraries are used in many projects both professional and open source.
+ A large number of forums, tutorials, and a whole community are available to answer any issue that + could arise.
+ The QxOrm objective is not to redevelop features that already exist but to provide a powerful + tool for access to databases such as it exists in other languages (Java with Hibernate, + .Net with NHibernate, Ruby, Python, etc...).

+ + + + + + + + + +
QtQt : cross-platform application development framework : GUI + (QtGui), network (QtNetwork), XML (QtXml), database (QtSql)...
+ Qt provides excellent support and documentation. Using Qt, you can write simple and powerful + C++ code.
+ Qt is produced by Digia's Qt Development Frameworks division and is available under LGPL + license.
+ QxOrm is compatible with many Qt's objects : QObject, QString, QDate, QTime, QDateTime, + QList, QHash, QSharedPointer, QScopedPointer...
+ It is recommended to install the latest version of Qt available at the following address : http://www.qt.io/
+

+ + + + + + + + + +
boostboost : many of boost's founders are on the C++ standard committee + and several boost libraries have been accepted for incorporation into C++1x (new standard for + the C++ programming language). + The boost's libraries are aimed at a wide range of C++ users and application domains.
+ QxOrm uses the following boost's features (header files *.hpp only, boost + serialization dependency is optional) : smart_pointer, type_traits, + multi_index_container, unordered_container, any, tuple, foreach, function.
+ It is recommended to get the latest version of boost available at the following address : http://www.boost.org/ +
+
+

+ Why does QxOrm require a precompiled header to be used ?

+ + + + + + + + + +
+ QxOrm uses the techniques of C++ meta-programming to provide most of its + functionalities.
+ You do not need to know how to use meta-programming to work with QxOrm library.
+ Indeed, QxOrm is simple to use and the C++ code written with Qt and QxOrm is easy to read, therefore + easy to develop and to maintain.

+ However, meta-programming is costly in compilation times.
+ By using a precompiled.h file, your project will be compiled much more quickly.
+ Last but not least, another advantage is that the file QxOrm.h includes the basic + functionalities of libraries boost and Qt.
+ It is thus not necessary anymore to write #include <QtCore/QString.h> to use the class + QString of Qt for example.
+ In the same way, there is no need anymore to write #include <boost/shared_ptr.hpp> to use + smart pointers of boost library. +
+

+ Is it possible to reduce compilation times of my project ?

+ + + + + + + + + +
+ Yes, if the serialization of your data in XML format is not used in your project, you + can disable this functionality.
+ The compilation times will be then reduced but you will not have anymore access to the namespace + qx::serialization:xml.
+ To disable XML serialization, it is necessary to open the QxOrm.pri config file and to + remove (or comment) the compilation option _QX_ENABLE_BOOST_SERIALIZATION_XML.
+ A recompilation of QxOrm library is necessary to take into account this modification.
+
+ Another possibility is to use the polymorphic classes of the library boost::serialization (instead of template).
+ This feature reduces compilation times and the size of the executable that is generated.
+ However, the speed of execution of your program will be reduced since part of the work carried out + during compilation will be done during the execution of your application.
+ To use this feature with QxOrm, you must enable the compilation option + _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC in the QxOrm.pri config file.
+ Warning : the serialization functions will be then accessible from the following + namespace : qx::serialization::polymorphic_binary, + qx::serialization::polymorphic_text and qx::serialization::polymorphic_xml.
+ A recompilation of QxOrm library is necessary to take into account this modification.
+
+ It is also possible to use Q_PROPERTY macro to define properties for a class inherited from + QObject type.
+ In this case, there is two different ways to register properties in QxOrm context and you can reduce + noticeably compilation times of your project.
+ For more details about this feature, click here.
+
+ Note : it is important to check if all optimizations provided by the compiler are enabled, for + example to compile using several processors : +
    +
  • MSVC++ : use environment variable SET CL=/MP
  • +
  • GCC and Clang : put processors count as parameter to the make process, for + example to use 8 processors : SET MAKE_COMMAND=make -j8
  • +
+
+

+ What are all types of serialization available ?

+ + + + + + + + + +
+ QxOrm is based on boost + serialization library.
+ There are several types of serialization available : binary, XML, text, etc...
+ QxOrm.pri config file can enable and/or disable some types of serialization.
+
+ Each type of serialization has its own characteristics :
+ * binary : smallest, fastest, non-portable
+ * text : larger, slower, portable
+ * XML : largest, slowest, portable
+
+ Note : binary type is not portable, so you can't transfer data between Windows and Unix + for example.
+ If you need to transfer data over network between different platforms, you have to use text or + XML serialization.
+ QxOrm provides another solution : portable_binary serialization.
+ portable_binary has the same characteristics as binary type and can serialize data in a + portable way.
+ However, portable_binary is not provided officially by boost library, so it's necessary + to test before using in a production software. +
+

+ Why does QxOrm provide a new type of container qx::QxCollection<Key, + Value> ?

+ + + + + + + + + +
+ There are many containers in stl, boost and Qt libraries.
+ It is therefore legitimate to ask this question : what is qx::QxCollection<Key, Value> + ?
+ qx::QxCollection<Key, + Value> is a new container (based on the excellent library boost::multi_index_container) which has the following functionalities : +
    +
  • preserves the insertion order of elements in the list +
  • +
  • quick access to an element by its index : is equivalent to std::vector<T> or + QList<T> for example +
  • +
  • quick access to an element by a key (hash-map) : is equivalent to QHash<Key, + Value> or boost::unordered_map<Key, Value> for example +
  • +
  • sort by Key type and by Value type
  • +
+ Note : qx::QxCollection<Key, Value> is compatible with the foreach macro + provided by Qt library and the BOOST_FOREACH macro provided by boost library.
+ However, each element returned by these 2 macros corresponds to an object of type std::pair<Key, + Value>.
+ To obtain a more natural and more readable result, it is advised to use the _foreach macro : + this macro uses BOOST_FOREACH for all the containers except for qx::QxCollection<Key, + Value>.
+ In this case, the returned element corresponds to the Value type (cf. sample).
+ The macro _foreach is compatible with all containers (stl, Qt, + boost...) since it uses the macro BOOST_FOREACH.

+ + Additional note : qx::QxCollection<Key, Value> is particularly suited to receive + data resulting from a database.
Indeed, these data can be sorted (by using ORDER BY in a + sql request for example), it is thus important to preserve the insertion order of the elements in the + list.
+ Furthermore, each data resulting from a database has a unique id. It is thus important to be able to + access quickly to an element based on this single identifier (hash-map).

+ + Sample :
+ + + + + + + +
+
/* definition of drug class with 3 properties : code, name, description */
+class drug { public: QString code; QString name; QString desc; };
+
+/* smart pointer of drug */
+typedef boost::shared_ptr<drug> drug_ptr;
+
+/* collection of drugs by code */
+qx::QxCollection<QString, drug_ptr> lstDrugs;
+
+/* create 3 new drugs */
+drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1";
+drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2";
+drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3";
+
+/* insert drugs into the collection */
+lstDrugs.insert(d1->code, d1);
+lstDrugs.insert(d2->code, d2);
+lstDrugs.insert(d3->code, d3);
+
+/* iterate with '_foreach' keyword */
+_foreach(drug_ptr p, lstDrugs)
+{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); }
+
+/* iterate with 'for' keyword */
+for (long l = 0; l < lstDrugs.count(); ++l)
+{
+   drug_ptr p = lstDrugs.getByIndex(l);
+   QString code = lstDrugs.getKeyByIndex(l);
+   qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc);
+}
+
+/* iterate with 'QxCollectionIterator' java style */
+qx::QxCollectionIterator<QString, drug_ptr> itr(lstDrugs);
+while (itr.next())
+{
+   QString code = itr.key();
+   qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc);
+}
+
+/* sort ascending by key and sort descending by value */
+lstDrugs.sortByKey(true);
+lstDrugs.sortByValue(false);
+
+/* access drug by code */
+drug_ptr p = lstDrugs.getByKey("code2");
+
+/* access drug by index */
+drug_ptr p = lstDrugs.getByIndex(2);
+
+/* test if drug exists and if collection is empty */
+bool bExist = lstDrugs.exist("code3");
+bool bEmpty = lstDrugs.empty();
+
+/* remove the second drug from collection */
+lstDrugs.removeByIndex(2);
+
+/* remove the drug with "code3" */
+lstDrugs.removeByKey("code3");
+
+/* clear the collection */
+lstDrugs.clear();
+
+
+

+ Why does QxOrm provide a new smart-pointer qx::dao::ptr<T> + ?

+ + + + + + + + + +
+ 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::...' functions.
+ qx::dao::ptr<T> + 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<T> can also be used with the function 'qx::dao::update_optimized()' + to update in database only properties changed.
+ qx::dao::ptr<T> can be used with a simple object and with many containers : stl, + boost, Qt and qx::QxCollection<Key, Value>.
+
+ Sample :
+ + + + + + + +
+
   // Test 'isDirty()' method
+   qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(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<author_ptr> > type_lst_author_test_is_dirty;
+
+   type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+   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);
+
+
+

+ Should I use QString or std::string ?

+ + + + + + + + + +
+ QxOrm advises to use the QString class for the management of the character strings.
+ Even if boost provides many functionalities with its module boost::string_algo, the QString class is easier to use and + supports many formats : ASCII, Utf8, Utf16...
+ However, QxOrm is compatible with std::string and std::wstring if you prefer to + use this kind of character strings. +
+

+ Is it necessary to use smart-pointers ?

+ + + + + + + + + +
+ QxOrm strongly advises to use boost or Qt smart-pointers.
+ The C++ language does not have Garbage Collector like Java or C# for example.
+ The use of smart-pointers simplifies the memory management in C++.
+ The ideal in a C++ program is not to have any call to delete or delete[].
+ Furthermore, smart-pointer is a new functionality of the new C++ standard : C++1x.
+ It is thus essential to know the following classes today : + +
+

+ The primary key is long type by default. Is it possible to use a key of + QString type or other ?

+ + + + + + + + + +
+ It is possible to define a unique id of QString type or other with QxOrm library.
+ By default, the unique id is long type.
+ To indicate that a class has a single identifier of QString type or other, it is necessary to + specialize the template qx::trait::get_primary_key.
+ To simplify, you can use the macro : QX_REGISTER_PRIMARY_KEY(myClass, QString).
+
+ Warning : the macro QX_REGISTER_PRIMARY_KEY must be used before the macro + QX_REGISTER_HPP_... in the definition of your class, otherwise a compilation error + occurs.
+
+ Here is an example with author class of qxBlog tutorial and a QString primary key + :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+ 
+class author
+{
+public:
+// -- properties
+   QString  m_id;
+   QString  m_name;
+// -- constructor, virtual destructor
+   author() { ; }
+   virtual ~author() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+

+ How to define a 'multi-columns primary key' (composite key) + ?

+ + + + + + + + + +
+ QxOrm supports 'multi-columns primary key'.
+ The class id must be defined with following type :
+ * QPair or std::pair to define 2 columns
+ * boost::tuple to define from 2 columns to 9 columns
+
+ It is necessary to use the macro QX_REGISTER_PRIMARY_KEY() to specialize the template + and to map class id with multi-columns in database.
+ The list of multi-columns names must be defined with '|' character : + 'column1|column2|column3|etc...'.
+
+ Sample with class 'author' from project 'qxBlogCompositeKey', this class has an + id mapped to 3 columns in database :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+
+   QX_REGISTER_FRIEND_CLASS(author)
+
+public:
+
+// -- composite key (multi-column primary key in database)
+   typedef boost::tuple<QString, long, QString> type_composite_key;
+   static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; }
+
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+
+// -- enum
+   enum enum_sex { male, female, unknown };
+
+// -- properties
+   type_composite_key   m_id;
+   QString              m_name;
+   QDate                m_birthdate;
+   enum_sex             m_sex;
+   list_blog            m_blogX;
+
+// -- contructor, virtual destructor
+   author() : m_id("", 0, ""), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+
+// -- methods
+   int age() const;
+
+// -- methods "get" to composite key
+   type_composite_key getId() const    { return m_id; }
+   QString getId_0() const             { return boost::tuples::get<0>(m_id); }
+   long getId_1() const                { return boost::tuples::get<1>(m_id); }
+   QString getId_2() const             { return boost::tuples::get<2>(m_id); }
+
+// -- methods "set" to composite key
+   void setId_0(const QString & s)     { boost::tuples::get<0>(m_id) = s; }
+   void setId_1(long l)                { boost::tuples::get<1>(m_id) = l; }
+   void setId_2(const QString & s)     { boost::tuples::get<2>(m_id) = s; }
+
+};
+
+QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<author::type_composite_key, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/author.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, author::str_composite_key());
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key());
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+

+ How to register private or protected members into QxOrm context + ?

+ + + + + + + + + +
+ To register private or protected members into QxOrm context + (qx::register_class<T> function), it's necessary to declare some friend class.
+ To simplify writing C++ template, QxOrm library provides this macro : + QX_REGISTER_FRIEND_CLASS(myClass).
+ An example using this macro can be found in ./test/qxDllSample/dll1/ directory of QxOrm package + with CPerson class :
+
+ + + + + + + +
+
namespace qx {
+namespace test {
+
+class QX_DLL1_EXPORT CPerson : public QObject
+{
+
+   Q_OBJECT
+   QX_REGISTER_FRIEND_CLASS(qx::test::CPerson)
+
+   // etc...
+
+};
+
+} // namespace test
+} // namespace qx
+
+
+
+

+ How to enable/disable the module QxMemLeak for automatic detection of memory + leaks ?

+ + + + + + + + + +
+ QxMemLeak module provides a fast detection of memory leaks in Debug mode once the + execution of the program is finished (with indication of the file and the line => style MFC from + Microsoft).
+ This module is developed by Wu Yongwei + and has undergone some modifications to be integrated in QxOrm.
+ If another tool is already used in your projects (Valgrind for example), this functionality + should not be activated.
+ To enable/disable QxMemLeak module, all is needed is to modify the constant + _QX_USE_MEM_LEAK_DETECTION defined in the QxConfig.h. file.
+ A recompilation of QxOrm library is necessary to take into account this modification. +
+

+ How to manage inheritance and database ?

+ + + + + + + + + +
+ With ORM tools, there is usually 3 strategies to manage inheritance and database : + + QxOrm works by default with Concrete Table Inheritance strategy (others are not + supported yet).
+ Many tutorials and forums are available on internet to more details about ORM inheritance and + database.
+ You can find a sample in the directory ./test/qxDllSample/dll2/ with the class + BaseClassTrigger. +
+

+ How to define a 'Trigger' with QxOrm ?

+ + + + + + + + + +
+ With QxOrm Trigger, it is possible to execute process before and/or after an insert, + update or delete query in the database.
+ You can find a sample in the directory ./test/qxDllSample/dll2/ with the class + BaseClassTrigger.
+ The class BaseClassTrigger contains 5 properties : m_id, m_dateCreation, + m_dateModification, m_userCreation and m_userModification.
+ Each property will be automatically auto-updated for all derived classes from BaseClassTrigger + (see Foo class and Bar class in the same project).
+ It is necessary to specialize 'QxDao_Trigger' template to work with this feature.
+
+ + + + + + + +
+
#ifndef _QX_BASE_CLASS_TRIGGER_H_
+#define _QX_BASE_CLASS_TRIGGER_H_
+
+class QX_DLL2_EXPORT BaseClassTrigger
+{
+
+   QX_REGISTER_FRIEND_CLASS(BaseClassTrigger)
+
+protected:
+
+   long        m_id;
+   QDateTime   m_dateCreation;
+   QDateTime   m_dateModification;
+   QString     m_userCreation;
+   QString     m_userModification;
+
+public:
+
+   BaseClassTrigger() : m_id(0)  { ; }
+   virtual ~BaseClassTrigger()   { ; }
+
+   long getId() const                     { return m_id; }
+   QDateTime getDateCreation() const      { return m_dateCreation; }
+   QDateTime getDateModification() const  { return m_dateModification; }
+   QString getUserCreation() const        { return m_userCreation; }
+   QString getUserModification() const    { return m_userModification; }
+
+   void setId(long l)                              { m_id = l; }
+   void setDateCreation(const QDateTime & dt)      { m_dateCreation = dt; }
+   void setDateModification(const QDateTime & dt)  { m_dateModification = dt; }
+   void setUserCreation(const QString & s)         { m_userCreation = s; }
+   void setUserModification(const QString & s)     { m_userModification = s; }
+
+   void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
+   void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
+
+};
+
+QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0)
+
+namespace qx {
+namespace dao {
+namespace detail {
+
+template <>
+struct QxDao_Trigger<BaseClassTrigger>
+{
+
+   static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeInsert(dao); } }
+   static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeUpdate(dao); } }
+   static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onBeforeFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+
+};
+
+} // namespace detail
+} // namespace dao
+} // namespace qx
+
+#endif // _QX_BASE_CLASS_TRIGGER_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/BaseClassTrigger.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger)
+
+namespace qx {
+template <> void register_class(QxClass<BaseClassTrigger> & t)
+{
+   IxDataMember * pData = NULL;
+
+   pData = t.id(& BaseClassTrigger::m_id, "id");
+
+   pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation");
+   pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification");
+   pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation");
+   pData = t.data(& BaseClassTrigger::m_userModification, "user_modification");
+}}
+
+void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateCreation = QDateTime::currentDateTime();
+   m_dateModification = QDateTime::currentDateTime();
+   m_userCreation = "current_user_1";
+   m_userModification = "current_user_1";
+}
+
+void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateModification = QDateTime::currentDateTime();
+   m_userModification = "current_user_2";
+}
+
+
+
+

+ How to register an abstract class into QxOrm context ?

+ + + + + + + + + +
+ A C++ abstract class (with at least one pure virtual method) cannot be mapped to a table of a database + (because it cannot be instantiated).
+ However, in some case, it can be interesting to define properties into abstract class used by a + persistent object (by inheritance).
+ A sample of abstract class registered in QxOrm context is available in the directory + ./test/qxDllSample/dll2/ of QxOrm package with the class BaseClassTrigger.
+ To register an abstract class into QxOrm context, you have to : +
    +
  • register the class with 'void register_class' like any other class ; +
  • +
  • use macro QX_REGISTER_ABSTRACT_CLASS(className) just after the class definition. +
  • +
+
+

+ How to register a class defined into a namespace into QxOrm context + ?

+ + + + + + + + + +
+ If a class is defined into a namespace, a compilation error occurs using macros : + QX_REGISTER_HPP and QX_REGISTER_CPP.
+ To avoid this compilation error, it is necessary to use followings macros : + QX_REGISTER_COMPLEX_CLASS_NAME_HPP and QX_REGISTER_COMPLEX_CLASS_NAME_CPP.
+ You can find a sample in the directory ./test/qxDllSample/dll1/ of QxOrm package with the class + CPerson defined into namespace qx::test :
+
+ * QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0, + qx_test_CPerson) +
+

+ How to define a soft delete behavior ?

+ + + + + + + + + +
+ A soft delete doesn't remove rows from database (this is not a physical delete) : a new column is + added to the table definition to flag a row as deleted or not.
+ This column can contain a boolean (1 means row deleted, 0 or NULL means row not deleted), or can + contain deletion date-time (if empty or NULL, row is not deleted).
+ So you can reactivate a deleted row by setting NULL or empty value into database.
+
+ To define a soft delete behavior with QxOrm library, you have to use the class qx::QxSoftDelete + in function mapping by class qx::register_class<T>.
+ Here is an example with the class Bar containing 2 properties m_id and m_desc + :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<Bar> & t)
+{
+   t.setSoftDelete(qx::QxSoftDelete("deleted_at"));
+
+   t.id(& Bar::m_id, "id");
+   t.data(& Bar::m_desc, "desc");
+}}
+
+
+ SQL queries builded by QxOrm library will take into account this soft delete parameter to add + conditions (don't fetch deleted item, don't delete physically a row, etc.).
+ For example, if you execute this code with the class Bar :
+
+ + + + + + + +
+
Bar_ptr pBar; pBar.reset(new Bar());
+pBar->setId(5);
+QSqlError daoError = qx::dao::delete_by_id(pBar);     qAssert(! daoError.isValid());
+qx_bool bDaoExist = qx::dao::exist(pBar);             qAssert(! bDaoExist);
+daoError = qx::dao::delete_all<Bar>();                qAssert(! daoError.isValid());
+long lBarCount = qx::dao::count<Bar>();               qAssert(lBarCount == 0);
+daoError = qx::dao::destroy_all<Bar>();               qAssert(! daoError.isValid());
+
+
+ You will obtain following output trace :
+
+ + + + + + + +
+
[QxOrm] sql query (93 ms) : UPDATE Bar SET deleted_at = '20110617115148615' WHERE id = :id
+[QxOrm] sql query (0 ms) : SELECT Bar.id AS Bar_id_0, Bar.deleted_at FROM Bar WHERE Bar.id = :id AND (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (78 ms) : UPDATE Bar SET deleted_at = '20110617115148724'
+[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM Bar WHERE (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (110 ms) : DELETE FROM Bar
+
+
+ Note : to delete physically a row from database, you have to use followings functions : + qx::dao::destroy_by_id() and qx::dao::destroy_all().
+
+ Other note : it is recommended to define into database an index on column deleted_at to + optimize execution of SQL queries.
+
+

+ How to use a session (qx::QxSession class) to manage automatically database + transactions (using C++ RAII) ?

+ + + + + + + + + +
+ A database transaction is a sequence of operations performed as a single logical + unit of work.
+ If no errors occurred during the execution of the transaction then the system commits the + transaction.
+ If an error occurs during the transaction, or if the user specifies a rollback operation, the + data manipulations within the transaction are not persisted to the database.
+
+ The qx::QxSession + class of QxOrm library is designed to manage automatically database transactions (using C++ + RAII) :
+
+ + + + + + + +
+
{ // Start a scope where a new session is instantiated
+
+  // Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
+  qx::QxSession session;
+
+  // Execute some operations with database (using += operator of qx::QxSession class and session database connexion)
+  session += qx::dao::insert(my_object, session.database());
+  session += qx::dao::update(my_object, session.database());
+  session += qx::dao::fetch_by_id(my_object, session.database());
+  session += qx::dao::delete_by_id(my_object, session.database());
+
+  // If the session is not valid (so an error occured) => display first error
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
+
+
+ Note : a session can throw a qx::dao::sql_error exception when a SQL error occured (by + default, there is no exception). You can setup this feature using :
+ * qx::QxSession constructor (for a specific session) ;
+ * qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b) parameter (for all + sessions).
+
+ Other note : don't forget to pass the session database connexion to each qx::dao::xxx + functions (using session.database() method).
+ Moreover, you can manage your own database connexion (from a connexion pool for example) using + constructor of qx::QxSession class.
+
+ qx::QxSession class provides also persistent methods (CRUD) to make easier to write C++ + code.
+ Here is the same example using methods of qx::QxSession class instead of functions into + namespace qx::dao :
+
+ + + + + + + +
+
{ // Start a scope where a new session is instantiated
+
+  // Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
+  qx::QxSession session;
+
+  // Execute some operations with database
+  session.insert(my_object);
+  session.update(my_object);
+  session.fetchById(my_object);
+  session.deleteById(my_object);
+
+  // If the session is not valid (so an error occured) => display first error
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
+
+
+
+

+ How to persist a type without its source code (class from an external library for + example) ?

+ + + + + + + + + +
+ QxOrm library can persist every types, not only classes registered in QxOrm context using + qx::register_class<T>().
+
+ It's necessary to write serialization functions from boost framework, using the non intrusive + method (because source code is not available or is read-only). + For more details on boost serialization module, goto + official website.
+
+ For example, imagine that you have the class 'ExtObject3D' from an external library and the + source code is not available or is read-only. + Here is the code to can persist an instance of 'ExtObject3D' type into database :
+
+ + + + + + + +
+
#ifndef _PERSIST_EXTOBJECT3D_H_
+#define _PERSIST_EXTOBJECT3D_H_
+
+#include "ExtObject3D.h"
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/nvp.hpp>
+ 
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void save(Archive & ar, const ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(t.getX()), y(t.getY()), z(t.getZ()), angle(t.getAngle());
+
+   ar << boost::serialization::make_nvp("x", x);
+   ar << boost::serialization::make_nvp("y", y);
+   ar << boost::serialization::make_nvp("z", z);
+   ar << boost::serialization::make_nvp("angle", angle);
+}
+
+template <class Archive>
+void load(Archive & ar, ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(0.0), y(0.0), z(0.0), angle(0.0);
+
+   ar >> boost::serialization::make_nvp("x", x);
+   ar >> boost::serialization::make_nvp("y", y);
+   ar >> boost::serialization::make_nvp("z", z);
+   ar >> boost::serialization::make_nvp("angle", angle);
+
+   t.setX(x);
+   t.setY(y);
+   t.setZ(z);
+   t.setAngle(angle);
+}
+
+} // namespace serialization
+} // namespace boost
+ 
+BOOST_SERIALIZATION_SPLIT_FREE(ExtObject3D)
+
+#endif // _PERSIST_EXTOBJECT3D_H_
+
+
+ Now you can persist an instance of 'ExtObject3D' type into database : so you can have a + 'ExtObject3D' property in a persistent class registered in QxOrm context. + This property can be mapped with a column of type TEXT or VARCHAR into database.
+
+ The default behaviour of QxOrm library is : the instance is serialized to XML format before to be + inserted or updated into database. + This default behaviour can be useful, for example if you want to save a collection of items without to + make relation (so you don't have to manage another table into database). + For example, with a property of type std::vector<mon_objet> in a persistent class without + relation, the list of items will be saved into database under XML format.
+
+ Note : the default behaviour can be easily modified for a specific type. + QtSql engine uses QVariant type to link C++ code and database. + QVariant type can contain text, numeric, binary, etc. + So it can be interesting to specialize the default behaviour (XML serialization) if you want to save + datas under binary format or to optimize your application (XML serialization is not very fast). + You just have to write (with boost serialization functions) a conversion into/from QVariant + type, for example with 'ExtObject3D' class :
+
+ + + + + + + +
+
namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< ExtObject3D > {
+static inline QVariant toVariant(const ExtObject3D & t, const QString & format, int index)
+{ /* Ici je convertis ExtObject3D en QVariant */ } };
+
+template <> struct QxConvert_FromVariant< ExtObject3D > {
+static inline qx_bool fromVariant(const QVariant & v, ExtObject3D & t, const QString & format, int index)
+{ /* Ici je convertis QVariant en ExtObject3D */; return qx_bool(true); } };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+
+
+

+ How to use introspection engine (or reflection engine) of QxOrm library + ?

+ + + + + + + + + +
+ All classes registered in QxOrm context using qx::register_class<T>() function can be + used by introspection engine (or reflection engine) of QxOrm library. + Introspection engine can provide dynamically (so during program execution) some informations about + types. + Those informations are called meta-datas and can list all classes characteristics (properties, + methods, etc.). + Many programming languages (for example Java or C#) have natively this mechanism, but not C++, that's + why QxOrm library emulates an introspection engine.
+
+ Here is a list of QxOrm library classes to access to meta-datas : +
    +
  • qx::QxClassX : + singleton class to iterate over all classes registered in QxOrm context using + qx::register_class<T>() ; +
  • +
  • qx::IxClass : interface + for a class registered in QxOrm context ;
  • +
  • qx::IxDataMemberX : list of properties associated to a class ;
  • +
  • qx::IxDataMember : + interface for a class property ;
  • +
  • qx::IxFunctionX : + list of methods associated to a class ;
  • +
  • qx::IxFunction : + interface for a class method.
  • +
+ An instance of qx::IxClass type contains the list of class properties + (qx::IxDataMemberX) and the list of class methods (qx::IxFunctionX).
+
+ Introspection engine of QxOrm library provides : +
    +
  • to create dynamically an instance of a class using class name under string format + (qx::create()) ;
  • +
  • to access/modify dynamically the value of an object field (qx::IxDataMember::getValue() + and qx::IxDataMember::setValue()) ;
  • +
  • to invoke dynamically a class method (qx::IxFunction::invoke()) ;
  • +
  • to access to the class hierarchy (qx::IxClass::getBaseClass()).
  • +
+ Note : QxService module + of QxOrm library (click here to go to the tutorial) to + create easily a C++ application server is based on introspection engine to call dynamically services + methods (client request) on server side.
+
+ Here is a sample using introspection engine : how to dump all classes, properties and methods + registered in QxOrm context ?
+
+ + + + + + + +
+
QString QxClassX::dumpAllClasses()
+{
+   QxClassX::registerAllClasses();
+   QxCollection<QString, IxClass *> * pAllClasses = QxClassX::getAllClasses();
+   if (! pAllClasses) { qAssert(false); return ""; }
+
+   QString sDump;
+   long lCount = pAllClasses->count();
+   qDebug("[QxOrm] start dump all registered classes (%ld)", lCount);
+   _foreach(IxClass * pClass, (* pAllClasses))
+   { if (pClass) { sDump += pClass->dumpClass(); } }
+   qDebug("[QxOrm] %s", "end dump all registered classes");
+
+   return sDump;
+}
+
+QString IxClass::dumpClass() const
+{
+   QString sDump;
+   sDump += "-- class '" + m_sKey + "' (name '" + m_sName + "', ";
+   sDump += "description '" + m_sDescription + "', version '" + QString::number(m_lVersion) + "', ";
+   sDump += "base class '" + (getBaseClass() ? getBaseClass()->getKey() : "") + "')\n";
+
+   long lCount = (m_pDataMemberX ? m_pDataMemberX->count() : 0);
+   sDump += "\t* list of registered properties (" + QString::number(lCount) + ")\n";
+   if (m_pDataMemberX)
+   {
+      IxDataMember * pId = this->getId();
+      for (long l = 0; l < lCount; l++)
+      {
+         IxDataMember * p = m_pDataMemberX->get(l); if (! p) { continue; }
+         IxSqlRelation * pRelation = p->getSqlRelation();
+         QString sInfos = p->getKey() + ((p == pId) ? QString(" (id)") : QString());
+         sInfos += (pRelation ? (QString(" (") + pRelation->getDescription() + QString(")")) : QString());
+         sDump += "\t\t" + sInfos + "\n";
+      }
+   }
+
+   lCount = (m_pFctMemberX ? m_pFctMemberX->count() : 0);
+   sDump += "\t* list of registered functions (" + QString::number(lCount) + ")\n";
+   if (m_pFctMemberX)
+   {
+      _foreach_if(IxFunction_ptr p, (* m_pFctMemberX), (p))
+      { QString sKey = p->getKey(); sDump += "\t\t" + sKey + "\n"; }
+   }
+
+   qDebug("%s", qPrintable(sDump));
+   return sDump;
+}
+
+
+ Using the function qx::QxClassX::dumpAllClasses() with qxBlog tutorial, you will obtain following output :
+
+ + + + + + + +
+
[QxOrm] start dump all registered classes (4)
+-- class 'author' (name 'author', description '', version '0', base class '')
+	* list of registered properties (5)
+		author_id (id)
+		name
+		birthdate
+		sex
+		list_blog (relation one-to-many)
+	* list of registered functions (1)
+		age
+
+-- class 'blog' (name 'blog', description '', version '0', base class '')
+	* list of registered properties (6)
+		blog_id (id)
+		blog_text
+		date_creation
+		author_id (relation many-to-one)
+		list_comment (relation one-to-many)
+		list_category (relation many-to-many)
+	* list of registered functions (0)
+
+-- class 'comment' (name 'comment', description '', version '0', base class '')
+	* list of registered properties (4)
+		comment_id (id)
+		comment_text
+		date_creation
+		blog_id (relation many-to-one)
+	* list of registered functions (0)
+
+-- class 'category' (name 'category', description '', version '0', base class '')
+	* list of registered properties (4)
+		category_id (id)
+		name
+		description
+		list_blog (relation many-to-many)
+	* list of registered functions (0)
+
+[QxOrm] end dump all registered classes
+
+
+ Note : you can add some informations to introspection engine using property bag + mechanism. + Indeed, qx::IxClass, qx::IxDataMember and qx::IxFunction classes contain a list + of QVariant items associated to a QString key (see qx::QxPropertyBag class for + more details).
+
+
+

+ How to register automatically Qt meta-properties (using Q_PROPERTY macro) to + QxOrm context ?

+ + + + + + + + + +
+ All classes inherited from QObject type can use Q_PROPERTY macro : + those properties become meta-properties. + This is how Qt framework provides an introspection engine using the moc process. + Meta-properties can be used for example by QML engine, QtScript, etc.
+
+ QxOrm library needs to register each properties per class in the mapping function void + qx::register_class<T>() to provide all features (persistence, XML and binary + serialization, etc.). + It's possible to register automatically all Qt meta-properties into QxOrm context without to manage + any mapping function per class void qx::register_class<T>() : + QX_REGISTER_ALL_QT_PROPERTIES() macro works with Qt introspection engine to iterate over all + meta-properties.
+
+ Here is an example with TestQtProperty class into ./test/qxDllSample/dll1/include/ + directory of QxOrm package :
+
+ + + + + + + +
+
#ifndef _QX_TEST_QT_META_PROPERTY_H_
+#define _QX_TEST_QT_META_PROPERTY_H_
+ 
+class QX_DLL1_EXPORT TestQtProperty : public QObject
+{
+
+   Q_OBJECT
+   Q_PROPERTY(int id READ id WRITE setId)
+   Q_PROPERTY(long number READ number WRITE setNumber)
+   Q_PROPERTY(QString desc READ desc WRITE setDesc)
+   Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate)
+   Q_PROPERTY(QVariant photo READ photo WRITE setPhoto)
+
+protected:
+
+   int         m_id;
+   long        m_number;
+   QString     m_desc;
+   QDateTime   m_birthDate;
+   QVariant    m_photo;
+
+public:
+
+   TestQtProperty() : QObject(), m_id(0), m_number(0) { ; }
+   virtual ~TestQtProperty() { ; }
+
+   int id() const                { return m_id; }
+   long number() const           { return m_number; }
+   QString desc() const          { return m_desc; }
+   QDateTime birthDate() const   { return m_birthDate; }
+   QVariant photo() const        { return m_photo; }
+
+   void setId(int i)                         { m_id = i; }
+   void setNumber(long l)                    { m_number = l; }
+   void setDesc(const QString & s)           { m_desc = s; }
+   void setBirthDate(const QDateTime & dt)   { m_birthDate = dt; }
+   void setPhoto(const QVariant & v)         { m_photo = v; }
+ 
+};
+
+QX_REGISTER_HPP_QX_DLL1(TestQtProperty, QObject, 0)
+
+#endif // _QX_TEST_QT_META_PROPERTY_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/TestQtProperty.h"
+
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_QX_DLL1(TestQtProperty)
+QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id")
+
+
+ If you don't want to use QX_REGISTER_ALL_QT_PROPERTIES macro, you can write 4 lines of code + :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<TestQtProperty> & t)
+{ qx::register_all_qt_properties<TestQtProperty>(t, "id"); }
+} // namespace qx
+
+
+ Note : the second parameter of QX_REGISTER_ALL_QT_PROPERTIES macro is the name of the + property mapped to the primary key into database. + If this parameter is empty, then the class doesn't have any primary key or the primary key has been + registered in a base class.
+
+ All properties defined with Q_PROPERTY macro can be registered in QxOrm context in two + different ways :
+ 1- with the classic method : t.data(& MyQObject::my_property, "my_property", 0);
+ 2- or without writing the data-member pointer : t.data("my_property", 0);
+
+ You can use the first or the second method to register your properties into QxOrm context and access + to the same functionalities using the common interface qx::IxDataMember. + You can also mix Qt meta-properties and classic registration data-member into the same mapping + function void qx::register_class<T>(). + Each registration method has some advantages and disadvantages.
+
+ Here is the list of advantages using the second registration method into QxOrm context : +
    +
  • much more faster to compile ;
  • +
  • reduce exec size ;
  • +
  • strong integration with Qt introspection/moc engine ;
  • +
  • no need to manage any mapping function per class using QX_REGISTER_ALL_QT_PROPERTIES + macro.
  • +
+ Here is the list of disadvantages compared to the classic registration method : +
    +
  • need to inherit from QObject class to use Q_PROPERTY macro ;
  • +
  • program execution more slower (QVariant type versus C++ template) ;
  • +
  • doesn't support relation between tables into database (one-to-one, one-to-many, + many-to-one and many-to-many) ; +
  • +
  • cannot access to the data-member pointer of a class (need to convert to QVariant type + before to access or to modify a value).
  • +
+
+

+ How to build a query without writing SQL with the class qx::QxSqlQuery + ?

+ + + + + + + + + +
+ The class qx::QxSqlQuery (or its typedef qx_query) is used to communicate + with database (to filter, to sort, etc.) in two different ways : +
    +
  • writing manually SQL query ;
  • +
  • using C++ methods with a syntax similar to SQL (same concept than the great library SubSonic for .Net). +
  • +
+ With the first method (writing manually SQL query), you can use some optimizations specific for each + database.
+ The second method (using C++ code to build SQL query) binds automatically SQL parameters without using + qx::QxSqlQuery::bind() function.
+
+ Here is an example with qx::QxSqlQuery class writing manually a SQL query :
+
+ + + + + + + +
+
// Build a SQL query to fetch only 'author' of type 'female'
+qx::QxSqlQuery query("WHERE author.sex = :sex");
+query.bind(":sex", author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* here we can work with the collection provided by database */ }
+
+
+ QxOrm library provides 3 styles to write SQL parameters.
+ This style can be modified for a project using the following method + qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle() :
+
    +
  • ph_style_2_point_name : "WHERE author.sex = :sex" (default style) ;
  • +
  • ph_style_at_name : "WHERE author.sex = @sex" ;
  • +
  • ph_style_question_mark : "WHERE author.sex = ?".
  • +
+ Here is the same example using C++ code of the class qx::QxSqlQuery (or its typedef + qx_query) to build query automatically :
+
+ + + + + + + +
+
// Build a SQL query to fetch only 'author' of type 'female'
+qx_query query;
+query.where("author.sex").isEqualTo(author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* here we can work with the collection provided by database */ }
+
+
+ With C++ methods of qx::QxSqlQuery class, you don't have to bind any SQL parameter, and the + syntax is similar to real SQL.
+ All SQL parameters will be provided to database automatically with the following style : + qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle().
+
+ Here is an example with many methods of qx::QxSqlQuery class (or its typedef qx_query) + :
+
+ + + + + + + +
+
qx_query query;
+query.where("sex").isEqualTo(author::female)
+     .and_("age").isGreaterThan(38)
+     .or_("last_name").isNotEqualTo("Dupont")
+     .or_("first_name").like("Alfred")
+     .and_OpenParenthesis("id").isLessThanOrEqualTo(999)
+     .and_("birth_date").isBetween(date1, date2)
+     .closeParenthesis()
+     .or_("id").in(50, 999, 11, 23, 78945)
+     .and_("is_deleted").isNotNull()
+     .orderAsc("last_name", "first_name", "sex")
+     .limit(50, 150);
+
+
+ This code will produce following SQL for MySQL, PostgreSQL and SQLite databases + (for Oracle and SQLServer, there is a specific process for limit() method) :
+
+ + + + + + + +
+
WHERE sex = :sex_1_0 
+AND age > :age_3_0 
+OR last_name <> :last_name_5_0 
+OR first_name LIKE :first_name_7_0 
+AND ( id <= :id_10_0 AND birth_date BETWEEN :birth_date_12_0_1 AND :birth_date_12_0_2 ) 
+OR id IN (:id_15_0_0, :id_15_0_1, :id_15_0_2, :id_15_0_3, :id_15_0_4) 
+AND is_deleted IS NOT NULL 
+ORDER BY last_name ASC, first_name ASC, sex ASC 
+LIMIT :limit_rows_count_19_0 OFFSET :offset_start_row_19_0
+
+
+ Here is the list of all functions available to use qx::QxSqlQuery class (or its typedef + qx_query) :
+
+ + + + + + + +
+
// with functions into namespace qx::dao
+qx::dao::count<T>()
+qx::dao::fetch_by_query<T>()
+qx::dao::update_by_query<T>()
+qx::dao::delete_by_query<T>()
+qx::dao::destroy_by_query<T>()
+qx::dao::fetch_by_query_with_relation<T>()
+qx::dao::fetch_by_query_with_all_relation<T>()
+qx::dao::update_by_query_with_relation<T>()
+qx::dao::update_by_query_with_all_relation<T>()
+qx::dao::update_optimized_by_query<T>()
+
+// with qx::QxSession class
+qx::QxSession::count<T>()
+qx::QxSession::fetchByQuery<T>()
+qx::QxSession::update<T>()
+qx::QxSession::deleteByQuery<T>()
+qx::QxSession::destroyByQuery<T>()
+
+// with qx::QxRepository<T> class
+qx::QxRepository<T>::count()
+qx::QxRepository<T>::fetchByQuery()
+qx::QxRepository<T>::update()
+qx::QxRepository<T>::deleteByQuery()
+qx::QxRepository<T>::destroyByQuery()
+
+
+ Note : those functions have 2 other optionals parameters : +
    +
  • const QStringList & columns : to indicate columns to fetch (by default, all columns are + fetched) ;
  • +
  • const QStringList & relation : to indicate relations to fetch (one-to-one, + one-to-many, many-to-one and many-to-many defined into void + qx::register_class<T>() mapping function by class), by default there is no relation + fetched. +
  • +
+
+

+ How to use the cache (functions into namespace qx::cache) of QxOrm + library ?

+ + + + + + + + + +
+ Cache engine provided by QxOrm library (QxCache module) is thread-safe and can store easily any kind of + objects.
+ Functions to access to the cache engine are inside namespace qx::cache.
+ qx::cache engine can provide a program optimization : you can for example store items fetched + by a query to database.
+
+ Each item into the cache is associated with a key of type QString : this key provides a quick + access to an item stored into the cache.
+ If a new item is inserted with a key already in the cache, then the old item associated with this key + is removed automatically from the cache.
+
+ Cache engine of QxOrm library doesn't manage memory : there is no delete called by the cache + engine.
+ This is why it's strongly recommended (but not an obligation) to store smart-pointers into the cache : + for example, boost::shared_ptr<T> of boost library or QSharedPointer<T> of Qt library.
+
+ Cache engine can have a max cost to avoid too much memory usage : each item inserted to the cache can + be associated with a cost (for example, element's count of a collection).
+ When the limit (max cost) of the cache engine is reached, first items inserted to the cache are + automatically removed (insertion order) until limit of the cache is ok.
+
+ It's also possible to associate a date-time insertion when an item is added to the cache.
+ If there is no date-time, then the current date-time is taken into account.
+ This feature provides a way to verify that an item stored into the cache must be updated or not.
+
+ Here is an example using cache engine of QxOrm library (functions into namespace + qx::cache) :
+
+ + + + + + + +
+
// Define max cost of cache engine to 500
+qx::cache::max_cost(500);
+
+// Fetch a list of 'author' from database
+boost::shared_ptr< QList<author> > list_author;
+QSqlError daoError = qx::dao::fetch_all(list_author);
+
+// Insert the list of 'author' to the cache
+qx::cache::set("list_author", list_author);
+
+// Fetch a list of 'blog' from database
+QSharedPointer< std::vector<blog> > list_blog;
+daoError = qx::dao::fetch_all(list_blog);
+
+// Insert the list of 'blog' to the cache (cost = 'blog' count)
+qx::cache::set("list_blog", list_blog, list_blog.count());
+
+// Pointer to an object of type 'comment'
+comment_ptr my_comment;
+my_comment.reset(new comment(50));
+daoError = qx::dao::fetch_by_id(my_comment);
+
+// Insert 'comment' to the cache with a date-time insertion
+qx::cache::set("comment", my_comment, 1, my_comment->dateModif());
+
+// Get the list of 'blog' stored into the cache
+list_blog = qx::cache::get< QSharedPointer< std::vector<blog> > >("list_blog");
+
+// Get the list of 'blog' without providing the type
+qx_bool bGetOk = qx::cache::get("list_blog", list_blog);
+
+// Remove list of 'author' from cache
+bool bRemoveOk = qx::cache::remove("list_author");
+
+// Get items count stored into the cache
+long lCount = qx::cache::count();
+
+// Get current cost of items stored into the cache
+long lCurrentCost = qx::cache::current_cost();
+
+// Verify that an element with the key "comment" exists into the cache
+bool bExist = qx::cache::exist("comment");
+
+// Get 'comment' stored into the cache with its date-time insertion
+QDateTime dt;
+bGetOk = qx::cache::get("comment", my_comment, dt);
+
+// Clear the cache
+qx::cache::clear();
+
+
+
+

+ How to build SQL schema (create and update tables) based on C++ persistents classes + registered in QxOrm context ?

+ + + + + + + + + +
+ It's recommended to use QxEntityEditor application to manage SQL schema + generation.
+
+ QxOrm library doesn't provide a generator to create and to update automatically tables into + database.
+ Indeed, qx::dao::create_table<T> function must be used only to create prototypes or + samples.
+ It's strongly recommended to work with a tool provided by each SGBD to design and to manage tables + into database (for example Navicat with MySql, pgAdmin with PostgreSQL, + SQLite Manager with SQLite, etc.).
+ Moreover, each tool provided by each SGBD can add some optimizations to the database (add some indexes + for example).
+
+ But sometimes, it can be useful to not have to manage manually tables into database.
+ In this case, it's possible to create a C++ function to iterate over all persistents classes + registered in QxOrm context (using introspection engine of QxOrm library) : so you can build a SQL + script to create and to update tables into database.
+
+ QxOrm library provides an example of a C++ function : based on this function, you can create your own + function to build SQL schema.
+ This QxOrm function is written in the file ./src/QxRegister/QxClassX.cpp and is called QString + qx::QxClassX::dumpSqlSchema().
+ This QxOrm function builds a SQL script and returns a QString value : it's also possible to + modify the function to generate a file with SQL script or to execute each SQL process directly to the + SGBD.
+
+ Here is a sample implementation provided by dodobibi to manage a + PostgreSQL database : this sample works with a version number to add columns to existing + tables, to add some indexes to existing columns, etc.
+ When you start your application, a version number is provided and incremented when a new version of + your application is released :
+
+ + + + + + + +
+
QApplication app(argc, argv);
+app.setProperty("DomainVersion", 1);
+
+
+ A table into the database must be created to store this version number.
+ A C++ persistent class is mapped to this table :
+
+ + + + + + + +
+
#ifndef _DATABASE_VERSION_H_
+#define _DATABASE_VERSION_H_
+ 
+class MY_DLL_EXPORT DatabaseVersion
+{
+public:
+  QString name;
+  long version;
+};
+
+QX_REGISTER_HPP_MY_APP(DatabaseVersion, qx::trait::no_base_class_defined, 0)
+
+#endif // _DATABASE_VERSION_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/DatabaseVersion.h"
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_MY_APP(DatabaseVersion)
+
+namespace qx {
+template <> void register_class(QxClass<DatabaseVersion> & t)
+{
+  t.id(& DatabaseVersion::name, "name");
+  t.data(& DatabaseVersion::version, "version");
+}}
+
+
+ With DatabaseVersion class, it's possible to verify that the database must be updated or + not.
+ This is the goal of isDatabaseVersionOld() function :
+
+ + + + + + + +
+
bool isDatabaseVersionOld()
+{
+  DatabaseVersion dbVersion;
+  dbVersion.name = "MyAppName";
+  QSqlError err = qx::dao::fetch_by_id(dbVersion);
+  if (err.isValid()) { qAssert(false); return false; }
+  return (dbVersion.version < qApp->property("DomainVersion").toInt());
+}
+
+
+ If isDatabaseVersionOld() function returns true when you start your application, then + you must update your SQL schema :
+
+ + + + + + + +
+
void updateDatabaseVersion()
+{
+  try
+  {
+    int domainVersion = qApp->property("DomainVersion").toInt();
+
+    // Connect to the database with a user with modifications rights on SQL schema
+    QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
+    db.setUserName("MyAdminLogin");
+    db.setPassword("MyAdminPassword");
+
+    // Create a session, open automatically a transaction and throw an exception when an error occured
+    qx::QxSession session(db, true, true);
+
+    // Fetch the database version with a lock to protect the database
+    DatabaseVersion dbVersion;
+    session.fetchByQuery(qx_query("WHERE name='MyAppName' FOR UPDATE"), dbVersion);
+
+    // When unlocked for other users, verify that the database must be updated or not
+    if (dbVersion.version >= domainVersion) { return; }
+
+    // Execute each SQL process with "query" variable
+    QSqlQuery query(db);
+
+    // Fetch all C++ persistents classes registered in QxOrm context
+    qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
+    if (! pAllClasses) { qAssert(false); return; }
+
+    // Fetch all tables into database (this is a Qt function)
+    QStringList tables = db.tables();
+
+    for (long k = 0; k < pAllClasses->count(); k++)
+    {
+      qx::IxClass * pClass = pAllClasses->getByIndex(k);
+      if (! pClass) { continue; }
+
+      // Filter non persitents classes
+      if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) { continue; }
+
+      // Filter already updated classes
+      if (pClass->getVersion() <= dbVersion.version) { continue; }
+
+      // If table doesn't exist, create it and set the owner
+      if (! tables.contains(pClass->getName()))
+      {
+        query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);"
+                   "ALTER TABLE " + pClass->getName() + " OWNER TO \"MyAdminLogin\";");
+        session += query.lastError();
+      }
+
+      // If a column doesn't exist, add it to the table
+      qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
+      for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
+      {
+        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
+        if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
+
+        query.exec("ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";");
+        session += query.lastError();
+
+        if (p->getIsPrimaryKey()) // PRIMARY KEY
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getAllPropertyBagKeys().contains("INDEX")) // INDEX
+        {
+          query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
+                     " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getNotNull()) // NOT NULL
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
+          session += query.lastError();
+        }
+
+        if (p->getAutoIncrement()) // AUTO INCREMENT
+        {
+          query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
+                     "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"MyAdminLogin\"; "
+                     "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
+                     "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
+          session += query.lastError();
+        }
+
+        if (p->getDescription() != "") // DESCRIPTION
+        {          query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
+          session += query.lastError();
+        }
+      }
+    }
+
+    // Save current version of the database
+    dbVersion.version = domainVersion;
+    session.save(dbVersion);
+
+    // End of "try" scope : session is destroyed => commit or rollback automatically
+    // Moreover, a commit or a rollback unlock the process for all users
+  }
+  catch (const qx::dao::sql_error & err)
+  {
+    QSqlError sqlError = err.get();
+    qDebug() << sqlError.databaseText();
+    qDebug() << sqlError.driverText();
+    qDebug() << sqlError.number();
+    qDebug() << sqlError.type();
+  }
+}
+
+
+ Note : this code (like qx::QxClassX::dumpSqlSchema() function) can be modified to provide more + features.
+ For example, it could be interesting to create by default another table (like DatabaseVersion + table) to store the list of all persistents classes registered in QxOrm context : instead of using + "db.tables()" Qt function, it could be possible to fetch all tables with more informations + (version number for each table, columns count registered in QxOrm context, table description, etc.). +
+
+

+ How to associate a SQL type to a C++ class ?

+ + + + + + + + + +
+ Each database provides its own SQL types to store datas.
+ QxOrm library associates by default some C++ classes frequently used in a program :
+
+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ If a SQL type provided by default by QxOrm library is not supported by the database, it can be easily + modified (globally for all the application) using the following collection :
+
+ + + + + + + +
+
QHash<QString, QString> * lstSqlType = qx::QxClassX::getAllSqlTypeByClassName();
+lstSqlType->insert("QString", "VARCHAR(255)");
+lstSqlType->insert("std::string", "VARCHAR(255)");
+// etc.
+
+
+ To modify a SQL type for a specific column of a table, you have to define the new SQL type in the + mapping function of QxOrm library :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<MyClass> & t)
+{
+  //...
+  IxDataMember * p =  t.data(& MyClass::m_MyProperty, "my_property");
+  p->setSqlType("VARCHAR(255)");
+  //...
+}}
+
+
+ For all classes not supported by default by QxOrm library (see the FAQ : How to persist a type without its source code (class from an external + library for example) ?), it's possible to associate a default SQL type using the following + macro (outside all namespace) :
+
+ + + + + + + +
+
QX_REGISTER_TRAIT_GET_SQL_TYPE(MyClass, "my_sql_type")
+
+
+
+

+ How to use QxValidator module to validate automatically an instance + ?

+ + + + + + + + + +
+ QxValidator module of + QxOrm library provides a validation engine for classes registered in QxOrm context.
+ To use this validation engine, you have to define your constraints into the mapping function per class + : void qx::register_class.
+ If for an instance of class, at least one constraint violation is detected, then the instance is + invalid : the object cannot be saved into database (INSERT or UPDATE).
+
+ It's also possible to use QxValidator module to validate an instance on the presentation layer + : if some datas from a user are invalids, an error message can be displayed, and it's not necessary to + try to send the instance to the data access layer.
+ The validation mechanism can be executed in different layers in your application without having to + duplicate any of these rules (presentation layer, data access layer).
+
+ Here is a description of some classes defined into QxValidator module : + + QxValidator module manages automatically class inheritance : each constraint defined into a + base class is checked during validation process of a derived class.
+
+ Here is an example using QxValidator module with a 'person' class :
+
+ * 'person.h' file :
+ + + + + + + +
+
#ifndef _CLASS_PERSON_H_
+#define _CLASS_PERSON_H_
+ 
+class person
+{
+
+public:
+
+   enum sex { male, female, unknown };
+
+   long        _id;
+   QString     _firstName;
+   QString     _lastName;
+   QDateTime   _birthDate;
+   sex         _sex;
+
+   person() : _id(0), _sex(unknown) { ; }
+   person(long id) : _id(id), _sex(unknown) { ; }
+   virtual ~person() { ; }
+
+private:
+
+   void isValid(qx::QxInvalidValueX & invalidValues);
+
+};
+
+QX_REGISTER_HPP_MY_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _CLASS_PERSON_H_
+
+
+ * 'person.cpp' file :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/person.h"
+#include "../include/global_validator.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_MY_EXE(person)
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+   t.id(& person::_id, "id");
+
+   t.data(& person::_firstName, "firstName");
+   t.data(& person::_lastName, "lastName");
+   t.data(& person::_birthDate, "birthDate");
+   t.data(& person::_sex, "sex");
+
+   QxValidatorX<person> * pAllValidator = t.getAllValidator();
+   pAllValidator->add_NotEmpty("firstName");
+   pAllValidator->add_NotEmpty("lastName", "a person must have a lastname");
+   pAllValidator->add_CustomValidator(& person::isValid);
+   pAllValidator->add_CustomValidator_QVariant(& validateFirstName, "firstName");
+   pAllValidator->add_CustomValidator_DataType<QDateTime>(& validateDateTime, "birthDate");
+}}
+
+void person::isValid(qx::QxInvalidValueX & invalidValues)
+{
+   // This method is called automatically by 'QxValidator' module (validator engine of QxOrm library) :
+   // - when you try to insert or update using 'qx::dao::xxx' functions
+   // - when you call 'qx::validate()' function
+
+   // For registration, see 'pAllValidator->add_CustomValidator(& person::isValid);' into 'qx::register_class' function
+
+   // Here, you can verify some values of your instance
+   // If a value is not valid, you must add an invalid value into the collection 'invalidValues'
+
+   // For example, if we want to check property '_sex' of a person :
+   if ((_sex != male) && (_sex != female))
+   { invalidValues.insert("person sex must be defined : male or female"); }
+}
+
+
+ * 'global_validator.h' file :
+ + + + + + + +
+
// Example of global functions 'validateFirstName' and 'validateDateTime' used by 'QxValidator' module
+// Those functions will be called automatically by validator engine of QxOrm library :
+// - when you try to insert or update using 'qx::dao::xxx' functions
+// - when you call 'qx::validate()' function
+ 
+void validateFirstName(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Here you can test the value (converted to QVariant type)
+   // If an invalid value is detected, just add a message into 'invalidValues' collection
+
+   // For example, if the value must be never equal to "admin" :
+   if (value.toString() == "admin")
+   { invalidValues.insert("value must not be equal to 'admin'"); }
+}
+
+void validateDateTime(const QDateTime & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Here you can test the value (with its real type, in this example, the data-member is a 'QDateTime' type)
+   // If an invalid value is detected, just add a message into 'invalidValues' collection
+
+   // For example, if the date-time must be valid :
+   if (! value.isValid())
+   { invalidValues.insert("date-time value must not be empty and must be valid"); }
+}
+
+
+ * 'main.cpp' file :
+ + + + + + + +
+
person personValidate;
+personValidate._lastName = "admin";
+qx::QxInvalidValueX invalidValues = qx::validate(personValidate);
+QString sInvalidValues = invalidValues.text();
+qDebug("[QxOrm] test 'QxValidator' module :\n%s", qPrintable(sInvalidValues));
+
+
+ During program execution of this code, 'personValidate' instance is not valid : + 'invalidValues' collection contains 4 items :
+ - "property 'firstName' must not be empty" ;
+ - "person sex must be defined : male or female" ;
+ - "value must not be equal to 'admin'" ;
+ - "date-time value must not be empty and must be valid".
+
+ QxValidator module provides some built-in constraints, which cover most of the basic data + checks.
+ As we'll see later, you're not limited to them, you can literally in a minute write your own + constraints : +
    +
  • add_NotNull() : checks if the value is not null ;
  • +
  • add_NotEmpty() : checks if the string is not empty ;
  • +
  • add_MinValue() : checks if the value is more than or equals to min ;
  • +
  • add_MaxValue() : checks if the value is less than or equals to max ;
  • +
  • add_Range() : checks if the value is between Min and Max (included) ;
  • +
  • add_MinDecimal() : checks if the decimal value is more than or equals to min ;
  • +
  • add_MaxDecimal() : checks if the decimal value is less than or equals to max ;
  • +
  • add_RangeDecimal() : checks if the decimal value is between Min and Max (included) ;
  • +
  • add_MinLength() : checks if the string length is more than or equals to min ;
  • +
  • add_MaxLength() : checks if the string length is less than or equals to max ;
  • +
  • add_Size() : checks if the string length is between the min-max range ;
  • +
  • add_DatePast() : checks if the date is in the past ;
  • +
  • add_DateFuture() : checks if the date is in the future ;
  • +
  • add_RegExp() : checks if the property matches the regular expression given a match flag ; +
  • +
  • add_EMail() : checks whether the string conforms to the email address specification.
  • +
+ Like 'person' class example, it's possible to define a custom validator : it's a function or a + class method called automatically by QxValidator module to validate a property or an instance + of class.
+ There are 3 kinds of custom validator : +
    +
  • add_CustomValidator() : class method, method signature must be "void + my_class::my_method(qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_QVariant() : global function with QVariant type (the property + is converted into QVariant type), function signature must be "void my_validator(const + QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_DataType() : global function with real type, function signature must + be "void my_validator(const T &, const qx::IxValidator *, qx::QxInvalidValueX &)" ;
  • +
+ Note : each validator can be associated with a group (optional parameter for each function + add_XXX() of qx::IxValidatorX class).
+ So it's possible to create a context validation during program execution : for example, a person from + IHM A can have different validation rules than a person from IHM B.
+ To execute a validation process by group (for example "myGroup"), you have to call the + following function : "qx::QxInvalidValueX invalidValues = qx::validate(personValidate, + "myGroup");".
+
+ Other note : QxValidator module provides default messages when a constraint violation is + detected.
+ It's possible to modify those default messages (for example, a traduction) using the following + collection : "QHash * lstMessage = QxClassX::getAllValidatorMessage();".
+ For example : "lstMessage->insert("min_value", "la valeur '%NAME%' doit �tre inf�rieure ou �gale � + '%CONSTRAINT%'");".
+ %NAME% and %CONSTRAINT% fields will be automatically replaced by the good value.
+ To modify a message for a specific validator (and not globally), you have to use the optional + parameter provided by each function add_XXX() of qx::IxValidatorX class.
+
+

+ How to use qx::IxPersistable interface ?

+ + + + + + + + + +
+ qx::IxPersistable + interface (or abstract class) provides only pure virtual methods.
+ Using qx::IxPersistable, you will have a common base class to call all persistents functions + without knowing the real type of current instance (polymorphism concept).
+ QxOrm library doesn't force developers to work with a base class to register a persistent type into + QxOrm context, however it's sometimes useful to have an interface to write some generic + algorithms.
+
+ qx::IxPersistable class provides following virtual methods (for more details about those + methods, goto QxOrm library online class + documentation) :
+
+
+
virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchAll(qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList());
+virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection() const;
+virtual qx::IxClass * qxClass() const;
+
+
+ For example, working with a list of qx::IxPersistable pointers, it's possible to save all items + into many tables of database, like this :
+
+ + + + + + + +
+
QList<qx::IxPersistable *> lst = ...;
+foreach(qx::IxPersistable * p, lst)
+{
+   QSqlError daoError = p->qxSave();
+   if (daoError.isValid()) { /* an error occured */ }
+   // etc...
+}
+
+
+ To implement qx::IxPersistable interface, it's necessary to : +
    +
  • inherit persistent class from qx::IxPersistable ;
  • +
  • into class definition (myClass.h for example), add QX_PERSISTABLE_HPP(myClass) + macro ;
  • +
  • into class implementation (myClass.cpp for example), add + QX_PERSISTABLE_CPP(myClass) macro. +
  • +
+ For example, to implement qx::IxPersistable interface for author class from qxBlog tutorial, you have to write + :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author : public qx::IxPersistable
+{
+   QX_PERSISTABLE_HPP(author)
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- properties
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- contructor, virtual destructor
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- methods
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+QX_PERSISTABLE_CPP(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+ Note : project test from ./test/qxDllSample/dll1/ directory provides a kind of 'super + base class' : qx::QxPersistable class implements qx::IxPersistable + interface and inherits from QObject.
+ So SIGNAL-SLOT concept from Qt library can be used with this class and could be an interesting + way to use QxOrm triggers.
+ qx::QxPersistable class provides also some virtual methods to override to manage for example + data validation process from QxValidator module.
+ For information, qx::QxPersistable class is not a part of QxOrm library, but you can copy-past + it into your own project to use all its features : + +
+

+ How to use relationship engine to fetch datas from many tables ?

+ + + + + + + + + +
+ QxOrm library supports 4 kind of relationships to link C++ classes registered in QxOrm context : + one-to-one, one-to-many, many-to-one and many-to-many.
+ For more details to define relationships, you can take a look at qxBlog tutorial.
+ We will explain here how to fetch datas from many tables (QxDao module, functions of qx::dao namespace) : + + The first parameter of fetch_by_id_with_relation, fetch_all_with_relation and fetch_by_query_with_relation functions is the list of relationships to + fetch.
+ This list of relationships can contain those items : +
    +
  • relation key : each relation is associated to a key defined into + qx::register_class<T> setting function ; +
  • +
  • "*" keyword means "fetch all relationships defined into + qx::register_class<T> function (1 level of relationships)" ;
  • +
  • "->" keyword means "LEFT OUTER JOIN" join type between 2 tables ;
  • +
  • ">>" keyword means "INNER JOIN" join type between 2 tables.
  • +
+ Note : using "*" keyword to indicate "fetch all relationships defined into + qx::register_class<T> function", those calls are similar : +
    +
  • qx::dao::fetch_by_id_with_relation("*", ...) == + qx::dao::fetch_by_id_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_by_query_with_relation("*", ...) == + qx::dao::fetch_by_query_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_all_with_relation("*", ...) == + qx::dao::fetch_all_with_all_relation(...). +
  • +
+
+ Example : from qxBlog tutorial, it's possible to fetch all those datas with only 1 query :
+
+ 1- fetch a blog and its author ;
+ 2- for the author fetched, fetch all blog he wrote ;
+ 3- for each blog written by author fetched, fetch all comment + associated.
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("author_id->list_blog->list_comment", my_blog);
+
+
+ This code builds the following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Another example : it's also possible to create a list of relationships to fetch, like this + :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QStringList relation;
+relation << "author_id->list_blog->list_comment";
+relation << "author_id->list_blog->list_category";
+relation << "list_comment";
+relation << "list_category";
+QSqlError daoError = qx::dao::fetch_by_id_with_relation(relation, my_blog);
+
+
+ This code builds the following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, 
+       category_7.category_id AS category_7_category_id_0, category_7.name AS category_7_name_0, category_7.description AS category_7_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN category_blog category_blog_7 ON blog.blog_id = category_blog_7.blog_id 
+LEFT OUTER JOIN category category_7 ON category_blog_7.category_id = category_7.category_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Another example : to fetch all relationships per level, "*" keyword must be used.
+ So to fetch all relationships on 3 levels, we can write :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("*->*->*", my_blog);
+
+
+ This code builds the following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, blog_2.author_id AS blog_2_author_id_0_2, 
+       author_3.author_id AS author_3_author_id_0, author_3.name AS author_3_name_0, author_3.birthdate AS author_3_birthdate_0, author_3.sex AS author_3_sex_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, comment_6.blog_id AS comment_6_blog_id_0_6, 
+       blog_7.blog_id AS blog_7_blog_id_0, blog_7.blog_text AS blog_7_blog_text_0, blog_7.date_creation AS blog_7_date_creation_0, blog_7.author_id AS blog_7_author_id_0_7, 
+       author_8.author_id AS author_8_author_id_0, author_8.name AS author_8_name_0, author_8.birthdate AS author_8_birthdate_0, author_8.sex AS author_8_sex_0, 
+       comment_9.comment_id AS comment_9_comment_id_0, comment_9.blog_id AS comment_9_blog_id_0, comment_9.comment_text AS comment_9_comment_text_0, comment_9.date_creation AS comment_9_date_creation_0, 
+       category_10.category_id AS category_10_category_id_0, category_10.name AS category_10_name_0, category_10.description AS category_10_description_0, 
+       category_11.category_id AS category_11_category_id_0, category_11.name AS category_11_name_0, category_11.description AS category_11_description_0, 
+       blog_12.blog_id AS blog_12_blog_id_0, blog_12.blog_text AS blog_12_blog_text_0, blog_12.date_creation AS blog_12_date_creation_0, blog_12.author_id AS blog_12_author_id_0_12, 
+       author_13.author_id AS author_13_author_id_0, author_13.name AS author_13_name_0, author_13.birthdate AS author_13_birthdate_0, author_13.sex AS author_13_sex_0, 
+       comment_14.comment_id AS comment_14_comment_id_0, comment_14.blog_id AS comment_14_blog_id_0, comment_14.comment_text AS comment_14_comment_text_0, comment_14.date_creation AS comment_14_date_creation_0, 
+       category_15.category_id AS category_15_category_id_0, category_15.name AS category_15_name_0, category_15.description AS category_15_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN author author_3 ON author_3.author_id = blog_2.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN blog blog_7 ON blog_7.blog_id = comment_6.blog_id 
+LEFT OUTER JOIN author author_8 ON author_8.author_id = blog_7.author_id 
+LEFT OUTER JOIN comment comment_9 ON comment_9.blog_id = blog_7.blog_id 
+LEFT OUTER JOIN category_blog category_blog_10 ON blog_7.blog_id = category_blog_10.blog_id 
+LEFT OUTER JOIN category category_10 ON category_blog_10.category_id = category_10.category_id 
+LEFT OUTER JOIN category_blog category_blog_11 ON blog.blog_id = category_blog_11.blog_id 
+LEFT OUTER JOIN category category_11 ON category_blog_11.category_id = category_11.category_id 
+LEFT OUTER JOIN category_blog category_blog_12 ON category_11.category_id = category_blog_12.category_id 
+LEFT OUTER JOIN blog blog_12 ON category_blog_12.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN author author_13 ON author_13.author_id = blog_12.author_id 
+LEFT OUTER JOIN comment comment_14 ON comment_14.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN category_blog category_blog_15 ON blog_12.blog_id = category_blog_15.blog_id 
+LEFT OUTER JOIN category category_15 ON category_blog_15.category_id = category_15.category_id 
+WHERE blog.blog_id = :blog_id
+
+
+
+

+ How to execute a stored procedure or a custom SQL query ?

+ + + + + + + + + +
+ QxOrm library provides 2 functions to execute a stored procedure or a custom SQL query : + + The first parameter of those functions, of qx::QxSqlQuery type (or qx_query), contains the stored procedure or + the custom SQL query to execute.
+ For more informations about qx::QxSqlQuery class, goto here : How to + build a query without writing SQL with the class qx::QxSqlQuery ?
+
+ qx::dao::execute_query<T>() function is a template function : T + type must be registered in QxOrm context (qx::register_class<T> function).
+ All datas returned by the stored procedure or the custom SQL query which could be associated with + members of the C++ class (of T type) will be fetched automatically.
+ An automatic search is done on the name of each fields returned by the query.
+ Here is an example from qxBlog project of QxOrm package :
+
+ + + + + + + +
+
// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+qx_query testStoredProcBis("SELECT * FROM author");
+daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+qx::dump(authorX);
+
+

+ qx::dao::call_query() function + is not a template function : you have to iterate over each result using qx::QxSqlQuery class + (or qx_query).
+ To get an output value parameter (must be pass as QSql::Out or QSql::InOut) returned by + a stored procedure, just call the following method : QVariant qx::QxSqlQuery::boundValue(const + QString & sKey) const;.
+
+ To iterate over all resultset, just use the following methods :
+ * long qx::QxSqlQuery::getSqlResultRowCount() const;
+ * long qx::QxSqlQuery::getSqlResultColumnCount() const;
+ * QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const;
+ * QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) const;
+ * QVector qx::QxSqlQuery::getSqlResultAllColumns() const;
+ * void qx::QxSqlQuery::dumpSqlResult();
+
+ Here is an example using qx::dao::call_query() function :
+
+ + + + + + + +
+
qx_query query("CALL MyStoredProc(:param1, :param2)");
+query.bind(":param1", "myValue1");
+query.bind(":param2", 5024, QSql::InOut);
+QSqlError daoError = qx::dao::call_query(query);
+QVariant vNewValue = query.boundValue(":param2");
+query.dumpSqlResult();
+
+
+
+

+ How to use qx::QxDaoAsync class to execute queries in asynchronous way + (multi-thread) ?

+ + + + + + + + + +
+ Sometimes, it's necessary to execute some queries to database in asynchronous way (multi-thread), for + example to avoid to freeze a GUI if a query is too long to execute.
+ To make easier to work with asynchronous queries, QxOrm library provides qx::QxDaoAsync + class.
+ This class executes a query in another thread and returns the queryFinished() SIGNAL + when query is terminated.
+ To use qx::QxDaoAsync class, you just have to : +
    +
  • be careful to work only with classes implementing qx::IxPersistable interface ;
  • +
  • create an instance of qx::QxDaoAsync type (for example, a property of a QWidget + derived class) ;
  • +
  • connect a SLOT to the qx::QxDaoAsync::queryFinished() SIGNAL (for example, + a SLOT of a QWidget derived class) ;
  • +
  • run a query using one of qx::QxDaoAsync::asyncXXXX() methods.
  • +
+ Here is an example with a class called MyWidget :
+
+ + + + + + + +
+
class MyWidget : public QWidget
+{ Q_OBJECT
+
+   //...
+   qx::QxDaoAsync m_daoAsync;
+   //...
+Q_SLOTS:
+   void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
+   //...
+
+};
+
+
+ And here is the implementation of MyWidget class :
+
+ + + + + + + +
+
MyWidget::MyWidget() : QObject()
+{
+   //...
+   QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), 
+                    this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)));
+   //...
+}
+
+void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams)
+{
+   if (! pDaoParams) { return; }
+   qx::QxSqlQuery query = pDaoParams->query;
+   if (! daoError.isValid()) { ; }
+   // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
+   qx::IxPersistable_ptr ptr = pDaoParams->pInstance;
+   // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
+   qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances;
+   //...
+}
+
+
+
+

+ How to use QxModelView module to interact with Qt model/view + architecture (Qt widgets and/or QML views) ?

+ + + + + + + + + +
+ QxModelView module + provides an easy way to work with Qt + model/view engine with all classes registered in QxOrm context : +
    +
  • Qt widgets : QTableView or QListView for example to display/modify a database + table content ;
  • +
  • QML : each property defined in QxOrm context is exposed to QML engine : QxModelView module + makes easier integration between QML and databases.
  • +
+ qx::IxModel interface provides + a generic way for all models linked to persistents classes registered in QxOrm context. All methods of + this class prefixed by 'qx' call functions from 'qx::dao' namespace and then communicate + with database.
+
+ The qxBlogModelView sample project in ./test/ directory of QxOrm package shows how to + create quickly a model and associate it to the Qt model/view engine (first with a Qt widget, + then with a QML view).
+
+ 1- Here is an example to display/modify data from 'author' table (go to qxBlog tutorial for 'author' class + definition) in a QTableView :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QTableView and display it
+QTableView tableView;
+tableView.setModel(pModel);
+tableView.show();
+
+
+ After executing this code, you will have the following window :
+
+ qx_model_view_01
+

+ 2- Here is another example in QML (with Qt5, QxModelView module works fine with Qt4 too) :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QML view and display it
+QQuickView qmlView;
+qmlView.rootContext()->setContextProperty("myModel", pModel);
+qmlView.setSource(QUrl("qrc:/documents/main.qml"));
+qmlView.show();
+
+
+ And here is the 'main.qml' file content :
+
+ + + + + + + +
+
import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+Item {
+   width: 400
+   height: 300
+   Row {
+      height: 20
+      spacing: 20
+      Button {
+         text: "Clear"
+         onClicked: myModel.clear()
+      }
+      Button {
+         text: "Fetch All"
+         onClicked: myModel.qxFetchAll_()
+      }
+      Button {
+         text: "Save"
+         onClicked: myModel.qxSave_()
+      }
+   }
+   ListView {
+      y: 30
+      height: 270
+      model: myModel
+      delegate: Row {
+         height: 20
+         spacing: 10
+         Text { text: "id: " + author_id }
+         TextField {
+            text: name
+            onTextChanged: name = text
+         }
+      }
+   }
+}
+
+
+ After executing this code, you will have the following window :
+
+ qx_model_view_02
+
+ As you can see in the 'main.qml' file, 'author_id' and 'name' properties of + 'author' model (myModel variable) can be automatically read and write (because they are + registered in QxOrm context).
+ Moreover, qx::IxModel + interface provides a list of methods for QML side (Q_INVOKABLE) to communicate with database : + for example, the 'Save' button will save the model in database without having to write a C++ + function.
+
+ Note : a QxEntityEditor plugin generates automatically the code to manage models with + relationships. Then it is possible to work with nested C++ models.
+
+

+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/home.html b/doc/qxorm_en/home.html new file mode 100644 index 0000000..78ff5be --- /dev/null +++ b/doc/qxorm_en/home.html @@ -0,0 +1,411 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Home + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+

QxOrm (the engine) + QxEntityEditor (the graphic editor) = the best solution to + manage your persistent data layer in C++/Qt !

+
+
+
QxOrm library is an Object Relational Mapping (ORM) database library for C++/Qt + developers. + With a simple C++ setting function per class (like Hibernate XML mapping file in Java), you have access to the following + features :
+
    +
  • + Persistence + : support most common databases like SQLite, MySQL, PostgreSQL, Oracle, MS SQL Server, MongoDB (with 1-1, 1-n, n-1 and + n-n relationships) ; +
  • +
  • + Serialization + : JSON, binary and XML format ;
  • +
  • + Reflection + (or + introspection + ) : access dynamically to classes definitions, retrieve properties and call classes methods ; +
  • +
  • + HTTP web server + + : standalone multi-threaded HTTP 1.1 web server (support SSL/TLS, persistent connections, + cookies, sessions, chunked responses, URL dispatcher/routing) ;
  • +
  • + JSON API + : interoperability with other technology than C++/Qt (REST web services, QML applications, + scripting language).
  • +
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ QxEntityEditor is a graphic editor for QxOrm library : QxEntityEditor provides a graphic + way to manage the data model.
+ QxEntityEditor is multi-platform (available for Windows, Linux and Mac OS X) and generates native code + for all environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android, iOS, Windows Phone, + Raspberry Pi, etc.).
+ A user manual (documentation) for QxEntityEditor application is + available.
+
+ QxEntityEditor is based on plugins and provides many ways to import/export your data model : + + QxEntityEditor +

+
+
+ QxOrm library is designed to make easier C++ development and provides many functionalities.
+ Here is a list of advantages of QxOrm library : +
    +
  • non intrusive : the C++ setting function per class doesn't modify class definition, QxOrm + can be used in existing projects ;
  • +
  • no XML mapping file ;
  • +
  • classes doesn't need to inherit from a 'super object' ;
  • +
  • template meta-programming : no macro hack ;
  • +
  • works with Visual C++ on Windows, GCC on Linux, Clang on Mac OS X, and MinGW + on Windows (other platforms will be tested soon : smartphones, etc...) ;
  • +
  • only one file <QxOrm.h> to include in precompiled-header (precompiled-header file is + recommended to reduce compilation times).
  • +
+
+ QxOrm is based on Qt framework (support Qt4, + Qt5, Qt6) : + +

+ + + + + + + + + +
QtQt : cross-platform application development framework : GUI (QtGui), + network (QtNetwork), XML (QtXml), database (QtSql)...
+ Qt provides excellent support and documentation. Using Qt, you can write simple and powerful C++ + code.
+ Qt is produced by Digia's Qt Development Frameworks division and is available under LGPL license.
+ QxOrm is compatible with many Qt's objects : QObject, QString, QDate, QTime, QDateTime, QList, + QHash, QSharedPointer, QScopedPointer...
+ It is recommended to install the latest version of Qt available at the following address : http://www.qt.io/
+

+ +
+

QxOrm provides the following modules :

+
    +
  • +

    QxDao : based on Qt QtSql engine, this module + provides communication with databases (select, update, delete, transaction...) by mapping + database table columns with C++ class properties. The relationships 1-1, 1-n, n-1 + and n-n are easy to setup in C++ code. This module supports object-oriented programming : + inheritance, polymorphism, modularity. It supports also many containers (stl, boost and + Qt : std::vector, std::list, std::unordered_map, QList, QHash...). +

    +
  • +
  • +

    QxRegister, QxDataMember, QxFactory and QxFunction : QxOrm + emulates reflection (or introspection) mechanism (like other languages : Java, C#...).

    +
  • +
  • +

    QxModelView : each + class registered in QxOrm context can be used by the Qt model/view engine (Qt widgets and/or QML views). qx::IxModel interface exposes + automatically to QML engine all properties defined in QxOrm context. This module makes easier + interaction between QML and databases.

    +
  • +
  • +

    QxService : based on QtNetwork engine of Qt + library, this module provides an easy and powerful way to create C++ application server + (services concept with request from client and reply from server). QxService + uses serialization and introspection from QxOrm library to transfer over network any class + or structure. For more details about QxService module, a tutorial is available here.

    +
  • +
  • +

    QxCollection<Key, + Value> : + + this thread-safe container has advantages of std::vector<T> (insertion order + quick access + by index) and std::unordered_map<Key, Value> or QHash<Key, Value> (quick + access by a key : hash-map). QxCollection<Key, Value> is adapted to contain the + items resulting from a database. +

    +
  • +
  • +

    QxSerialize : this + module is based on Qt QDataStream class. + + Any class defined by QxOrm can be serialized to binary, XML and JSON format. This module also allows to + clone all instances of objects. Most of Qt objects (QObject, QString, QDate, QTime, QDateTime, QList, + QHash...) are compatible with QxSerialize module. +

    +
  • +
  • +

    QxTraits : C++ standard + library provides several generic traits. QxOrm uses them but needs new functionalities that are not + present in std standard library.

    +
  • +
  • +

    QxCache : QxOrm's cache can + contain all types of objects. It's possible for example to store data resulting from a database to avoid + too frequent requests. This cache is generic and can be used in other contexts than QxOrm.

    +
  • +
  • +

    QxValidator : this + module provides a validation engine for classes registered in QxOrm context. To use this validation + engine, you have to define your constraints into the mapping function per class : void + qx::register_class. If for an instance of class, at least one constraint violation is detected, + then the instance is invalid : the object cannot be saved into database (INSERT or + UPDATE). For more information about QxValidator module, read the manual here. +

    +
  • +
  • +

    QxMemLeak : fast + detection of memory leaks in Debug mode (with indication of file and line => MFC style from + Microsoft). This module is developed by Wu + Yongwei. If another tool is already used in your projects (Valgrind for example), this + functionality should not be enabled. By default, QxMemLeak module is disabled.

    +
  • +
+

+
+

You can download the current version of QxOrm library and QxEntityEditor application here. +
A manual (user guide) to learn how to work with QxOrm library is available here. +
A quick sample showing basic functionalities of QxOrm is available here. +
If you have any questions about QxOrm library or QxEntityEditor application, a forum is + available here.
+

+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/link.html b/doc/qxorm_en/link.html new file mode 100644 index 0000000..35d7198 --- /dev/null +++ b/doc/qxorm_en/link.html @@ -0,0 +1,264 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Forum + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+ If you find a bug or if you have a question about QxOrm library or QxEntityEditor + software : + + + + + + + + + + +
+ + + QxOrm forum + + QxEntityEditor forum +
+
+ If you have a question about boost or Qt library : + + + + + + + + + + +
+ + + Qt forum + + boost forum +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ French web sites to help you to your development software with forums, tutorials, documentations... + +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/manual.html b/doc/qxorm_en/manual.html new file mode 100644 index 0000000..230eff2 --- /dev/null +++ b/doc/qxorm_en/manual.html @@ -0,0 +1,12788 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Manual - QxOrm library user guide + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + + +
+ Select a manual : + + QxOrm user guide + QxEntityEditor user guide +
+
+
+ + + + + + + + + +
+

QxOrm library manual - Table of Contents

+
+
    +
  1. + Introduction +
      +
    1. + QxOrm library +
    2. +
    3. + Quick overview of QxEntityEditor application +
    4. +
    5. + C++ coding style of QxOrm library +
    6. +
    +
  2. +
  3. + Installation +
      +
    1. + Qt dependency +
    2. +
    3. + Boost dependency (optional) +
    4. +
    5. + QxOrm.pri (or QxOrm.cmake) configuration file +
    6. +
    7. + Build QxOrm library (with qmake or CMake) +
    8. +
    9. + Qt SQL drivers (supported databases) +
    10. +
    +
  4. +
  5. + Persistence - Object Relational Mapping (ORM) +
      +
    1. + Register a class in QxOrm context (mapping) +
        +
      1. + Primary key other than default type "long" +
      2. +
      3. + Composite primary key +
      4. +
      5. + public or protected/private data members +
      6. +
      7. + Namespace +
      8. +
      9. + Built-in C++ supported types +
      10. +
      11. + Register a transient data member +
      12. +
      +
    2. +
    3. + Connection to database +
    4. +
    5. + Persist a C++ instance in database (insert/update) +
    6. +
    7. + Delete an instance in database (delete) +
        +
      1. + Soft delete behaviour (logical delete) +
      2. +
      +
    8. +
    9. + Get a C++ instance from database (fetch) +
    10. +
    11. + SQL queries +
        +
      1. + Using qx::QxSqlQuery class (or qx_query + alias) +
      2. +
      3. + Using standard SQL or stored procedure +
      4. +
      +
    12. +
    13. + Transactions (commit, rollback, session) +
    14. +
    15. + Relationships +
        +
      1. + one-to-many (1-n) +
      2. +
      3. + many-to-one (n-1) +
      4. +
      5. + many-to-many (n-n) +
      6. +
      7. + one-to-one (1-1) +
      8. +
      9. + Fetch relationships +
      10. +
      11. + Select columns fetching relationships and define + custom SQL alias +
      12. +
      13. + Add SQL query inside LEFT OUTER JOIN / INNER + JOIN +
      14. +
      +
    16. +
    17. + Supported containers +
        +
      1. + Qt containers +
      2. +
      3. + Boost containers +
      4. +
      5. + std containers +
      6. +
      7. + qx::QxCollection +
      8. +
      +
    18. +
    19. + Supported smart pointers +
        +
      1. + Qt smart pointers +
      2. +
      3. + Boost smart pointers +
      4. +
      5. + std smart pointers +
      6. +
      7. + qx::dao::ptr +
      8. +
      +
    20. +
    21. + Triggers +
    22. +
    23. + Validators +
    24. +
    25. + Manage NULL database value +
        +
      1. + boost::optional +
      2. +
      3. + QVariant +
      4. +
      +
    26. +
    27. + Inheritance and polymorphism +
    28. +
    29. + qx::IxPersistable interface (abstract class) +
    30. +
    31. + Use PIMPL C++ pattern (Private Implementation idiom or + d-pointer) +
    32. +
    33. + Persist custom type +
    34. +
    35. + Generate database DDL SQL schema +
    36. +
    37. + Associate a SQL type to a C++ class +
    38. +
    39. + Async database queries +
    40. +
    41. + Cache to store C++ instances (QxCache module) +
    42. +
    43. + Working with several databases +
    44. +
    45. + Register an abstract class in QxOrm context +
    46. +
    47. + Register automatically Qt meta-properties + (Q_PROPERTY macro) +
    48. +
    +
  6. +
  7. + Serialization +
      +
    1. + Version number to manage ascendant compatibility +
    2. +
    3. + Qt QDataStream engine +
    4. +
    5. + Qt JSON engine +
    6. +
    7. + XML boost serialization +
    8. +
    9. + Binary boost serialization +
    10. +
    11. + Other boost serialization +
    12. +
    13. + Clone a C++ instance +
    14. +
    15. + Dump a C++ instance (XML or JSON format) +
    16. +
    +
  8. +
  9. + Introspection - Reflection +
      +
    1. + Get a data member value dynamically +
    2. +
    3. + Set a data member value dynamically +
    4. +
    5. + Call function dynamically +
    6. +
    7. + Create a C++ instance dynamically +
    8. +
    9. + Iterate over all classes/properties registered in QxOrm + context +
    10. +
    +
  10. +
  11. + Services : transfer persistent data layer over network + (QxService module) +
      +
    1. + Input/output service parameters (request/response) +
    2. +
    3. + Define service functions exposed to clients +
    4. +
    5. + List of options available on server side +
    6. +
    7. + Connection settings on client side +
    8. +
    9. + Service authentication +
    10. +
    11. + Async client/server queries +
    12. +
    +
  12. +
  13. + Model View engine (QxModelView module) +
      +
    1. + Simple model (without relationship) +
    2. +
    3. + Model with relationships (nested models) +
    4. +
    5. + Interaction with QML views +
    6. +
    7. + Interaction with QtWidget views +
    8. +
    9. + Connect model to QxService module +
    10. +
    +
  14. +
  15. + QxOrm and MongoDB database (C++ ODM Object Document Mapper) +
      +
    1. + Prerequisites : driver libmongoc and + libbson +
    2. +
    3. + QxOrm.pri (or QxOrm.cmake) configuration file +
    4. +
    5. + Connection to MongoDB database +
    6. +
    7. + Register a MongoDB persistent class (Collection) in + QxOrm context (mapping) +
        +
      1. + Manage ObjectId (primary key) +
      2. +
      +
    8. +
    9. + Insert a C++ instance (Document) in MongoDB database +
        +
      1. + Insert many C++ instances (list of Documents) in + MongoDB database +
      2. +
      +
    10. +
    11. + Update a C++ instance (Document) in MongoDB database +
        +
      1. + Update many C++ instances (list of Documents) in + MongoDB database +
      2. +
      +
    12. +
    13. + Delete a C++ instance (Document) from MongoDB + database +
        +
      1. + Delete many C++ instances (list of Documents) + from MongoDB database +
      2. +
      +
    14. +
    15. + Fetch a C++ instance (Document) from MongoDB + database +
        +
      1. + Fetch many C++ instances (list of Documents) from + MongoDB database +
      2. +
      +
    16. +
    17. + JSON queries +
        +
      1. + Using qx::QxSqlQuery class (or qx_query + alias) +
      2. +
      3. + Using MongoDB aggregation framework +
      4. +
      5. + Add 'sort', 'limit', 'skip', etc..., properties + to JSON query +
      6. +
      7. + Execute a custom query +
      8. +
      +
    18. +
    19. + Relationships engine (MongoDB version 3.6 or + is + required) +
        +
      1. + Embedded vs Referenced +
      2. +
      +
    20. +
    21. + Create automatically indexes +
    22. +
    +
  16. +
  17. + HTTP/HTTPS web server (QxHttpServer module) +
      +
    1. + Hello World ! +
    2. +
    3. + HTTP/HTTPS web server settings +
        +
      1. + Secured connections SSL/TLS +
      2. +
      +
    4. +
    5. + Routing URL (dispatcher / endpoints) +
        +
      1. + Dynamic URL routing +
      2. +
      +
    6. +
    7. + Get HTTP request parameters +
    8. +
    9. + Build HTTP response +
    10. +
    11. + Sessions (storage per client on server side) +
    12. +
    13. + Cookies +
    14. +
    15. + Static files +
    16. +
    17. + Chunked responses +
    18. +
    19. + Requests using JSON API (QxRestApi module) +
    20. +
    21. + WebSocket +
    22. +
    23. + Performance (tested with Apache Benchmark) +
        +
      1. + Improve performance with epoll dispatcher on + Linux +
      2. +
      +
    24. +
    +
  18. +
  19. + JSON REST API (QxRestApi module) +
      +
    1. + How it works +
        +
      1. + Use cases +
      2. +
      +
    2. +
    3. + qxBlogRestApi example project (QML and HTTP web + server) +
    4. +
    5. + Fetch +
        +
      1. + fetch_all +
      2. +
      3. + fetch_by_id +
      4. +
      5. + fetch_by_query +
      6. +
      7. + count +
      8. +
      9. + exist +
      10. +
      +
    6. +
    7. + Insert +
    8. +
    9. + Update +
    10. +
    11. + Save (insert or update) +
    12. +
    13. + Delete +
        +
      1. + delete_all / destroy_all +
      2. +
      3. + delete_by_query / destroy_by_query +
      4. +
      5. + delete_by_id / destroy_by_id +
      6. +
      +
    14. +
    15. + Validate +
    16. +
    17. + Custom SQL query or stored procedure +
    18. +
    19. + Call C++ natives functions +
    20. +
    21. + Meta-data (C++ classes registered into QxOrm + context) +
    22. +
    23. + Send a list of JSON requests +
    24. +
    +
  20. +
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt + Ambassador Program + +
+
+
+
+ +

Introduction

+
+ The goal of this documentation is to provide a user guide to learn how to work with QxOrm + library features. + This manual is intended for developers and software architects who are looking for a solution to + manage a persistent data layer in C++/Qt. + Technical skills in C++ and databases are required to understand this document. +

+ Note : all features described in this manual/user guide can be defined quickly and easily + with QxEntityEditor application (the graphic editor for QxOrm library, data model + designer and source code generator). + Another documentation dedicated to QxEntityEditor application + is available on QxOrm website. +

+ Other note : this manual is based on the old FAQ of QxOrm website, you + can always access to this FAQ here. +

+

QxOrm library

+
+ QxOrm is a C++ library designed to provide Object Relational Mapping (ORM) feature to + C++ users.
+ QxOrm is developed by XDL Team, a software development engineer since 2003.
+

+ Based on a simple C++ setting function per class (like Hibernate XML mapping file in Java), QxOrm library provides + following features : +
    +
  • + Persistence + + : support most common databases like SQLite, MySQL, PostgreSQL, Oracle, MS SQL + Server, MongoDB (with 1-1, 1-n, + n-1 and n-n relationships) ; +
  • +
  • + Serialization + : JSON, binary and XML format ;
  • +
  • + Reflection + + (or + introspection + ) : access dynamically to classes definitions, retrieve properties and call classes + methods ;
  • +
  • + HTTP web + server + : standalone multi-threaded HTTP 1.1 web server (support SSL/TLS, persistent + connections, cookies, sessions, chunked responses, URL dispatcher/routing) ;
  • +
  • + JSON API + + : interoperability with other technology than C++/Qt (REST web services, QML + applications, scripting language).
  • +
+ QxOrm depends on Qt (from version 4.5.0) + and boost (from version 1.38, and by + default just header files *.hpp are necessary).
+ QxOrm library has been accepted into the Qt Ambassador + Program. +

+ If you find a bug or if you have a question about QxOrm library, you can send an e-mail + to : support@qxorm.com.
+ A forum dedicated to QxOrm library is available here.
+ If you speak/understand french, you can access to the french community on the famous developpez.com forum. +

+
+

Quick overview of + QxEntityEditor application

+
+ QxEntityEditor is a graphic editor for QxOrm library : QxEntityEditor + provides a graphic way to manage the data model.
+ QxEntityEditor is multi-platform (available for Windows, Linux and Mac OS X) and + generates native code for all environments : desktop (Windows, Linux, Mac OS X), embedded and + mobile (Android, iOS, Windows Phone, Raspberry Pi, etc.).
+ A presentation video of QxEntityEditor application is + available on YouTube.
+
+ QxEntityEditor is based on plugins and provides many ways to import/export your data + model : +
    +
  • generate C++ persistent classes automatically (registered in QxOrm context) ;
  • +
  • generate DDL SQL script automatically (database schema) for SQLite, MySQL, PostgreSQL, + Oracle and MS SQL Server ;
  • +
  • manage schema evolution for each project version (ALTER TABLE, ADD COLUMN, + DROP INDEX, etc.) ; +
  • +
  • transfer your data model over network and create quickly client/server applications, + using QxService + module ;
  • +
  • import existing database structure (using ODBC connection) for SQLite, MySQL, PostgreSQL, + Oracle and MS SQL Server databases ;
  • +
  • because each project is different, QxEntityEditor provides several ways to customize + generated files (especially a javascript engine and an integrated debugger).
  • +
+ QxEntityEditor +

+ QxEntityEditor is developed by XDL Team, a software development engineer since 2003.
+ A manual dedicated to QxEntityEditor application is + available on QxOrm website. +

+
+

C++ coding style of QxOrm + library

+
+ QxOrm library uses following syntax and naming convention for C++ source code : +
    +
  • all classes, functions, properties, etc... are defined under namespace qx ; +
  • +
  • all macros of QxOrm library are prefixed by QX_... ; +
  • +
  • all abstracts classes (or interfaces) start with prefix Ix (for example + IxFactory is an interface to create an instance of object) ; +
  • +
  • other classes start with prefix Qx (for example QxDataMember) ; +
  • +
  • containers of objects end with suffix X (for example QxDataMemberX is a + list of QxDataMember) ; +
  • +
  • functions to interact with databases are under namespace qx::dao (for example + qx::dao::fetch_by_id()) ; +
  • +
  • functions to serialize are under namespace + qx::serialization (for example qx::serialization::xml::to_file()) ; +
  • +
  • the reflection (or introspection) engine can be used with + qx::QxClassX class (for example qx::QxClassX::invoke() to call a + class method) ; +
  • +
  • all traits classes are under namespace qx::trait (for + example qx::trait::is_smart_ptr<T>). +
  • +
+
+
+ +

Installation

+
+ QxOrm library is multi-platform and can be installed on all environments : Windows, Linux, + Mac OS X, Android, iOS, Windows Phone, Raspberry Pi, etc...
+ A full tutorial (with screenshots) to install a development environment + with QxOrm on Windows is available here. +

+ The goal of this chapter is to explain all steps required to install QxOrm library on all + environments : + +
+

Qt dependency

+
+ + + + + + + + + +
QtQt : cross-platform application development framework : GUI + (QtGui), network (QtNetwork), XML (QtXml), database + (QtSql)...
+ Qt provides excellent support and documentation. Using Qt, you can write simple and + powerful C++ code.
+ Qt is produced by Digia's Qt Development Frameworks division and is available under + LGPL license.
+ QxOrm is compatible with many Qt's objects : QObject, QString, QDate, QTime, + QDateTime, QList, QHash, QSharedPointer, QScopedPointer...
+ It is recommended to install the latest version of Qt available at the following + address : http://www.qt.io/
+
+ Note : by default, QxOrm library depends only on QtCore and QtSql binaries. + It is possible to enable extra features in the QxOrm.pri (or + QxOrm.cmake) configuration file : some features can add dependencies to QxOrm + library. +

+
+

Boost dependency + (optional)

+
+ By default, QxOrm library depends only on Qt (QtCore and QtSql). + boost installation is optional and not required with default configuration. +
+ Note : QxOrm provides 2 dependency levels on boost : +
    +
  • dependency only on boost headers files (*.hpp) : _QX_ENABLE_BOOST + compilation option ;
  • +
  • dependency on boost serialization module : _QX_ENABLE_BOOST_SERIALIZATION + compilation option.
  • +
+
+ + + + + + + + + +
boostboost : many of boost's founders are on the C++ standard + committee and several boost libraries have been accepted for incorporation into + C++1x (new standard for the C++ programming language). + The boost's libraries are aimed at a wide range of C++ users and application + domains.
+ QxOrm uses the following boost's features (header files *.hpp only, boost + serialization dependency is optional) : smart_pointer, type_traits, + multi_index_container, unordered_container, any, tuple, foreach, + function.
+ It is recommended to get the latest version of boost available at the following + address : http://www.boost.org/ +
+
+ Important note : with _QX_ENABLE_BOOST compilation option, QxOrm library + depends only on *.hpp boost header files (header only libraries). + So in this case, boost installation is very easy because you just have to unzip boost package + (to get *.hpp header files, there is nothing to build). +

+
+

QxOrm.pri (or + QxOrm.cmake) configuration file

+
+ QxOrm.pri (or QxOrm.cmake) configuration file is divided into several sections + (each section is commented) and provides all settings and compilation options available to + customize QxOrm library features. + So it is strongly recommended to read carefully QxOrm.pri configuration file before + compiling and building QxOrm library. + It is possible to keep default settings, only QX_BOOST_INCLUDE_PATH variable is required + if you work with boost : this variable is used to define where *.hpp boost header files + are located :
+
+ + + + + + + +
+
   isEmpty(QX_BOOST_INCLUDE_PATH) { QX_BOOST_INCLUDE_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_57/include) }   
+
+
+ If you don't want to change QxOrm.pri configuration file, it is possible to define an + environment variable named BOOST_INCLUDE : this environment variable will be used + automatically to set QX_BOOST_INCLUDE_PATH value (read QxOrm.pri configuration + file for more details). +

+ Here is a list of compilation options available in QxOrm.pri configuration file, by + default they are all disabled : +
    +
  • _QX_ENABLE_BOOST : add a dependency to boost headers files (*.hpp), support + some classes like : boost::shared_ptr, boost::optional, + boost::container, etc... ; +
  • +
  • _QX_ENABLE_BOOST_SERIALIZATION : enable boost::serialization + engine. This option requires to build boost::serialization binary and adds a dependency to QxOrm library + ;
  • +
    +
  • _QX_ENABLE_QT_GUI : support serialization of QtGui types : + QBrush, QColor, QFont, QImage, QMatrix, QPicture, QPixmap, QRegion. This option + adds a dependency to QxOrm library (QtGui) ; +
  • +
  • _QX_ENABLE_QT_NETWORK : enable QxService module to + transfer persistent data layer over network (client/server application). This option adds + a dependency to QxOrm library (QtNetwork) ;
  • +
  • _QX_NO_PRECOMPILED_HEADER : disable precompiled header (used to reduce compilation + times of a project) : this option is required with recent + versions of MinGW (because of a known compiler bug), for all other compilers it is + recommended to work with precompiled header ;
  • +
  • _QX_NO_RTTI : build QxOrm library (and all projects which depend on QxOrm) without + RTTI C++ + type information ; +
  • +
  • _QX_STATIC_BUILD : build QxOrm library in static mode (but build QxOrm as a + shared library is recommended). +
  • +
  • _QX_UNITY_BUILD : reduce QxOrm library compilation times using unity build + concept : only one all.cpp source file to compile. It is recommended to enable this + option with CMake (because doesn't + support natively precompiled headers) ;
  • +
  • _QX_ENABLE_MONGODB : support MongoDB database, QxOrm + library becomes an ODM (Object Document Mapper).
  • +
+
+ Note : QxOrm.pri (or QxOrm.cmake) configuration file must be included in + all projects which depend on QxOrm library, just adding following line in *.pro project + file :
+
+ + + + + + + +
+
   include(my_path_to_QxOrm_library/QxOrm.pri)   
+
+
+ Other note : instead of qmake, it is possible to use CMake compilation tools to configure and build QxOrm library. + CMake provides a GUI tool to display and configure all available parameters : +

+ QxOrm and CMake +

+
+

Build QxOrm library (with + qmake or CMake)

+
+ QxOrm library uses qmake process from Qt framework to create + makefile and build the project (it is also possible to use CMake compilation tools, a CMakeLists.txt file is provided with + QxOrm library).
+ qmake is portable and multi-platform, so it works perfectly on Windows, Linux (Unix) and + Mac OS X.
+ To build QxOrm library, just execute following commands :
+
+ + + + + + + +
+
   qmake
+   make debug
+   make release   
+
+
+ On Windows, *.vcproj and *.sln files are available for Microsoft Visual + C++.
+ *.pro files are readable by Qt Creator, and some plugins are available to + interface to other C++ source code editors.
+ mingw_build_all_debug.bat and mingw_build_all_release.bat scripts in the directory + ./tools/ can be used to quickly build QxOrm library and all tests with MinGW + compiler on Windows.
+ gcc_build_all_debug.sh and gcc_build_all_release.sh scripts in the directory + ./tools/ can be used to quickly build QxOrm library and all tests with GCC + compiler on Linux.
+ osx_build_all_debug.sh and osx_build_all_release.sh scripts in the directory + ./tools/ can be used to quickly build QxOrm library and all tests on Mac OS X + (thanks very much to Dominique Billet for the scripts). +

+
+

Qt SQL drivers (supported + databases)

+
+ QxOrm library uses QtSql engine of Qt framework based on a system of + plugins.
+ A list of supported databases is + available on Qt website.
+ The ODBC plugin (QODBC) ensures compatibility with many databases.
+ For optimal performances, it is recommended to work with a database specific plugin : +
    +
  • QMYSQL : MySQL ;
  • +
  • QPSQL : PostgreSQL (versions 7.3 and above) ;
  • +
  • QOCI : Oracle Call Interface Driver ;
  • +
  • QSQLITE : SQLite version 3 ;
  • +
  • QDB2 : IBM DB2 (version 7.1 and above) ;
  • +
  • QIBASE : Borland InterBase ;
  • +
  • QTDS : Sybase Adaptive Server.
  • +
+ Note : to connect to a Microsoft SQL Server database, it is necessary to use + ODBC (QODBC plugin). +

+ Other note : QxOrm library is able to connect to MongoDB database + (C++ ODM Object Document Mapper). +

+
+
+ +

Persistence - Object + Relational Mapping (ORM)

+
+ QxOrm library provides a data persistence engine based on QtSql module of Qt + framework. + This persistence engine uses programming pattern : Object Relational Mapping (ORM). +

+ From Wikipedia + website : Object-Relational Mapping (ORM) in computer science is a programming technique for + converting data between incompatible type systems in object-oriented programming languages. This + creates, in effect, a "virtual object database" that can be used from within the programming + language.
+ In object-oriented programming, data management tasks act on object-oriented (OO) objects that are + almost always non-scalar values. For example, consider an address book entry that represents a + single person along with zero or more phone numbers and zero or more addresses. This could be + modeled in an object-oriented implementation by a "Person object" with attributes/fields to hold + each data item that the entry comprises : the person's name, a list of phone numbers, and a list of + addresses. The list of phone numbers would itself contain "PhoneNumber objects" and so on. The + address book entry is treated as a single object by the programming language (it can be referenced + by a single variable containing a pointer to the object, for instance). Various methods can be + associated with the object, such as a method to return the preferred phone number, the home + address, and so on.
+ However, many popular database products such as SQL database management systems (DBMS) can only + store and manipulate scalar values such as integers and strings organized within tables. The + programmer must either convert the object values into groups of simpler values for storage in the + database (and convert them back upon retrieval), or only use simple scalar values within the + program. Object-relational mapping is used to implement the first approach.
+ The heart of the problem is translating the logical representation of the objects into an atomized + form that is capable of being stored in the database, while preserving the properties of the + objects and their relationships so that they can be reloaded as objects when needed. If this + storage and retrieval functionality is implemented, the objects are said to be persistent. +

+ To do this link between object world and relational world, and to provide all its features, + QxOrm library requires that C++ classes are registered in QxOrm context. + So we will start this chapter this way : how to register a C++ class in QxOrm context ? +

+ Note : QxOrm library is able to connect to MongoDB database (C++ ODM + Object Document Mapper). +

+

Register a class in QxOrm + context (mapping)

+
+ All C++ classes can be registered in QxOrm context : there is no need to inherit from a super + object, and you can write your methods and accessors without any constraint. + Register a C++ class in QxOrm context means : +
    +
  • in *.h header file (containing class definition) : use + QX_REGISTER_HPP(class_name, base_class, class_version) macro ; +
  • +
  • in *.cpp source file (containing class implementation) : use + QX_REGISTER_CPP(class_name) macro ; +
  • +
  • in *.cpp source file (containing class implementation) : specialize template + function : void qx::register_class<T>(qx::QxClass<T> & t).
  • +
+ Here is an example to show how to define a class named person with 4 properties + registered in QxOrm context : id, firstName, lastName, birthDate + :
+
+ * person.h file :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+/* This macro is necessary to register 'person' class in QxOrm context */
+/* param 1 : the current class to register => 'person' */
+/* param 2 : the base class, if no base class, use the qx trait => 'qx::trait::no_base_class_defined' */
+/* param 3 : the class version used by serialization engine to provide 'ascendant compatibility' */
+
+#endif // _PERSON_H_
+
+
+ * person.cpp file :
+ + + + + + + +
+
#include "precompiled.h"   // Precompiled-header with '#include <QxOrm.h>' and '#include "export.h"'
+#include "person.h"          // Class definition 'person'
+#include <QxOrm_Impl.h>     // Automatic memory leak detection and boost serialization export macro
+
+QX_REGISTER_CPP_MY_TEST_EXE(person)   // This macro is necessary to register 'person' class in QxOrm context
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.setName("t_person");               // 'person' C++ class is mapped to 't_person' database table
+
+  t.id(& person::id, "id");               // Register 'person::id' <=> primary key in your database
+  t.data(& person::firstName, "first_name");      // Register 'person::firstName' property mapped to 'first_name' database column name
+  t.data(& person::lastName, "last_name");  // Register 'person::lastName' property mapped to 'last_name' database column name
+  t.data(& person::birthDate, "birth_date");  // Register 'person::birthDate' property mapped to 'birth_date' database column name
+}}
+
+

+ Note : class methods qx::QxClass<T>::id() and qx::QxClass<T>::data() return an instance of type : qx::IxDataMember + (which is the base class to register a data member). + With this instance, it is possible to customize default behaviour of qx::IxDataMember + class, like for example in the chapter : Register a transient data + member. +

+ Other note : it is also possible to register functions and class methods in QxOrm context + (support static and non static methods) with qx::QxClass<T>::fct_0(), qx::QxClass<T>::fct_1(), etc... + This feature is a part of introspection engine of QxOrm library, more + details in the chapter : Call function dynamically. +

+

Primary key other + than default type "long"

+
+ By default, the unique id (primary key) of a C++ class registered in QxOrm context is defined + as long type (with auto-increment behaviour in database).
+
+ It is possible to define a unique id (primary key) of another type (for example, + QString type) with QX_REGISTER_PRIMARY_KEY macro.
+ This macro specializes qx::trait::get_primary_key<T> template to associate a + primary key type to a C++ class.
+
+ For example, to define a QString primary key for myClass C++ class (mapped to a + database table with a column primary key of type VARCHAR), you have to write : + QX_REGISTER_PRIMARY_KEY(myClass, QString)
+
+ Warning : QX_REGISTER_PRIMARY_KEY macro must be used before + QX_REGISTER_HPP macro in your class definition, otherwise a compilation error + occurs.
+
+ Here is an example with author class of qxBlog tutorial and a QString + primary key type :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+ 
+class author
+{
+public:
+// -- properties
+   QString  m_id;
+   QString  m_name;
+// -- constructor, virtual destructor
+   author() { ; }
+   virtual ~author() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+

+
+

Composite primary + key

+
+ QxOrm supports 'multi-columns primary key'.
+ The class id (primary key) must be defined with following type : +
    +
  • QPair or std::pair to define 2 columns ;
  • +
  • boost::tuple (or std::tuple) to define from 2 columns to 9 columns.
  • +
+ It is necessary to use QX_REGISTER_PRIMARY_KEY() macro to specialize template + and to map class id with multi-columns in database.
+ The list of multi-columns names must be defined with '|' character as separator : + 'column1|column2|column3|etc...'.
+
+ Here is an example with 'author' class from 'qxBlogCompositeKey' sample + project, this class has an id mapped to 3 columns in database :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+
+   QX_REGISTER_FRIEND_CLASS(author)
+
+public:
+
+// -- composite key (multi-column primary key in database)
+   typedef boost::tuple<QString, long, QString> type_composite_key;
+   static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; }
+
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+
+// -- enum
+   enum enum_sex { male, female, unknown };
+
+// -- properties
+   type_composite_key   m_id;
+   QString              m_name;
+   QDate                m_birthdate;
+   enum_sex             m_sex;
+   list_blog            m_blogX;
+
+// -- contructor, virtual destructor
+   author() : m_id("", 0, ""), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+
+// -- methods
+   int age() const;
+
+// -- methods "get" to composite key
+   type_composite_key getId() const    { return m_id; }
+   QString getId_0() const             { return boost::tuples::get<0>(m_id); }
+   long getId_1() const                { return boost::tuples::get<1>(m_id); }
+   QString getId_2() const             { return boost::tuples::get<2>(m_id); }
+
+// -- methods "set" to composite key
+   void setId_0(const QString & s)     { boost::tuples::get<0>(m_id) = s; }
+   void setId_1(long l)                { boost::tuples::get<1>(m_id) = l; }
+   void setId_2(const QString & s)     { boost::tuples::get<2>(m_id) = s; }
+
+};
+
+QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<author::type_composite_key, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/author.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, author::str_composite_key());
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key());
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+

+
+

public or + protected/private data members

+
+ To register private or protected data members in QxOrm context + (qx::register_class<T> function), it's necessary to declare some friend + class.
+ To do that, QxOrm library provides QX_REGISTER_FRIEND_CLASS(myClass) macro.
+ An example can be found in ./test/qxDllSample/dll1/ directory of QxOrm package with + CPerson class :
+
+ + + + + + + +
+
namespace qx {
+namespace test {
+
+class QX_DLL1_EXPORT CPerson : public QObject
+{
+
+   Q_OBJECT
+   QX_REGISTER_FRIEND_CLASS(qx::test::CPerson)
+
+   // etc...
+
+};
+
+} // namespace test
+} // namespace qx
+
+

+
+

Namespace

+
+ If a class is defined in a namespace, a compilation error occurs with QX_REGISTER_HPP + and QX_REGISTER_CPP macros.
+ To avoid this compilation error, it is necessary to use + QX_REGISTER_COMPLEX_CLASS_NAME_HPP and QX_REGISTER_COMPLEX_CLASS_NAME_CPP + macros.
+
+ You can find a sample in ./test/qxDllSample/dll1/ directory of QxOrm package with + CPerson class defined in qx::test namespace :
+
+ + + + + + + +
+
   QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0, qx_test_CPerson)   
+
+
+ QX_REGISTER_COMPLEX_CLASS_NAME... macros require an extra parameter (in above sample : + qx_test_CPerson) to be able to create a global variable. + This global variable is created before your application is started. + This global variable instance registers the class in QxFactory + module (design pattern factory). + A C++ class name cannot contain "::" character, so this is why extra parameter + replaces all "::" characters by "_". +

+
+

Built-in C++ + supported types

+
+ QxOrm library supports all primitive types of C++ standard and Qt framework (numeric, + boolean, string, date/time, container, pointer and smart-pointer, etc...). + Here is an example with a list (non exhaustive) of supported C++ types mapped to database + types (here as SQLite format) : +

+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ Note : it is possible to persist a type not managed by default by QxOrm library. Go to + the chapter Persist custom type for more details + about this feature. +

+ Other note : to map a C++ type to a database type, please go to the chapter Associate a SQL type to a C++ class for more details. +

+
+

Register a transient + data member

+
+ A transient data member is not associated to a column in a database table. + QxDao module doesn't use a + transient property for all requests to database. +

+ Why to register a transient property in QxOrm context ?
+ Register a transient data member in QxOrm context enables other features provided by + QxOrm library on this property : serialization, introspection, etc... +

+ qx::QxClass<T>::data() class method has an optional parameter + named : bool bDao (default value is true). + For example, we add a transient property named age to person class (this + property doesn't have to be stored in database because we already have a birthDate + property) : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name";);
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+  t.data(& person::age, "age", 0, true, false);
+}}
+
+
+ Here is another way to define a transient property with qx::IxDataMember instance : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name";);
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+
+  IxDataMember * pDataMember = t.data(& person::age, "age");
+  pDataMember->setDao(false);
+}}
+
+

+
+
+

Connection to + database

+
+ To configure a connection to database, you can use the singleton class : qx::QxSqlDatabase.
+ Here is an example to connect to a SQLite database named test_qxorm.db : +

+ + + + + + + +
+
   // Init parameters to connect to database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+
+
+ By default, all requests sent from QxOrm library to database are executed using qx::QxSqlDatabase singleton class settings. + For more details about available settings, it is recommended to read QSqlDatabase Qt class + documentation. +

+ Note : qx::QxSqlDatabase singleton class can manage automatically + requests to database in several threads (support multi-threading). +

+ Other note : it is possible to manage your own connection pool to database, and also to + work with several databases : for more details about this feature, please go to the chapter Working with several databases. +

+ Other note : depending on Qt SQL plugin (setDriverName() method), QxOrm library associates automatically a + SQL generator. + This SQL generator is used to manage specific features provided by databases. + All SQL generators inherit from qx::dao::detail::IxSqlGenerator base class : + + + + + + + + +
+
   qx::dao::detail::IxSqlGenerator_ptr pSqlGenerator;
+   pSqlGenerator.reset(new qx::dao::detail::QxSqlGenerator_MSSQLServer());   
+   qx::QxSqlDatabase::getSingleton()->setSqlGenerator(pSqlGenerator);   
+
+

+
+

Persist a C++ instance in + database (insert/update)

+
+ All functions to communicate with databases are located in qx::dao namespace.
+
+ To save a C++ instance (or a list of C++ instances) to database, QxOrm library provides these + functions : + +
+ For example :
+ + + + + + + +
+
   // Create 3 drugs instances
+   // It is possible to use 'boost' and 'Qt' smart pointer : 'boost::shared_ptr', 'QSharedPointer', etc...
+   typedef boost::shared_ptr<drug> drug_ptr;
+   drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1";
+   drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2";
+   drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3";
+
+   // Insert some drugs into a container
+   // It is possible to use many containers from 'std', 'boost', 'Qt' and 'qx::QxCollection<Key, Value>'
+   typedef std::vector<drug_ptr> type_lst_drug;
+   type_lst_drug lst_drug;
+   lst_drug.push_back(d1);
+   lst_drug.push_back(d2);
+   lst_drug.push_back(d3);
+
+   // Insert drugs from container to database
+   // 'id' property of 'd1', 'd2' and 'd3' are auto-updated
+   QSqlError daoError = qx::dao::insert(lst_drug);
+
+   // Modify and update the second drug into database
+   d2->name = "name2 modified";
+   d2->description = "desc2 modified";
+   daoError = qx::dao::update(d2);
+
+
+

+ Note : all functions located in qx::dao namespace are flexible because they accept several types of + parameters : a simple instance, a list of instances, a pointer, a smart-pointer, a list of + pointers, a list of smart-pointers, etc... For example : +
    +
  • my_entity t;     /* ... */     + qx::dao::insert(t);
  • +
  • my_entity * t;     /* ... */     + qx::dao::insert(t);
  • +
  • std::shared_ptr<my_entity> t;     /* ... + */     qx::dao::insert(t);
  • +
  • QList<my_entity> lst;     /* ... */     + qx::dao::insert(lst);
  • +
  • QList<std::shared_ptr<my_entity> > lst;     /* ... + */     qx::dao::insert(lst);
  • +
+ About supported collection types by QxOrm library, please go to the chapter : Supported containers.
+ About supported smart-pointer types by QxOrm library, please go to the chapter : Supported smart pointers.
+

+
+

Delete an instance in + database (delete)

+
+ All functions to communicate with databases are located in qx::dao namespace.
+
+ To delete a C++ instance (or a list of C++ instances) from database, QxOrm library provides + these functions : + +
+ For example :
+ + + + + + + +
+
   // Create a drug instance with id '18'
+   drug d; d.setId(18);
+
+   // Delete the drug with id '18' from database
+   QSqlError daoError = qx::dao::delete_by_id(d);
+
+   // Delete all drugs from database
+   daoError = qx::dao::delete_all<drug>();
+
+

+

Soft delete behaviour + (logical delete)

+
+ A soft delete doesn't remove rows from a database table (this is not a physical delete) : a + new column is added to table definition to flag a row as deleted or not. + This extra column can contain a boolean (1 means row deleted, 0 or NULL means row not + deleted), or can contain deletion date-time (if empty or NULL, row is not deleted). + So it is always possible to enable a row which has been previously deleted : you just have to + put a NULL or empty value in this extra column.
+
+ To define a soft delete behaviour with QxOrm library, you have to use qx::QxSoftDelete class in mapping function + qx::register_class<T>.
+ Here is an example with Bar class containing 2 properties m_id and + m_desc :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<Bar> & t)
+{
+   t.setSoftDelete(qx::QxSoftDelete("deleted_at"));
+
+   t.id(& Bar::m_id, "id");
+   t.data(& Bar::m_desc, "desc");
+}}
+
+
+ SQL queries generated by QxOrm library will take into account this soft delete parameter to + add conditions (don't fetch deleted items, don't delete physically a row, etc...).
+ For example, if you execute this code with Bar class :
+
+ + + + + + + +
+
Bar_ptr pBar; pBar.reset(new Bar());
+pBar->setId(5);
+QSqlError daoError = qx::dao::delete_by_id(pBar);     qAssert(! daoError.isValid());
+qx_bool bDaoExist = qx::dao::exist(pBar);             qAssert(! bDaoExist);
+daoError = qx::dao::delete_all<Bar>();                qAssert(! daoError.isValid());
+long lBarCount = qx::dao::count<Bar>();               qAssert(lBarCount == 0);
+daoError = qx::dao::destroy_all<Bar>();               qAssert(! daoError.isValid());
+
+
+ Then output logs are :
+
+ + + + + + + +
+
[QxOrm] sql query (93 ms) : UPDATE Bar SET deleted_at = '20110617115148615' WHERE id = :id
+[QxOrm] sql query (0 ms) : SELECT Bar.id AS Bar_id_0, Bar.deleted_at FROM Bar WHERE Bar.id = :id 
+                                         AND (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (78 ms) : UPDATE Bar SET deleted_at = '20110617115148724'
+[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM Bar WHERE (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (110 ms) : DELETE FROM Bar
+
+
+ Note : to delete physically a row from database, you have to use these functions : + qx::dao::destroy_by_id() and qx::dao::destroy_all().
+
+ Other note : it is recommended to define an index on deleted_at extra column to + optimize SQL queries execution (better performance). +

+
+
+

Get a C++ instance from + database (fetch)

+
+ All functions to communicate with databases are located in qx::dao namespace.
+
+ To fetch automatically all properties of a C++ instance (or a list of C++ instances) mapped to + database table columns (and several tables if relationships are defined), QxOrm library provides + these functions : + +
+ For example :
+ + + + + + + +
+
   // Fetch drug with id '3' into a new variable
+   drug_ptr d; d.reset(new drug());
+   d->id = 3;
+   QSqlError daoError = qx::dao::fetch_by_id(d);
+
+

+
+

SQL queries

+
+ QxOrm library provides several tools to execute SQL queries to database : + + Note : QxOrm library is based on QtSql module of Qt framework, so it is always possible to call database + using QSqlQuery Qt class if + QxOrm features are not adapted to solve an issue. +

+

Using qx::QxSqlQuery + class (or qx_query alias)

+
+ qx::QxSqlQuery class (or its qx_query typedef) is used + to communicate with database (to filter, to sort, etc.) in 2 different ways : +
    +
  • writing manually a SQL query ;
  • +
  • using C++ methods with a syntax similar to SQL (same concept than the great library SubSonic + for .Net).
  • +
+ With the first method (writing manually SQL query), you can use some optimizations specific + for each database.
+ The second method (using C++ code to build SQL query) binds automatically SQL parameters + without having to deal with qx::QxSqlQuery::bind() function.
+
+ Here is an example with qx::QxSqlQuery class writing manually a SQL query :
+
+ + + + + + + +
+
// Build a SQL query to fetch only 'author' of type 'female'
+qx::QxSqlQuery query("WHERE author.sex = :sex");
+query.bind(":sex", author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* here we can work with the collection provided by database */ }
+
+
+ QxOrm library provides 3 styles to write SQL parameters.
+ This style can be modified for a project using + qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle() method :
+
    +
  • ph_style_2_point_name : "WHERE author.sex = :sex" (default style) ;
  • +
  • ph_style_at_name : "WHERE author.sex = @sex" ;
  • +
  • ph_style_question_mark : "WHERE author.sex = ?".
  • +
+ Here is the same example using qx::QxSqlQuery class methods to generate SQL query + automatically :
+
+ + + + + + + +
+
// Build a SQL query to fetch only 'author' of type 'female'
+qx_query query;
+query.where("author.sex").isEqualTo(author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* here we can work with the collection provided by database */ }
+
+
+ With C++ methods of qx::QxSqlQuery class, you don't have to bind any SQL parameter, + and the syntax is similar to real SQL.
+ All SQL parameters will be provided to database automatically with the following style : + qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle().
+
+ Here is another example using several qx::QxSqlQuery class methods :
+
+ + + + + + + +
+
qx_query query;
+query.where("sex").isEqualTo(author::female)
+     .and_("age").isGreaterThan(38)
+     .or_("last_name").isNotEqualTo("Dupont")
+     .or_("first_name").like("Alfred")
+     .and_OpenParenthesis("id").isLessThanOrEqualTo(999)
+     .and_("birth_date").isBetween(date1, date2)
+     .closeParenthesis()
+     .or_("id").in(50, 999, 11, 23, 78945)
+     .and_("is_deleted").isNotNull()
+     .orderAsc("last_name", "first_name", "sex")
+     .limit(50, 150);
+
+
+ This code will generate following SQL query for MySQL, PostgreSQL and + SQLite databases (for Oracle and Microsoft SQL Server, there is a + specific process for limit() method) :
+
+ + + + + + + +
+
WHERE sex = :sex_1_0 
+AND age > :age_3_0 
+OR last_name <> :last_name_5_0 
+OR first_name LIKE :first_name_7_0 
+AND ( id <= :id_10_0 AND birth_date BETWEEN :birth_date_12_0_1 AND :birth_date_12_0_2 ) 
+OR id IN (:id_15_0_0, :id_15_0_1, :id_15_0_2, :id_15_0_3, :id_15_0_4) 
+AND is_deleted IS NOT NULL 
+ORDER BY last_name ASC, first_name ASC, sex ASC 
+LIMIT :limit_rows_count_19_0 OFFSET :offset_start_row_19_0
+
+
+ Here is the list of all functions available to use qx::QxSqlQuery class (or its + qx_query typedef) :
+
+ + + + + + + +
+
// with functions into namespace qx::dao
+qx::dao::count<T>()
+qx::dao::fetch_by_query<T>()
+qx::dao::update_by_query<T>()
+qx::dao::delete_by_query<T>()
+qx::dao::destroy_by_query<T>()
+qx::dao::fetch_by_query_with_relation<T>()
+qx::dao::fetch_by_query_with_all_relation<T>()
+qx::dao::update_by_query_with_relation<T>()
+qx::dao::update_by_query_with_all_relation<T>()
+qx::dao::update_optimized_by_query<T>()
+
+// with qx::QxSession class
+qx::QxSession::count<T>()
+qx::QxSession::fetchByQuery<T>()
+qx::QxSession::update<T>()
+qx::QxSession::deleteByQuery<T>()
+qx::QxSession::destroyByQuery<T>()
+
+// with qx::QxRepository<T> class
+qx::QxRepository<T>::count()
+qx::QxRepository<T>::fetchByQuery()
+qx::QxRepository<T>::update()
+qx::QxRepository<T>::deleteByQuery()
+qx::QxRepository<T>::destroyByQuery()
+
+
+ Note : these functions have 2 other optionals parameters : +
    +
  • const QStringList & columns : to select columns to fetch (by default, all + columns are fetched) ;
  • +
  • const QStringList & relation : to select relationships to fetch + (one-to-one, one-to-many, many-to-one and many-to-many + defined in void qx::register_class<T>() mapping function per class), by + default there is no relation fetched.
  • +
+
+
+

Using standard SQL or + stored procedure

+
+ QxOrm library provides 2 functions to execute a stored procedure or a custom SQL query : + + The first parameter of these functions, of qx::QxSqlQuery type (or qx_query), contains the stored + procedure or the custom SQL query to execute.
+ For more information about qx::QxSqlQuery class, please read this chapter : Using qx::QxSqlQuery class (or qx_query alias)
+
+ qx::dao::execute_query<T>() function is a template + function : T type must be registered in QxOrm context (qx::register_class<T> + function).
+ All datas returned by the stored procedure or the custom SQL query which could be associated + with members of the C++ class (of T type) will be fetched automatically.
+ An automatic search is done on the name of each fields returned by the query.
+ Here is an example from qxBlog project of QxOrm package :
+
+ + + + + + + +
+
// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+qx_query testStoredProcBis("SELECT * FROM author");
+daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+qx::dump(authorX);
+
+

+ qx::dao::call_query() + function is not a template function : you have to iterate over each result using qx::QxSqlQuery class (or qx_query).
+ To get an output value parameter (must be passed as QSql::Out or QSql::InOut) + returned by a stored procedure, just call the following method : QVariant + qx::QxSqlQuery::boundValue(const QString & sKey) const;.
+
+ To iterate over all resultset, just use the following methods : +
    +
  • long qx::QxSqlQuery::getSqlResultRowCount() const;
  • +
  • long qx::QxSqlQuery::getSqlResultColumnCount() const;
  • +
  • QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const;
  • +
  • QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) + const;
  • +
  • QVector qx::QxSqlQuery::getSqlResultAllColumns() const;
  • +
  • void qx::QxSqlQuery::dumpSqlResult();
  • +
+ Here is an example using qx::dao::call_query() function :
+
+ + + + + + + +
+
qx_query query("CALL MyStoredProc(:param1, :param2)");
+query.bind(":param1", "myValue1");
+query.bind(":param2", 5024, QSql::InOut);
+QSqlError daoError = qx::dao::call_query(query);
+QVariant vNewValue = query.boundValue(":param2");
+query.dumpSqlResult();
+
+

+
+
+

Transactions (commit, + rollback, session)

+
+ A database transaction is a sequence of operations performed as a single + logical unit of work :
+
    +
  • if no error occurred during the execution of the transaction, then the system + commits the transaction. +
  • +
  • if an error occurs during the transaction, or if the user specifies a rollback + operation, then the data manipulations within the transaction are not persisted to the + database.
  • +
+ qx::QxSession + class of QxOrm library is designed to manage automatically database transactions (using C++ RAII) :
+
+ + + + + + + +
+
{ // Start a scope where a new session is instantiated
+
+  // Create a session : a valid database connection by thread is automatically assigned to the session and a transaction is opened
+  qx::QxSession session;
+
+  // Execute some operations with database (using += operator of qx::QxSession class and session database connection)
+  session += qx::dao::insert(my_object, session.database());
+  session += qx::dao::update(my_object, session.database());
+  session += qx::dao::fetch_by_id(my_object, session.database());
+  session += qx::dao::delete_by_id(my_object, session.database());
+
+  // If the session is not valid (so an error occured) => display first error
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
+
+
+ Note : a session can throw a qx::dao::sql_error exception when a SQL error occured (by default, + there is no exception). You can setup this feature using : +
    +
  • qx::QxSession constructor (for a specific session) ;
  • +
  • qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b) parameter (for all + sessions).
  • +
+ Other note : don't forget to pass the session database connection to each + qx::dao::xxx functions (using session.database() method).
+ Moreover, you can manage your own database connection (from a connection pool for example) using + constructor of qx::QxSession class.
+
+ qx::QxSession class provides persistent methods to perform CRUD operations.
+ Here is the same example using qx::QxSession class methods instead of qx::dao + functions :
+
+ + + + + + + +
+
{ // Start a scope where a new session is instantiated
+
+  // Create a session : a valid database connection by thread is automatically assigned to the session and a transaction is opened
+  qx::QxSession session;
+
+  // Execute some operations with database
+  session.insert(my_object);
+  session.update(my_object);
+  session.fetchById(my_object);
+  session.deleteById(my_object);
+
+  // If the session is not valid (so an error occured) => display first error
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error)
+
+

+
+

Relationships

+
+ QxOrm library provides a powerful relationship engine to define easily : + + Note : a full tutorial about relationships based on + qxBlog sample project (source code in QxOrm package) is available. +

+

one-to-many (1-n) +

+
+ A one-to-many (1-n) relationship is defined with method : qx::QxClass<T>::relationOneToMany(). + This method returns an instance of qx::IxSqlRelation type (which is the base class to register a + relationship) and take 3 parameters : +
    +
  • V U::* pData : reference to the class data member ;
  • +
  • const QString & sKey : unique key associated to the relationship ;
  • +
  • const QString & sForeignKey : foreign key defined in the linked class/table. +
  • +
+
+ For example : imagine an author (a person) who can write several blog : + we will show how to define a one-to-many relationship.
+ Here are the 2 tables in database :
+
+ qxBlog.table.author
+
+ author.h file :
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- properties
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- constructor, virtual destructor
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- methods
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ author.cpp file :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+

+
+

many-to-one (n-1) +

+
+ A many-to-one (n-1) relationship is defined with method : qx::QxClass<T>::relationManyToOne(). + This method returns an instance of qx::IxSqlRelation type (which is the base class to register a + relationship) and take 2 parameters : +
    +
  • V U::* pData : reference to the class data member ;
  • +
  • const QString & sKey : unique key associated to the relationship (mapped to a + table column in database) ;
  • +
+
+ For example : a comment is associated to a blog and a blog can + contain several comment : we will show how to define a many-to-one + relationship.
+ Here are the 2 tables in database :
+
+ qxBlog.table.comment
+
+ comment.h file :
+ + + + + + + +
+
#ifndef _QX_BLOG_COMMENT_H_
+#define _QX_BLOG_COMMENT_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT comment
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+// -- properties
+   long        m_id;
+   QString     m_text;
+   QDateTime   m_dt_create;
+   blog_ptr    m_blog;
+// -- constructor, virtual destructor
+   comment() : m_id(0) { ; }
+   virtual ~comment() { ; }
+};
+
+QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<comment> comment_ptr;
+typedef QList<comment_ptr> list_comment;
+
+#endif // _QX_BLOG_COMMENT_H_
+
+
+
+ comment.cpp file :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/comment.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(comment)
+
+namespace qx {
+template <> void register_class(QxClass<comment> & t)
+{
+   t.id(& comment::m_id, "comment_id");
+
+   t.data(& comment::m_text, "comment_text");
+   t.data(& comment::m_dt_create, "date_creation");
+
+   t.relationManyToOne(& comment::m_blog, "blog_id");
+}}
+
+
+

+
+

many-to-many + (n-n)

+
+ A many-to-many (n-n) relationship is defined with method : qx::QxClass<T>::relationManyToMany(). + This method returns an instance of qx::IxSqlRelation type (which is the base class to register a + relationship) and take 5 parameters : +
    +
  • V U::* pData : reference to the class data member ;
  • +
  • const QString & sKey : unique key associated to the relationship ;
  • +
  • const QString & sExtraTable : extra table name to store id of each side of + relationship ;
  • +
  • const QString & sForeignKeyOwner : foreign key in extra table linked to current + class ;
  • +
  • const QString & sForeignKeyDataType : foreign key in extra table linked to + other class.
  • +
+
+ For example : a category embed several blog and a blog can belong + to several category : we will show how to define a many-to-many + relationship. + A n-n relationship requires an extra table to store id of each side of + relationship.
+ Here are the 3 tables in database :
+
+ qxBlog.table.category
+
+ category.h file :
+ + + + + + + +
+
#ifndef _QX_BLOG_CATEGORY_H_
+#define _QX_BLOG_CATEGORY_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT category
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef qx::QxCollection<long, blog_ptr> list_blog;
+// -- properties
+   long        m_id;
+   QString     m_name;
+   QString     m_desc;
+   list_blog   m_blogX;
+// -- constructor, virtual destructor
+   category() : m_id(0) { ; }
+   virtual ~category() { ; }
+};
+
+QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0)
+
+typedef QSharedPointer<category> category_ptr;
+typedef qx::QxCollection<long, category_ptr> list_category;
+
+#endif // _QX_BLOG_CATEGORY_H_
+
+
+
+ category.cpp file :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/category.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(category)
+
+namespace qx {
+template <> void register_class(QxClass<category> & t)
+{
+   t.id(& category::m_id, "category_id");
+
+   t.data(& category::m_name, "name");
+   t.data(& category::m_desc, "description");
+
+   t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id");
+}}
+
+
+

+
+

one-to-one (1-1) +

+
+ A one-to-one (1-1) relationship links 2 entities which share the same database id. + A one-to-one (1-1) relationship is defined with method : qx::QxClass<T>::relationOneToOne(). + This method returns an instance of qx::IxSqlRelation type (which is the base class to register a + relationship) and take 2 parameters : +
    +
  • V U::* pData : reference to the class data member ;
  • +
  • const QString & sKey : unique key associated to the relationship ;
  • +
+
+ For example : imagine a person table and an author table : an + author is also a person, so these 2 tables could share the same id in database. + Here are the 2 tables in database (with person_id == author_id) :
+
+ qxBlog.table.person +


+
+

Fetch + relationships

+
+ QxOrm library supports 4 kind of relationships to link C++ classes registered in QxOrm + context : one-to-one, one-to-many, many-to-one and + many-to-many.
+ For more details to define relationships, you can take a look at qxBlog tutorial.
+ We will explain here how to fetch datas from many tables (QxDao module, functions of + qx::dao namespace) : + + The first parameter of fetch_by_id_with_relation, fetch_all_with_relation + and fetch_by_query_with_relation functions is the list of relationships to + fetch.
+ This list of relationships can contain these items : +
    +
  • relation key : each relation is associated to a key defined in + qx::register_class<T> mapping function ; +
  • +
  • "*" keyword means "fetch all relationships defined in + qx::register_class<T> function (1 level of relationships)" ;
  • +
  • "->" keyword means "LEFT OUTER JOIN" join type between 2 tables ;
  • +
  • ">>" keyword means "INNER JOIN" join type between 2 tables.
  • +
+ Note : using "*" keyword to indicate "fetch all relationships defined into + qx::register_class<T> function", following calls are similar : +
    +
  • qx::dao::fetch_by_id_with_relation("*", ...) == + qx::dao::fetch_by_id_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_by_query_with_relation("*", ...) == + qx::dao::fetch_by_query_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_all_with_relation("*", ...) == + qx::dao::fetch_all_with_all_relation(...). +
  • +
+
+ Example : from qxBlog tutorial, it's possible to fetch all these datas with only 1 + query :
+
+ 1- fetch a blog and its author ;
+ 2- for the author fetched, fetch all blog he wrote ;
+ 3- for each blog written by author fetched, fetch all comment + associated.
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("author_id->list_blog->list_comment", my_blog);
+
+
+ This code generates following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Another example : it's also possible to create a list of relationships to fetch, like + this :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QStringList relation;
+relation << "author_id->list_blog->list_comment";
+relation << "author_id->list_blog->list_category";
+relation << "list_comment";
+relation << "list_category";
+QSqlError daoError = qx::dao::fetch_by_id_with_relation(relation, my_blog);
+
+
+ This code generates following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, 
+       category_7.category_id AS category_7_category_id_0, category_7.name AS category_7_name_0, category_7.description AS category_7_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN category_blog category_blog_7 ON blog.blog_id = category_blog_7.blog_id 
+LEFT OUTER JOIN category category_7 ON category_blog_7.category_id = category_7.category_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Another example : to fetch all relationships per level, "*" keyword must be used.
+ So to fetch all relationships on 3 levels, we can write :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("*->*->*", my_blog);
+
+
+ This code generates following SQL query : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, blog_2.author_id AS blog_2_author_id_0_2, 
+       author_3.author_id AS author_3_author_id_0, author_3.name AS author_3_name_0, author_3.birthdate AS author_3_birthdate_0, author_3.sex AS author_3_sex_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, comment_6.blog_id AS comment_6_blog_id_0_6, 
+       blog_7.blog_id AS blog_7_blog_id_0, blog_7.blog_text AS blog_7_blog_text_0, blog_7.date_creation AS blog_7_date_creation_0, blog_7.author_id AS blog_7_author_id_0_7, 
+       author_8.author_id AS author_8_author_id_0, author_8.name AS author_8_name_0, author_8.birthdate AS author_8_birthdate_0, author_8.sex AS author_8_sex_0, 
+       comment_9.comment_id AS comment_9_comment_id_0, comment_9.blog_id AS comment_9_blog_id_0, comment_9.comment_text AS comment_9_comment_text_0, comment_9.date_creation AS comment_9_date_creation_0, 
+       category_10.category_id AS category_10_category_id_0, category_10.name AS category_10_name_0, category_10.description AS category_10_description_0, 
+       category_11.category_id AS category_11_category_id_0, category_11.name AS category_11_name_0, category_11.description AS category_11_description_0, 
+       blog_12.blog_id AS blog_12_blog_id_0, blog_12.blog_text AS blog_12_blog_text_0, blog_12.date_creation AS blog_12_date_creation_0, blog_12.author_id AS blog_12_author_id_0_12, 
+       author_13.author_id AS author_13_author_id_0, author_13.name AS author_13_name_0, author_13.birthdate AS author_13_birthdate_0, author_13.sex AS author_13_sex_0, 
+       comment_14.comment_id AS comment_14_comment_id_0, comment_14.blog_id AS comment_14_blog_id_0, comment_14.comment_text AS comment_14_comment_text_0, comment_14.date_creation AS comment_14_date_creation_0, 
+       category_15.category_id AS category_15_category_id_0, category_15.name AS category_15_name_0, category_15.description AS category_15_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN author author_3 ON author_3.author_id = blog_2.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN blog blog_7 ON blog_7.blog_id = comment_6.blog_id 
+LEFT OUTER JOIN author author_8 ON author_8.author_id = blog_7.author_id 
+LEFT OUTER JOIN comment comment_9 ON comment_9.blog_id = blog_7.blog_id 
+LEFT OUTER JOIN category_blog category_blog_10 ON blog_7.blog_id = category_blog_10.blog_id 
+LEFT OUTER JOIN category category_10 ON category_blog_10.category_id = category_10.category_id 
+LEFT OUTER JOIN category_blog category_blog_11 ON blog.blog_id = category_blog_11.blog_id 
+LEFT OUTER JOIN category category_11 ON category_blog_11.category_id = category_11.category_id 
+LEFT OUTER JOIN category_blog category_blog_12 ON category_11.category_id = category_blog_12.category_id 
+LEFT OUTER JOIN blog blog_12 ON category_blog_12.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN author author_13 ON author_13.author_id = blog_12.author_id 
+LEFT OUTER JOIN comment comment_14 ON comment_14.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN category_blog category_blog_15 ON blog_12.blog_id = category_blog_15.blog_id 
+LEFT OUTER JOIN category category_15 ON category_blog_15.category_id = category_15.category_id 
+WHERE blog.blog_id = :blog_id
+
+

+
+

Select columns + fetching relationships and define custom SQL alias

+
+ It is sometimes necessary to not request all table columns to optimize : indeed, selecting + columns really used by a process limits network traffic between database and C++ application, + so performance are improved.
+
+ About relationships, QxOrm library provides a syntax to select columns to fetch, using format + : my_relation { col_1, col_2, etc... }. + By default, if this syntax is not used, then QxOrm library fetches all columns.
+
+ For example : imagine a query to fetch : +
    +
  • only blog_text column of blog table ;
  • +
  • only name and birthdate columns of author table ;
  • +
  • only comment_text column of comment table.
  • +
+ + + + + + + +
+
   // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... }
+   list_blog lstBlogComplexRelation;
+   QStringList relations = QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text }";
+   QSqlError daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation);
+
+   qx::dump(lstBlogComplexRelation);
+   qAssert(lstBlogComplexRelation.size() > 0);
+   qAssert(lstBlogComplexRelation[0]->m_text != ""); // Fetched
+   qAssert(lstBlogComplexRelation[0]->m_dt_creation.isNull()); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched
+   qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0);
+   qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched
+
+
+ Note : another syntax is available to select columns to not fetch : my_relation -{ + col_1, col_2, etc... }. +

+ Other note : you can also define a custom SQL alias per relation. + This is useful to write your WHERE conditions in the SQL query. + A SQL alias can be defined between characters < >. +

+ Example : here is a fetch with relationships example defining some SQL aliases per + relation : +

+ + + + + + + +
+
list_blog lstBlogComplexRelation3;
+QStringList relations;
+relations << "<blog_alias> { blog_text }";
+relations << "author_id <author_alias> { name, birthdate }";
+relations << "list_comment <list_comment_alias> { comment_text } -> blog_id <blog_alias_2> -> * <..._my_alias_suffix>";
+QSqlError daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation3);
+qx::dump(lstBlogComplexRelation3);
+
+

+ This code generates following SQL query : +
+
+
SELECT blog_alias.blog_id AS blog_alias_blog_id_0, blog_alias.blog_text AS blog_alias_blog_text_0, blog_alias.author_id AS blog_alias_author_id_0, author_alias.author_id AS author_alias_author_id_0, author_alias.name AS author_alias_name_0, author_alias.birthdate AS author_alias_birthdate_0, list_comment_alias.comment_id AS list_comment_alias_comment_id_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0, list_comment_alias.comment_text AS list_comment_alias_comment_text_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0_2, blog_alias_2.blog_id AS blog_alias_2_blog_id_0, blog_alias_2.blog_text AS blog_alias_2_blog_text_0, blog_alias_2.date_creation AS blog_alias_2_date_creation_0, blog_alias_2.author_id AS blog_alias_2_author_id_0_3, author_my_alias_suffix.author_id AS author_my_alias_suffix_author_id_0, author_my_alias_suffix.name AS author_my_alias_suffix_name_0, author_my_alias_suffix.birthdate AS author_my_alias_suffix_birthdate_0, author_my_alias_suffix.sex AS author_my_alias_suffix_sex_0, comment_my_alias_suffix.comment_id AS comment_my_alias_suffix_comment_id_0, comment_my_alias_suffix.blog_id AS comment_my_alias_suffix_blog_id_0, comment_my_alias_suffix.comment_text AS comment_my_alias_suffix_comment_text_0, comment_my_alias_suffix.date_creation AS comment_my_alias_suffix_date_creation_0, comment_my_alias_suffix.blog_id AS comment_my_alias_suffix_blog_id_0_5, category_my_alias_suffix.category_id AS category_my_alias_suffix_category_id_0, category_my_alias_suffix.name AS category_my_alias_suffix_name_0, category_my_alias_suffix.description AS category_my_alias_suffix_description_0
+  FROM blog AS blog_alias
+  LEFT OUTER JOIN author author_alias ON author_alias.author_id = blog_alias.author_id
+  LEFT OUTER JOIN comment list_comment_alias ON list_comment_alias.blog_id = blog_alias.blog_id
+  LEFT OUTER JOIN blog blog_alias_2 ON blog_alias_2.blog_id = list_comment_alias.blog_id
+  LEFT OUTER JOIN author author_my_alias_suffix ON author_my_alias_suffix.author_id = blog_alias_2.author_id
+  LEFT OUTER JOIN comment comment_my_alias_suffix ON comment_my_alias_suffix.blog_id = blog_alias_2.blog_id
+  LEFT OUTER JOIN category_blog category_blog_6 ON blog_alias_2.blog_id = category_blog_6.blog_id
+  LEFT OUTER JOIN category category_my_alias_suffix ON category_blog_6.category_id = category_my_alias_suffix.category_id
+
+

+
+

Add SQL query inside + LEFT OUTER JOIN / INNER JOIN

+
+ qx::QxSqlQuery + class (or its qx_query alias) provides the following method : +

+ + + + + + + +
+
QxSqlQuery & QxSqlQuery::addJoinQuery(const QString & relationKeyOrAlias, const QxSqlQuery & joinQuery);
+
+

+ The qx::QxSqlQuery::addJoinQuery() method inserts SQL sub-queries inside LEFT OUTER + JOIN / INNER JOIN.
+ For example : +

+ + + + + + + +
+
// Test to add join SQL sub-queries (inside LEFT OUTER JOIN or INNER JOIN)
+list_blog lstBlogWithJoinQueries;
+qx_query query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1");
+query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL");
+query.addJoinQuery("author_alias", qx_query().freeText("AND author_alias.sex = :sex", QVariantList() << author::female));
+daoError = qx::dao::fetch_by_query_with_relation(QStringList() << "<blog_alias> { blog_text }" << "author_id <author_alias> { name, birthdate, sex }" 
+                                                               << "list_comment <list_comment_alias> { comment_text }", query, lstBlogWithJoinQueries);
+qx::dump(lstBlogWithJoinQueries);
+qAssert(lstBlogWithJoinQueries.size() > 0);
+qAssert(lstBlogWithJoinQueries[0]->m_text == "update blog_text_1");
+qAssert(lstBlogWithJoinQueries[0]->m_author->m_sex == author::female);
+
+

+ Above C++ code will build following SQL query : +

+
+
SELECT blog_alias.blog_id AS blog_alias_blog_id_0, blog_alias.blog_text AS blog_alias_blog_text_0, blog_alias.author_id AS blog_alias_author_id_0, author_alias.author_id AS author_alias_author_id_0, author_alias.name AS author_alias_name_0, author_alias.birthdate AS author_alias_birthdate_0, author_alias.sex AS author_alias_sex_0, list_comment_alias.comment_id AS list_comment_alias_comment_id_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0, list_comment_alias.comment_text AS list_comment_alias_comment_text_0
+  FROM blog AS blog_alias
+  LEFT OUTER JOIN author author_alias ON (author_alias.author_id = blog_alias.author_id
+      AND author_alias.sex = :sex)
+  LEFT OUTER JOIN comment list_comment_alias ON (list_comment_alias.blog_id = blog_alias.blog_id
+      AND list_comment_alias.comment_text IS NOT NULL)
+  WHERE blog_alias.blog_text = :blog_alias_blog_text_1_0
+
+

+
+
+

Supported containers +

+
+ QxOrm library supports several containers provided by Qt, boost and std standard library. + QxOrm library provides also its own container, named qx::QxCollection, especially designed to store data fetched from + database. + So the developer is not restricted : QxOrm library offers a large choice of containers. +

+

Qt containers

+
+ + + + + + + +
+
+  QList<T>  
+  QVector<T>  
+  QSet<T>  
+  QLinkedList<T>  
+  QHash<Key, Value>  
+  QMap<Key, Value>  
+  QMultiHash<Key, Value>  
+  QMultiMap<Key, Value>  
+
+
+
+
+

Boost containers +

+
+ + + + + + + +
+
+  boost::unordered_map<Key, Value>  
+  boost::unordered_set<T>  
+  boost::unordered_multimap<Key, Value>  
+  boost::unordered_multiset<T>  
+
+
+
+
+

std containers +

+
+ + + + + + + +
+
+  std::list<T>  
+  std::vector<T>  
+  std::set<T>  
+  std::map<Key, Value>  
+
+  std::unordered_map<Key, Value>  
+  std::unordered_set<T>  
+  std::unordered_multimap<Key, Value>  
+  std::unordered_multiset<T>  
+
+
+
+
+

qx::QxCollection +

+
+ There are several containers provided by stl, boost and Qt + libraries.
+ So, it is legitimate to ask this question : what is qx::QxCollection<Key, Value> + for ?
+ qx::QxCollection<Key, Value> is a new container + (based on the excellent boost::multi_index_container library) which has following + features : +
    +
  • keeps insertion order of items in the list ; +
  • +
  • quick access to an item by its index : is equivalent to std::vector<T> or + QList<T> for example ; +
  • +
  • quick access to an item by a key (hash-map) : is equivalent to QHash<Key, + Value> or boost::unordered_map<Key, Value> for example ; +
  • +
  • sort by Key type and by Value type ; +
  • +
  • thread-safe. +
  • +
+ Note : qx::QxCollection<Key, Value> is compatible with the foreach + macro provided by Qt library and the BOOST_FOREACH macro provided by boost library.
+ However, each element returned by these 2 macros matches to an object of std::pair<Key, + Value> type.
+ To get a more natural and more readable result, it is advised to use the _foreach + macro : this macro uses BOOST_FOREACH for all containers except for + qx::QxCollection<Key, Value>.
+ In this case, the returned element matches to the Value type (cf. sample).
+ _foreach macro is compatible with all containers (stl, Qt, + boost...) since it uses BOOST_FOREACH macro.

+ + Additional note : qx::QxCollection<Key, Value> is especially designed to + receive data resulting from a database.
+ Indeed, these data can be sorted (using ORDER BY in a SQL query for example), it is + thus important to keep insertion order of items in the list.
+ Furthermore, each data resulting from a database has a unique id : it is thus important to be + able to access quickly to an item based on this single identifier (hash-map).

+ + Sample :
+ + + + + + + +
+
/* definition of drug class with 3 properties : code, name, description */
+class drug { public: QString code; QString name; QString desc; };
+
+/* smart pointer of drug */
+typedef boost::shared_ptr<drug> drug_ptr;
+
+/* collection of drugs by code */
+qx::QxCollection<QString, drug_ptr> lstDrugs;
+
+/* create 3 new drugs */
+drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1";
+drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2";
+drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3";
+
+/* insert drugs into the collection */
+lstDrugs.insert(d1->code, d1);
+lstDrugs.insert(d2->code, d2);
+lstDrugs.insert(d3->code, d3);
+
+/* iterate with '_foreach' keyword */
+_foreach(drug_ptr p, lstDrugs)
+{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); }
+
+/* iterate with 'for' keyword */
+for (long l = 0; l < lstDrugs.count(); ++l)
+{
+   drug_ptr p = lstDrugs.getByIndex(l);
+   QString code = lstDrugs.getKeyByIndex(l);
+   qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc);
+}
+
+/* iterate with 'QxCollectionIterator' java style */
+qx::QxCollectionIterator<QString, drug_ptr> itr(lstDrugs);
+while (itr.next())
+{
+   QString code = itr.key();
+   qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc);
+}
+
+/* sort ascending by key and sort descending by value */
+lstDrugs.sortByKey(true);
+lstDrugs.sortByValue(false);
+
+/* access drug by code */
+drug_ptr p = lstDrugs.getByKey("code2");
+
+/* access drug by index */
+drug_ptr p = lstDrugs.getByIndex(2);
+
+/* test if drug exists and if collection is empty */
+bool bExist = lstDrugs.exist("code3");
+bool bEmpty = lstDrugs.empty();
+
+/* remove the second drug from collection */
+lstDrugs.removeByIndex(2);
+
+/* remove the drug with "code3" */
+lstDrugs.removeByKey("code3");
+
+/* clear the collection */
+lstDrugs.clear();
+
+

+
+
+

Supported smart + pointers

+
+ QxOrm library supports several smart pointers provided by Qt, boost and std standard library. + QxOrm library provides also its own smart pointer, named qx::dao::ptr, which provides new features when used with qx::dao functions. + So the developer is not restricted : QxOrm library offers a large choice of smart pointers. +

+

Qt smart pointers +

+
+ + + + + + + +
+
+  QSharedPointer<T>  
+  QScopedPointer<T>  
+  QWeakPointer<T>  
+  QSharedDataPointer<T>  
+
+
+
+
+

Boost smart + pointers

+
+ + + + + + + +
+
+  boost::shared_ptr<T>  
+  boost::intrusive_ptr<T>  
+  boost::scoped_ptr<T>  
+  boost::weak_ptr<T>  
+
+
+
+
+

std smart + pointers

+
+ + + + + + + +
+
+  std::shared_ptr<T>  
+  std::unique_ptr<T>  
+  std::weak_ptr<T>  
+
+
+
+
+

qx::dao::ptr

+
+ QxOrm library can be used with smart-pointers provided by std, boost and + Qt libraries.
+ QxOrm smart-pointer is based on QSharedPointer and provides new features with + 'qx::dao::...' functions.
+ qx::dao::ptr<T> 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<T> can also be used with the function + 'qx::dao::update_optimized()' to update in database only properties changed.
+ qx::dao::ptr<T> can be used with a simple object and with many containers : + stl, boost, Qt and qx::QxCollection<Key, Value>.
+
+ Sample :
+ + + + + + + +
+
   // Test 'isDirty()' method
+   qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(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<author_ptr> > type_lst_author_test_is_dirty;
+
+   type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+   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);
+
+

+
+
+

Triggers

+
+ With QxOrm Triggers, it is possible to execute custom process before and/or after + an insert, update or delete query in database.
+ You can find a sample in ./test/qxDllSample/dll2/ directory of QxOrm package with + BaseClassTrigger class.
+ BaseClassTrigger sample class contains 5 properties : m_id, m_dateCreation, + m_dateModification, m_userCreation and m_userModification.
+ In the following example, each property will be automatically auto-updated for all derived + classes from BaseClassTrigger (see Foo class and Bar class in the same + project).
+ It is necessary to specialize 'qx::dao::detail::QxDao_Trigger<T>' template to work + with this feature.
+
+ + + + + + + +
+
#ifndef _QX_BASE_CLASS_TRIGGER_H_
+#define _QX_BASE_CLASS_TRIGGER_H_
+
+class QX_DLL2_EXPORT BaseClassTrigger
+{
+
+   QX_REGISTER_FRIEND_CLASS(BaseClassTrigger)
+
+protected:
+
+   long        m_id;
+   QDateTime   m_dateCreation;
+   QDateTime   m_dateModification;
+   QString     m_userCreation;
+   QString     m_userModification;
+
+public:
+
+   BaseClassTrigger() : m_id(0)  { ; }
+   virtual ~BaseClassTrigger()   { ; }
+
+   long getId() const                     { return m_id; }
+   QDateTime getDateCreation() const      { return m_dateCreation; }
+   QDateTime getDateModification() const  { return m_dateModification; }
+   QString getUserCreation() const        { return m_userCreation; }
+   QString getUserModification() const    { return m_userModification; }
+
+   void setId(long l)                              { m_id = l; }
+   void setDateCreation(const QDateTime & dt)      { m_dateCreation = dt; }
+   void setDateModification(const QDateTime & dt)  { m_dateModification = dt; }
+   void setUserCreation(const QString & s)         { m_userCreation = s; }
+   void setUserModification(const QString & s)     { m_userModification = s; }
+
+   void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
+   void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
+
+};
+
+QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0)
+
+namespace qx {
+namespace dao {
+namespace detail {
+
+template <>
+struct QxDao_Trigger<BaseClassTrigger>
+{
+
+   static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeInsert(dao); } }
+   static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeUpdate(dao); } }
+   static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onBeforeFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+
+};
+
+} // namespace detail
+} // namespace dao
+} // namespace qx
+
+#endif // _QX_BASE_CLASS_TRIGGER_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/BaseClassTrigger.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger)
+
+namespace qx {
+template <> void register_class(QxClass<BaseClassTrigger> & t)
+{
+   IxDataMember * pData = NULL;
+
+   pData = t.id(& BaseClassTrigger::m_id, "id");
+
+   pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation");
+   pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification");
+   pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation");
+   pData = t.data(& BaseClassTrigger::m_userModification, "user_modification");
+}}
+
+void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateCreation = QDateTime::currentDateTime();
+   m_dateModification = QDateTime::currentDateTime();
+   m_userCreation = "current_user_1";
+   m_userModification = "current_user_1";
+}
+
+void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateModification = QDateTime::currentDateTime();
+   m_userModification = "current_user_2";
+}
+
+
+

+
+

Validators

+
+ QxValidator + module of QxOrm library provides a validation engine for classes registered in QxOrm + context.
+ To use this validation engine, you have to define your constraints into the mapping function per + class : void qx::register_class<T>.
+ If for an instance of class, at least one constraint violation is detected, then the instance is + invalid : the object cannot be saved into database (INSERT or UPDATE).
+
+ It's also possible to use QxValidator module to validate an instance on the presentation + layer : if some datas from a user are invalids, an error message can be displayed, and it's not + necessary to try to send the instance to the data access layer.
+ The validation process can be executed in several layers of your application without having to + duplicate any of these rules (presentation layer, data access layer).
+
+ Here is a description of some classes defined in QxValidator module : +
    +
  • qx::IxValidator : each constraint defined in void + qx::register_class<T> function is associated with an interface of + qx::IxValidator type ; +
  • +
  • qx::IxValidatorX : the list of constraints is associated with an + interface of qx::IxValidatorX type. You can iterate over this collection during + program execution : it could be interesting for example to generate DDL SQL schema and to + take into account some validation rules into database (read the chapter : Generate database DDL SQL schema) ;
  • +
  • qx::QxInvalidValueX : when an instance is invalid, list of + constraints violation are inserted into a qx::QxInvalidValueX collection ;
  • +
  • qx::QxInvalidValue : each item into this collection is a + qx::QxInvalidValue type and contains an error message (description to explain why + the instance is not valid). +
  • +
+ QxValidator module manages automatically class inheritance : each constraint defined into + a base class is checked during validation process of a derived class.
+
+ Here is an example using QxValidator module with a 'person' class :
+
+ * 'person.h' file :
+ + + + + + + +
+
#ifndef _CLASS_PERSON_H_
+#define _CLASS_PERSON_H_
+ 
+class person
+{
+
+public:
+
+   enum sex { male, female, unknown };
+
+   long        _id;
+   QString     _firstName;
+   QString     _lastName;
+   QDateTime   _birthDate;
+   sex         _sex;
+
+   person() : _id(0), _sex(unknown) { ; }
+   person(long id) : _id(id), _sex(unknown) { ; }
+   virtual ~person() { ; }
+
+private:
+
+   void isValid(qx::QxInvalidValueX & invalidValues);
+
+};
+
+QX_REGISTER_HPP_MY_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _CLASS_PERSON_H_
+
+
+ * 'person.cpp' file :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/person.h"
+#include "../include/global_validator.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_MY_EXE(person)
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+   t.id(& person::_id, "id");
+
+   t.data(& person::_firstName, "firstName");
+   t.data(& person::_lastName, "lastName");
+   t.data(& person::_birthDate, "birthDate");
+   t.data(& person::_sex, "sex");
+
+   QxValidatorX<person> * pAllValidator = t.getAllValidator();
+   pAllValidator->add_NotEmpty("firstName");
+   pAllValidator->add_NotEmpty("lastName", "a person must have a lastname");
+   pAllValidator->add_CustomValidator(& person::isValid);
+   pAllValidator->add_CustomValidator_QVariant(& validateFirstName, "firstName");
+   pAllValidator->add_CustomValidator_DataType<QDateTime>(& validateDateTime, "birthDate");
+}}
+
+void person::isValid(qx::QxInvalidValueX & invalidValues)
+{
+   // This method is called automatically by 'QxValidator' module (validator engine of QxOrm library) :
+   // - when you try to insert or update using 'qx::dao::xxx' functions
+   // - when you call 'qx::validate()' function
+
+   // For registration, see 'pAllValidator->add_CustomValidator(& person::isValid);' into 'qx::register_class' function
+
+   // Here, you can verify some values of your instance
+   // If a value is not valid, you must add an invalid value into the collection 'invalidValues'
+
+   // For example, if we want to check property '_sex' of a person :
+   if ((_sex != male) && (_sex != female))
+   { invalidValues.insert("person sex must be defined : male or female"); }
+}
+
+
+ * 'global_validator.h' file :
+ + + + + + + +
+
// Example of global functions 'validateFirstName' and 'validateDateTime' used by 'QxValidator' module
+// Those functions will be called automatically by validator engine of QxOrm library :
+// - when you try to insert or update using 'qx::dao::xxx' functions
+// - when you call 'qx::validate()' function
+ 
+void validateFirstName(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Here you can test the value (converted to QVariant type)
+   // If an invalid value is detected, just add a message into 'invalidValues' collection
+
+   // For example, if the value must be never equal to "admin" :
+   if (value.toString() == "admin")
+   { invalidValues.insert("value must not be equal to 'admin'"); }
+}
+
+void validateDateTime(const QDateTime & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Here you can test the value (with its real type, in this example, the data-member is a 'QDateTime' type)
+   // If an invalid value is detected, just add a message into 'invalidValues' collection
+
+   // For example, if the date-time must be valid :
+   if (! value.isValid())
+   { invalidValues.insert("date-time value must not be empty and must be valid"); }
+}
+
+
+ * 'main.cpp' file :
+ + + + + + + +
+
person personValidate;
+personValidate._lastName = "admin";
+qx::QxInvalidValueX invalidValues = qx::validate(personValidate);
+QString sInvalidValues = invalidValues.text();
+qDebug("[QxOrm] test 'QxValidator' module :\n%s", qPrintable(sInvalidValues));
+
+
+ During program execution of above source code, 'personValidate' instance is not valid : + 'invalidValues' collection contains 4 items :
+ - "property 'firstName' must not be empty" ;
+ - "person sex must be defined : male or female" ;
+ - "value must not be equal to 'admin'" ;
+ - "date-time value must not be empty and must be valid".
+
+ QxValidator module provides some built-in constraints, which cover most of the basic data + checks.
+ As we'll see later, you're not limited to them, you can literally in a minute write your own + constraints : +
    +
  • add_NotNull() : checks if the value is not null ;
  • +
  • add_NotEmpty() : checks if the string is not empty ;
  • +
  • add_MinValue() : checks if the value is more than or equals to min ;
  • +
  • add_MaxValue() : checks if the value is less than or equals to max ;
  • +
  • add_Range() : checks if the value is between Min and Max (included) ;
  • +
  • add_MinDecimal() : checks if the decimal value is more than or equals to min ; +
  • +
  • add_MaxDecimal() : checks if the decimal value is less than or equals to max ; +
  • +
  • add_RangeDecimal() : checks if the decimal value is between Min and Max (included) + ;
  • +
  • add_MinLength() : checks if the string length is more than or equals to min ;
  • +
  • add_MaxLength() : checks if the string length is less than or equals to max ;
  • +
  • add_Size() : checks if the string length is between the min-max range ;
  • +
  • add_DatePast() : checks if the date is in the past ;
  • +
  • add_DateFuture() : checks if the date is in the future ;
  • +
  • add_RegExp() : checks if the property matches the regular expression given a match + flag ;
  • +
  • add_EMail() : checks whether the string conforms to the email address + specification.
  • +
+ Like 'person' class example, it's possible to define a custom validator : it's a function + or a class method called automatically by QxValidator module to validate a property or an + instance of class.
+ There are 3 kinds of custom validator : +
    +
  • add_CustomValidator() : class method, method signature must be "void + my_class::my_method(qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_QVariant() : global function with QVariant type (the + property is converted into QVariant type), function signature must be "void + my_validator(const QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)" ; +
  • +
  • add_CustomValidator_DataType() : global function with real type, function + signature must be "void my_validator(const T &, const qx::IxValidator *, + qx::QxInvalidValueX &)" ;
  • +
+ Note : each validator can be associated with a group (optional parameter for each + function add_XXX() of qx::IxValidatorX class).
+ So it's possible to create a context validation during program execution : for example, a person + from IHM A can have different validation rules than a person from IHM B.
+ To execute a validation process by group (for example "myGroup"), you have to call the + following function : "qx::QxInvalidValueX invalidValues = qx::validate(personValidate, + "myGroup");".
+
+ Other note : QxValidator module provides default messages when a constraint + violation is detected.
+ It's possible to modify these default messages (for example, a translation) using the following + collection : "QHash * lstMessage = + QxClassX::getAllValidatorMessage();".
+ For example : "lstMessage->insert("min_value", "la valeur '%NAME%' doit �tre inf�rieure ou + �gale � '%CONSTRAINT%'");".
+ %NAME% and %CONSTRAINT% fields will be automatically replaced by the good + value.
+ To modify a message for a specific validator (and not globally), you have to use the optional + parameter provided by each function add_XXX() of qx::IxValidatorX class. +

+
+

Manage NULL database + value

+
+ All databases manages NULL value : for more details about NULL value, please read the Wikipedia + web page.
+ QxOrm library provides several ways to manage NULL value : +
    +
  • using boost::optional class provided by boost library ;
  • +
  • using QVariant class provided by Qt framework ;
  • +
  • using pointers or smart-pointers : a C++ NULL pointer is associated to a NULL value in + database.
  • +
+
+

boost::optional +

+
+ boost::optional<T> class provided by boost is the best solution + to manage NULL value in C++.
+ To use boost::optional<T> with QxOrm library, you must define + _QX_ENABLE_BOOST compilation option, or include + <QxExtras/QxBoostOptionalOnly.h> header file.
+ Here is an example where all properties (except primary key) can be NULL using boost::optional class :
+
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   boost::optional<QString> firstName;
+   boost::optional<QString> lastName;
+   boost::optional<QDateTime> birthDate;  
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+#endif // _PERSON_H_
+
+
+ boost::optional<T> class is very easy to use : please read documentation on boost website for more details. +

+
+

QVariant

+
+ QVariant class provided by + Qt is another way to manage NULL value in C++.
+ Here is a class example where all values (except primary key) can be NULL using QVariant class :
+
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QVariant firstName;
+   QVariant lastName;
+   QVariant birthDate;  
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }  
+};
+
+#endif // _PERSON_H_
+
+
+ This solution is not perfect compared to boost::optional<T> because you loose the property type.
+ So it is recommended to work with boost::optional<T> class to manage NULL value with QxOrm + library. +

+
+
+

Inheritance and + polymorphism

+
+ With ORM tools, there are usually 3 strategies to manage inheritance and database : + + QxOrm works by default with Concrete Table Inheritance strategy (others are not + supported yet).
+ Many tutorials and forums are available on internet for more details about ORM + inheritance and database.
+ You can find a sample in ./test/qxDllSample/dll2/ directory of QxOrm package with + BaseClassTrigger class. +

+
+

qx::IxPersistable + interface (abstract class)

+
+ qx::IxPersistable interface (or abstract class) provides only pure + virtual methods.
+ Using qx::IxPersistable, you will have a common base class to call all persistents + functions without knowing the real type of current instance (polymorphism concept).
+ QxOrm library doesn't force developers to work with a base class to register a persistent type + in QxOrm context, however it's sometimes useful to have an interface to write some generic + algorithms.
+
+ qx::IxPersistable class provides following virtual methods (for more details about these + methods, goto QxOrm library online class + documentation) :
+
+
+
virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchAll(qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList());
+virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection() const;
+virtual qx::IxClass * qxClass() const;
+
+
+ For example, working with a list of qx::IxPersistable pointers, it's possible to save all + items to several database tables, like this :
+
+ + + + + + + +
+
QList<qx::IxPersistable *> lst = ...;
+foreach(qx::IxPersistable * p, lst)
+{
+   QSqlError daoError = p->qxSave();
+   if (daoError.isValid()) { /* an error occured */ }
+   // etc...
+}
+
+
+ To implement qx::IxPersistable interface, it's necessary to : +
    +
  • inherit persistent class from qx::IxPersistable ;
  • +
  • into class definition (myClass.h for example), add + QX_PERSISTABLE_HPP(myClass) macro ; +
  • +
  • into class implementation (myClass.cpp for example), add + QX_PERSISTABLE_CPP(myClass) macro. +
  • +
+ For example, to implement qx::IxPersistable interface for author class from qxBlog tutorial, you have + to write :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author : public qx::IxPersistable
+{
+   QX_PERSISTABLE_HPP(author)
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- properties
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- contructor, virtual destructor
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- methods
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+QX_PERSISTABLE_CPP(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+ Note : project test from ./test/qxDllSample/dll1/ directory provides a kind of + 'super base class' : qx::QxPersistable class implements qx::IxPersistable interface and inherits from QObject.
+ So SIGNAL-SLOT engine of Qt library can be used with this class and could be an + interesting way to use QxOrm triggers.
+ qx::QxPersistable class provides also some virtual methods to override to manage for + example data validation process from QxValidator module.
+ For information, qx::QxPersistable class is not a part of QxOrm library, but you can + copy-past it into your own project to use all its features : + +
+
+

Use PIMPL C++ pattern + (Private Implementation idiom or d-pointer)

+
+ From cppreference + website : "Pointer to implementation" or "pImpl" is a C++ programming technique that + removes implementation details of a class from its object representation by placing them in a + separate class, accessed through an opaque pointer. + This technique is used to construct C++ library interfaces with stable ABI and to reduce + compile-time dependencies. +

+ Advantages of PIMPL pattern for C++ persistent classes registered into + QxOrm context : +
    +
  • Compilation Firewall : if the private implementation changes, the client code + doesn't have to be recompiled ;
  • +
  • Reduce compilation times : headers files (*.h, *.hpp) are smaller ;
  • +
  • Binary Compatibility : as long as the binary interface stays the same, you can + link your app to a different version of a library ;
  • +
  • Reduce the size of generated binaries (*.dll, *.so, *.exe, etc...).
  • +
+ Disadvantages of PIMPL : +
    +
  • Performance : one level of indirection is added ;
  • +
  • Memory Management : a memory chunk has to be allocated (or preallocated) for the private + implementation (can issue memory fragmentation).
  • +
+
+ QxOrm library provides a sample project where all persistent classes are developed using the + PIMPL pattern : qxBlogPImpl (with relationships).
+ It is also possible (and recommended) to use QxEntityEditor + application to export automatically all C++ persistent classes of a project + with the PIMPL option.
+
+ Here is an example of a C++ class registered into QxOrm context developed with the PIMPL idiom + (with 1-n, n-1 and n-n relationships) :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_BLOG_H_
+#define _QX_BLOG_BLOG_H_
+
+class author;
+class comment;
+class category;
+
+class QX_BLOG_DLL_EXPORT blog
+{
+
+   QX_REGISTER_FRIEND_CLASS(blog)
+
+private:
+
+   struct blog_impl;
+   std::unique_ptr<blog_impl> m_pImpl; //!< Private implementation idiom
+
+public:
+
+   blog();
+   virtual ~blog();
+
+   blog(const blog & other);
+   blog & operator=(const blog & other);
+
+#ifdef Q_COMPILER_RVALUE_REFS
+   blog(blog && other) Q_DECL_NOEXCEPT;
+   blog & operator=(blog && other) Q_DECL_NOEXCEPT;
+#endif // Q_COMPILER_RVALUE_REFS
+
+   long id() const;
+   QString text() const;
+   QDateTime dateCreation() const;
+
+   void setId(long l);
+   void setText(const QString & s);
+   void setDateCreation(const QDateTime & d);
+
+   std::shared_ptr<author> & getAuthor();
+   QList< std::shared_ptr<comment> > & listOfComments();
+   qx::QxCollection<long, QSharedPointer<category> > & listOfCategories();
+
+};
+
+QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)
+
+typedef std::shared_ptr<blog> blog_ptr;
+typedef std::vector<blog_ptr> list_blog;
+
+#endif // _QX_BLOG_BLOG_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/blog.h"
+#include "../include/author.h"
+#include "../include/comment.h"
+#include "../include/category.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(blog)
+
+struct Q_DECL_HIDDEN blog::blog_impl
+{
+   long           m_id;
+   QString        m_text;
+   QDateTime      m_dt_creation;
+   author_ptr     m_author;
+   list_comment   m_commentX;
+   list_category  m_categoryX;
+
+   blog_impl() : m_id(0) { ; }
+   ~blog_impl() { ; }
+};
+
+namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   IxDataMember * pImpl = t.pimpl(& blog::m_pImpl);
+
+   t.id(& blog::blog_impl::m_id, "blog_id", 0, pImpl);
+
+   t.data(& blog::blog_impl::m_text, "blog_text", 0, true, true, pImpl);
+   t.data(& blog::blog_impl::m_dt_creation, "date_creation", 0, true, true, pImpl);
+
+   t.relationManyToOne(& blog::blog_impl::m_author, "author_id", 0, pImpl);
+   t.relationOneToMany(& blog::blog_impl::m_commentX, "list_comment", "blog_id", 0, pImpl);
+   t.relationManyToMany(& blog::blog_impl::m_categoryX, "list_category", "category_blog", "blog_id", "category_id", 0, pImpl);
+}}
+
+blog::blog() : m_pImpl(new blog_impl()) { ; }
+
+blog::~blog() { ; }
+
+blog::blog(const blog & other) : m_pImpl(new blog_impl(* other.m_pImpl)) { ; }
+
+blog & blog::operator=(const blog & other)
+{
+   if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); }
+   return (* this);
+}
+
+#ifdef Q_COMPILER_RVALUE_REFS
+blog::blog(blog && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; }
+blog & blog::operator=(blog && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); }
+#endif // Q_COMPILER_RVALUE_REFS
+
+long blog::id() const { return m_pImpl->m_id; }
+
+QString blog::text() const { return m_pImpl->m_text; }
+
+QDateTime blog::dateCreation() const { return m_pImpl->m_dt_creation; }
+
+void blog::setId(long l) { m_pImpl->m_id = l; }
+
+void blog::setText(const QString & s) { m_pImpl->m_text = s; }
+
+void blog::setDateCreation(const QDateTime & d) { m_pImpl->m_dt_creation = d; }
+
+std::shared_ptr<author> & blog::getAuthor() { return m_pImpl->m_author; }
+
+QList< std::shared_ptr<comment> > & blog::listOfComments() { return m_pImpl->m_commentX; }
+
+qx::QxCollection<long, QSharedPointer<category> > & blog::listOfCategories() { return m_pImpl->m_categoryX; }
+
+

+
+

Persist custom type +

+
+ QxOrm library can persist every types, not only classes registered in QxOrm context using + qx::register_class<T>().
+
+ It's necessary to write serialization functions from boost framework, using the non + intrusive method (because source code is not available or is read-only). + For more details on boost serialization module, goto official website.
+
+ For example, imagine that you have the class 'ExtObject3D' from an external library and + the source code is not available or is read-only. + Here is the code to can persist an instance of 'ExtObject3D' type into database :
+
+ + + + + + + +
+
#ifndef _PERSIST_EXTOBJECT3D_H_
+#define _PERSIST_EXTOBJECT3D_H_
+
+#include "ExtObject3D.h"
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/nvp.hpp>
+ 
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void save(Archive & ar, const ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(t.getX()), y(t.getY()), z(t.getZ()), angle(t.getAngle());
+
+   ar << boost::serialization::make_nvp("x", x);
+   ar << boost::serialization::make_nvp("y", y);
+   ar << boost::serialization::make_nvp("z", z);
+   ar << boost::serialization::make_nvp("angle", angle);
+}
+
+template <class Archive>
+void load(Archive & ar, ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(0.0), y(0.0), z(0.0), angle(0.0);
+
+   ar >> boost::serialization::make_nvp("x", x);
+   ar >> boost::serialization::make_nvp("y", y);
+   ar >> boost::serialization::make_nvp("z", z);
+   ar >> boost::serialization::make_nvp("angle", angle);
+
+   t.setX(x);
+   t.setY(y);
+   t.setZ(z);
+   t.setAngle(angle);
+}
+
+} // namespace serialization
+} // namespace boost
+ 
+BOOST_SERIALIZATION_SPLIT_FREE(ExtObject3D)
+
+#endif // _PERSIST_EXTOBJECT3D_H_
+
+
+ Now you can persist an instance of 'ExtObject3D' type into database : so you can have a + 'ExtObject3D' property in a persistent class registered in QxOrm context. + This property can be mapped with a column of type TEXT or VARCHAR into + database.
+
+ The default behaviour of QxOrm library is : the instance is serialized to XML format before + being inserted or updated into database. + This default behaviour can be useful, for example if you want to save a collection of items + without to make relation (so you don't have to manage another table into database). + For example, with a property of type std::vector<mon_objet> in a persistent class + without relation, the list of items will be saved into database under XML format.
+
+ Note : the default behaviour can be easily modified for a specific type. + QtSql engine uses QVariant type to link C++ code and database. + QVariant type can contain text, numeric, binary, etc. + So it can be interesting to specialize the default behaviour (XML serialization) if you want to + save datas under binary format or to optimize your application (XML serialization is not very + fast). + You just have to write (with boost serialization functions) a conversion into/from + QVariant type, for example with 'ExtObject3D' class :
+
+ + + + + + + +
+
namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< ExtObject3D > {
+static inline QVariant toVariant(const ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{ /* Here I convert from ExtObject3D to QVariant */ } };
+
+template <> struct QxConvert_FromVariant< ExtObject3D > {
+static inline qx_bool fromVariant(const QVariant & v, ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{ /* Here I convert from QVariant to ExtObject3D */; return qx_bool(true); } };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+

+ Note : here is a template to create a custom persistable type : +

+ + + + + + + +
+
#ifndef _MY_CUSTOM_PERSISTABLE_TYPE_H_
+#define _MY_CUSTOM_PERSISTABLE_TYPE_H_
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <QxOrm.h>
+
+class MyPersistableType
+{
+   /* What you want here */
+};
+
+QX_REGISTER_CLASS_NAME(MyPersistableType)
+QX_CLASS_VERSION(MyPersistableType, 0)
+
+QDataStream & operator<< (QDataStream & stream, const MyPersistableType & t)
+{
+   /* Your implementation here */
+}
+
+QDataStream & operator>> (QDataStream & stream, MyPersistableType & t)
+{
+   /* Your implementation here */
+}
+
+namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< MyPersistableType > {
+static inline QVariant toVariant(const MyPersistableType & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{
+   /* Here I convert from MyPersistableType to QVariant */
+} };
+
+template <> struct QxConvert_FromVariant< MyPersistableType > {
+static inline qx_bool fromVariant(const QVariant & v, MyPersistableType & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{
+   /* Here I convert from QVariant to MyPersistableType */
+   return qx_bool(true);
+} };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+#ifndef _QX_NO_JSON
+
+namespace qx {
+namespace cvt {
+namespace detail {
+
+template <>
+struct QxConvert_ToJson< MyPersistableType >
+{
+   static inline QJsonValue toJson(const MyPersistableType & t, const QString & format)
+   {
+      /* Your implementation here */
+   }
+};
+
+template <>
+struct QxConvert_FromJson< MyPersistableType >
+{
+   static inline qx_bool fromJson(const QJsonValue & j, MyPersistableType & t, const QString & format)
+   {
+      /* Your implementation here */
+   }
+};
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+#endif // _QX_NO_JSON
+
+// ------------------------------------
+// If you are using boost serialization, you have also to implement save/load functions like above 'ExtObject3D' example
+// ------------------------------------
+
+#endif // _MY_CUSTOM_PERSISTABLE_TYPE_H_
+
+

+
+

Generate database DDL SQL + schema

+
+ + !!! It's strongly recommended to use + QxEntityEditor application to manage DDL SQL schema generation !!! + +
+
+ QxOrm library doesn't provide a generator to create and to update automatically tables into + database.
+ Indeed, qx::dao::create_table<T> function must be used only to create prototypes or + samples.
+ It's strongly recommended to work with a tool provided by each SGBD to design and to manage + tables into database (for example Navicat with MySql, pgAdmin with + PostgreSQL, SQLite Manager with SQLite, etc.).
+ Moreover, each tool provided by each SGBD can add some optimizations to the database (add some + indexes for example).
+
+ But sometimes, it can be useful to not have to manage manually tables into database.
+ In this case, it's possible to create a C++ function to iterate over all persistents classes + registered in QxOrm context (using introspection engine of QxOrm library) : so you can build a + SQL script to create and to update tables into database.
+
+ QxOrm library provides an example of a C++ function : based on this function, you can create + your own function to build SQL schema.
+ This QxOrm function is written in the file ./src/QxRegister/QxClassX.cpp and is called QString + qx::QxClassX::dumpSqlSchema().
+ This QxOrm function builds a SQL script and returns a QString value : it's also possible + to modify the function to generate a file with SQL script or to execute each SQL process + directly to the SGBD.
+
+ Here is a sample implementation provided by dodobibi to + manage a PostgreSQL database : this sample works with a version number to add columns to + existing tables, to add some indexes to existing columns, etc.
+ When you start your application, a version number is provided and incremented when a new version + of your application is released :
+
+ + + + + + + +
+
QApplication app(argc, argv);
+app.setProperty("DomainVersion", 1);
+
+
+ A table into the database must be created to store this version number.
+ A C++ persistent class is mapped to this table :
+
+ + + + + + + +
+
#ifndef _DATABASE_VERSION_H_
+#define _DATABASE_VERSION_H_
+ 
+class MY_DLL_EXPORT DatabaseVersion
+{
+public:
+  QString name;
+  long version;
+};
+
+QX_REGISTER_HPP_MY_APP(DatabaseVersion, qx::trait::no_base_class_defined, 0)
+
+#endif // _DATABASE_VERSION_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/DatabaseVersion.h"
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_MY_APP(DatabaseVersion)
+
+namespace qx {
+template <> void register_class(QxClass<DatabaseVersion> & t)
+{
+  t.id(& DatabaseVersion::name, "name");
+  t.data(& DatabaseVersion::version, "version");
+}}
+
+
+ With DatabaseVersion class, it's possible to verify that the database must be updated or + not.
+ This is the goal of isDatabaseVersionOld() function :
+
+ + + + + + + +
+
bool isDatabaseVersionOld()
+{
+  DatabaseVersion dbVersion;
+  dbVersion.name = "MyAppName";
+  QSqlError err = qx::dao::fetch_by_id(dbVersion);
+  if (err.isValid()) { qAssert(false); return false; }
+  return (dbVersion.version < qApp->property("DomainVersion").toInt());
+}
+
+
+ If isDatabaseVersionOld() function returns true when you start your application, + then you must update your SQL schema :
+
+ + + + + + + +
+
void updateDatabaseVersion()
+{
+  try
+  {
+    int domainVersion = qApp->property("DomainVersion").toInt();
+
+    // Connect to the database with a user with modifications rights on SQL schema
+    QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
+    db.setUserName("MyAdminLogin");
+    db.setPassword("MyAdminPassword");
+
+    // Create a session, open automatically a transaction and throw an exception when an error occured
+    qx::QxSession session(db, true, true);
+
+    // Fetch the database version with a lock to protect the database
+    DatabaseVersion dbVersion;
+    session.fetchByQuery(qx_query("WHERE name='MyAppName' FOR UPDATE"), dbVersion);
+
+    // When unlocked for other users, verify that the database must be updated or not
+    if (dbVersion.version >= domainVersion) { return; }
+
+    // Execute each SQL process with "query" variable
+    QSqlQuery query(db);
+
+    // Fetch all C++ persistents classes registered in QxOrm context
+    qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
+    if (! pAllClasses) { qAssert(false); return; }
+
+    // Fetch all tables into database (this is a Qt function)
+    QStringList tables = db.tables();
+
+    for (long k = 0; k < pAllClasses->count(); k++)
+    {
+      qx::IxClass * pClass = pAllClasses->getByIndex(k);
+      if (! pClass) { continue; }
+
+      // Filter non persitents classes
+      if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) { continue; }
+
+      // Filter already updated classes
+      if (pClass->getVersion() <= dbVersion.version) { continue; }
+
+      // If table doesn't exist, create it and set the owner
+      if (! tables.contains(pClass->getName()))
+      {
+        query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);"
+                   "ALTER TABLE " + pClass->getName() + " OWNER TO \"MyAdminLogin\";");
+        session += query.lastError();
+      }
+
+      // If a column doesn't exist, add it to the table
+      qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
+      for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
+      {
+        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
+        if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
+
+        query.exec("ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";");
+        session += query.lastError();
+
+        if (p->getIsPrimaryKey()) // PRIMARY KEY
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getAllPropertyBagKeys().contains("INDEX")) // INDEX
+        {
+          query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
+                     " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getNotNull()) // NOT NULL
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
+          session += query.lastError();
+        }
+
+        if (p->getAutoIncrement()) // AUTO INCREMENT
+        {
+          query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
+                     "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"MyAdminLogin\"; "
+                     "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
+                     "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
+          session += query.lastError();
+        }
+
+        if (p->getDescription() != "") // DESCRIPTION
+        {          query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
+          session += query.lastError();
+        }
+      }
+    }
+
+    // Save current version of the database
+    dbVersion.version = domainVersion;
+    session.save(dbVersion);
+
+    // End of "try" scope : session is destroyed => commit or rollback automatically
+    // Moreover, a commit or a rollback unlock the process for all users
+  }
+  catch (const qx::dao::sql_error & err)
+  {
+    QSqlError sqlError = err.get();
+    qDebug() << sqlError.databaseText();
+    qDebug() << sqlError.driverText();
+    qDebug() << sqlError.number();
+    qDebug() << sqlError.type();
+  }
+}
+
+
+ Note : this code (like qx::QxClassX::dumpSqlSchema() function) can be modified to provide + more features.
+ For example, it could be interesting to create by default another table (like + DatabaseVersion table) to store the list of all persistents classes registered in QxOrm + context : instead of using "db.tables()" Qt function, it could be possible to fetch all + tables with more information (version number for each table, columns count registered in QxOrm + context, table description, etc.). +

+
+

Associate a SQL type to a + C++ class

+
+ Each database provides its own SQL types to store datas.
+ QxOrm library associates by default some C++ classes frequently used in a program :
+
+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ If a SQL type provided by default by QxOrm library is not supported by the database, it can be + easily modified (globally for all the application) using the following collection :
+
+ + + + + + + +
+
QHash<QString, QString> * lstSqlType = qx::QxClassX::getAllSqlTypeByClassName();
+lstSqlType->insert("QString", "VARCHAR(255)");
+lstSqlType->insert("std::string", "VARCHAR(255)");
+// etc.
+
+
+ To modify a SQL type for a specific column of a table, you have to define the new SQL type in + the mapping function of QxOrm library :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<MyClass> & t)
+{
+  //...
+  IxDataMember * p =  t.data(& MyClass::m_MyProperty, "my_property");
+  p->setSqlType("VARCHAR(255)");
+  //...
+}}
+
+
+ For all classes not supported by default by QxOrm library (read chapter : Persist custom type), it's possible to associate a default SQL + type using the following macro (outside all namespace) :
+
+ + + + + + + +
+
QX_REGISTER_TRAIT_GET_SQL_TYPE(MyClass, "my_sql_type")
+
+

+
+

Async database + queries

+
+ Sometimes, it's necessary to execute some queries to database in asynchronous way + (multi-thread), for example to avoid to freeze a GUI if a query is too long to execute.
+ To make easier to work with asynchronous queries, QxOrm library provides qx::QxDaoAsync class.
+ This class executes a query in another thread and returns the queryFinished() + SIGNAL when query is terminated.
+ To use qx::QxDaoAsync class, you just have to : +
    +
  • be careful to work only with classes implementing qx::IxPersistable interface ;
  • +
  • create an instance of qx::QxDaoAsync type (for example, a property of a + QWidget derived class) ; +
  • +
  • connect a SLOT to the qx::QxDaoAsync::queryFinished() SIGNAL (for + example, a SLOT of a QWidget derived class) ;
  • +
  • run a query using one of qx::QxDaoAsync::asyncXXXX() methods.
  • +
+ Here is an example with a class called MyWidget :
+
+ + + + + + + +
+
class MyWidget : public QWidget
+{ Q_OBJECT
+
+   //...
+   qx::QxDaoAsync m_daoAsync;
+   //...
+Q_SLOTS:
+   void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
+   //...
+
+};
+
+
+ And here is the implementation of MyWidget class :
+
+ + + + + + + +
+
MyWidget::MyWidget() : QObject()
+{
+   //...
+   QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), 
+                    this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)));
+   //...
+}
+
+void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams)
+{
+   if (! pDaoParams) { return; }
+   qx::QxSqlQuery query = pDaoParams->query;
+   if (! daoError.isValid()) { ; }
+   // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
+   qx::IxPersistable_ptr ptr = pDaoParams->pInstance;
+   // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
+   qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances;
+   //...
+}
+
+

+
+

Cache to store C++ + instances (QxCache module)

+
+ Cache engine provided by QxOrm library (QxCache module) is thread-safe and can store easily any + kind of objects.
+ Functions to access to the cache engine are inside namespace + qx::cache.
+ qx::cache engine can provide a program optimization : you can for example store items + fetched by a query to database.
+
+ Each item into the cache is associated with a key of type QString : this key provides a + quick access to an item stored into the cache.
+ If a new item is inserted with a key already in the cache, then the old item associated with + this key is removed automatically from the cache.
+
+ Cache engine of QxOrm library doesn't manage memory : there is no delete called by the + cache engine.
+ This is why it's strongly recommended (but not an obligation) to store smart-pointers into the + cache : for example, boost::shared_ptr<T> of boost library or QSharedPointer<T> of Qt library.
+
+ Cache engine can have a max cost to avoid too much memory usage : each item inserted to the + cache can be associated with a cost (for example, element's count of a collection).
+ When the limit (max cost) of the cache engine is reached, first items inserted to the cache are + automatically removed (insertion order) until limit of the cache is ok.
+
+ It's also possible to associate a date-time insertion when an item is added to the cache.
+ If there is no date-time, then the current date-time is taken into account.
+ This feature provides a way to verify that an item stored into the cache must be updated or + not.
+
+ Here is an example using cache engine of QxOrm library (functions into namespace + qx::cache) :
+
+ + + + + + + +
+
// Define max cost of cache engine to 500
+qx::cache::max_cost(500);
+
+// Fetch a list of 'author' from database
+boost::shared_ptr< QList<author> > list_author;
+QSqlError daoError = qx::dao::fetch_all(list_author);
+
+// Insert the list of 'author' to the cache
+qx::cache::set("list_author", list_author);
+
+// Fetch a list of 'blog' from database
+QSharedPointer< std::vector<blog> > list_blog;
+daoError = qx::dao::fetch_all(list_blog);
+
+// Insert the list of 'blog' to the cache (cost = 'blog' count)
+qx::cache::set("list_blog", list_blog, list_blog.count());
+
+// Pointer to an object of type 'comment'
+comment_ptr my_comment;
+my_comment.reset(new comment(50));
+daoError = qx::dao::fetch_by_id(my_comment);
+
+// Insert 'comment' to the cache with a date-time insertion
+qx::cache::set("comment", my_comment, 1, my_comment->dateModif());
+
+// Get the list of 'blog' stored into the cache
+list_blog = qx::cache::get< QSharedPointer< std::vector<blog> > >("list_blog");
+
+// Get the list of 'blog' without providing the type
+qx_bool bGetOk = qx::cache::get("list_blog", list_blog);
+
+// Remove list of 'author' from cache
+bool bRemoveOk = qx::cache::remove("list_author");
+
+// Get items count stored into the cache
+long lCount = qx::cache::count();
+
+// Get current cost of items stored into the cache
+long lCurrentCost = qx::cache::current_cost();
+
+// Verify that an element with the key "comment" exists into the cache
+bool bExist = qx::cache::exist("comment");
+
+// Get 'comment' stored into the cache with its date-time insertion
+QDateTime dt;
+bGetOk = qx::cache::get("comment", my_comment, dt);
+
+// Clear the cache
+qx::cache::clear();
+
+

+
+

Working with several + databases

+
+ In the Connection to database chapter, we have seen how to configure + default connection to database using singleton class : qx::QxSqlDatabase. + QxOrm library is based on Qt QtSql engine, so QxOrm uses internally the Qt QSqlDatabase class. + All functions to communicate with databases (qx::dao namespace, qx::QxSession class, etc...) have an optional parameter named : + QSqlDatabase * pDatabase = NULL : +
    +
  • if value of this parameter is NULL (which is the default value) : then QxOrm library uses + qx::QxSqlDatabase settings to connect to database (support + multi-threading) ; +
  • +
  • if value is not NULL : then QxOrm library uses connection provided by this QSqlDatabase * + pDatabase pointer.
  • +
+ So this optional parameter can be used to manage your own connection pool and/or to connect to + several databases. +

+
+

Register an abstract + class in QxOrm context

+
+ A C++ abstract class (with at least one pure virtual method) cannot be mapped to a database + table (because it cannot be instantiated).
+ However, in some cases, it can be interesting to define properties into abstract class used by a + persistent object (by inheritance).
+ A sample of abstract class registered in QxOrm context is available in + ./test/qxDllSample/dll2/ directory of QxOrm package with BaseClassTrigger + class.
+ To register an abstract class in QxOrm context, you have to : +
    +
  • register the class with 'void register_class' like any other class ; +
  • +
  • use QX_REGISTER_ABSTRACT_CLASS(className) macro just after the class definition. +
  • +
+
+
+

Register automatically Qt + meta-properties (Q_PROPERTY macro)

+
+ All classes inherited from QObject type can use Q_PROPERTY + macro : these properties become meta-properties. + This is how Qt framework provides an introspection engine using the moc process. + Meta-properties can be used for example by QML engine, QtScript, etc.
+
+ QxOrm library requires to register all properties per class in the void + qx::register_class<T>() mapping function to provide all features (persistence, XML, + JSON and binary serialization, etc.). + It's possible to register automatically all Qt meta-properties in QxOrm context without having + to manage any mapping function per class void qx::register_class<T>() : + QX_REGISTER_ALL_QT_PROPERTIES() macro works with Qt introspection engine to iterate over + all meta-properties.
+
+ Here is an example with TestQtProperty class in ./test/qxDllSample/dll1/include/ + directory of QxOrm package :
+
+ + + + + + + +
+
#ifndef _QX_TEST_QT_META_PROPERTY_H_
+#define _QX_TEST_QT_META_PROPERTY_H_
+ 
+class QX_DLL1_EXPORT TestQtProperty : public QObject
+{
+
+   Q_OBJECT
+   Q_PROPERTY(int id READ id WRITE setId)
+   Q_PROPERTY(long number READ number WRITE setNumber)
+   Q_PROPERTY(QString desc READ desc WRITE setDesc)
+   Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate)
+   Q_PROPERTY(QVariant photo READ photo WRITE setPhoto)
+
+protected:
+
+   int         m_id;
+   long        m_number;
+   QString     m_desc;
+   QDateTime   m_birthDate;
+   QVariant    m_photo;
+
+public:
+
+   TestQtProperty() : QObject(), m_id(0), m_number(0) { ; }
+   virtual ~TestQtProperty() { ; }
+
+   int id() const                { return m_id; }
+   long number() const           { return m_number; }
+   QString desc() const          { return m_desc; }
+   QDateTime birthDate() const   { return m_birthDate; }
+   QVariant photo() const        { return m_photo; }
+
+   void setId(int i)                         { m_id = i; }
+   void setNumber(long l)                    { m_number = l; }
+   void setDesc(const QString & s)           { m_desc = s; }
+   void setBirthDate(const QDateTime & dt)   { m_birthDate = dt; }
+   void setPhoto(const QVariant & v)         { m_photo = v; }
+ 
+};
+
+QX_REGISTER_HPP_QX_DLL1(TestQtProperty, QObject, 0)
+
+#endif // _QX_TEST_QT_META_PROPERTY_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/TestQtProperty.h"
+
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_QX_DLL1(TestQtProperty)
+QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id")
+
+
+ If you don't want to use QX_REGISTER_ALL_QT_PROPERTIES macro, you can write 4 lines of + code :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<TestQtProperty> & t)
+{ qx::register_all_qt_properties<TestQtProperty>(t, "id"); }
+} // namespace qx
+
+
+ Note : the second parameter of QX_REGISTER_ALL_QT_PROPERTIES macro is the name of + the property mapped to the primary key into database. + If this parameter is empty, then the class doesn't have any primary key or the primary key has + been registered in a base class.
+
+ All properties defined with Q_PROPERTY macro can be registered in QxOrm context in two + different ways :
+ 1- with the classic method : t.data(& MyQObject::my_property, "my_property", + 0);
+ 2- or without writing the data-member pointer : t.data("my_property", 0);
+
+ You can use the first or the second method to register your properties in QxOrm context and + access to the same functionalities using the common interface qx::IxDataMember. + You can also mix Qt meta-properties and classic registration data-member into the same mapping + function void qx::register_class<T>(). + Each registration method has some advantages and disadvantages.
+
+ Here is the list of advantages using the second registration method in QxOrm context : +
    +
  • much more faster to compile ;
  • +
  • reduce exec size ;
  • +
  • strong integration with Qt introspection/moc engine ;
  • +
  • no need to manage any mapping function per class using + QX_REGISTER_ALL_QT_PROPERTIES macro. +
  • +
+ Here is the list of disadvantages compared to the classic registration method : +
    +
  • need to inherit from QObject class to use Q_PROPERTY macro ;
  • +
  • program execution more slower (QVariant type versus C++ template) ;
  • +
  • doesn't support relationship between tables into database (one-to-one, + one-to-many, many-to-one and many-to-many) ; +
  • +
  • cannot access to the data-member pointer of a class (need to convert to QVariant + type before to access or to modify a value).
  • +
+
+
+ +

Serialization

+
+ From Wikipedia web page : + serialization is the process of translating data structures or object state into a format + that can be stored (for example, in a file or memory buffer, or transmitted across a network + connection link) and reconstructed later in the same or another computer environment. + When the resulting series of bits is reread according to the serialization format, it can be used + to create a semantically identical clone of the original object. + The opposite operation, extracting a data structure from a series of bytes, is named + deserialization. +

+ Each C++ class registered in QxOrm context can be serialized in several ways : + + Note : serialization engine of QxOrm library provides extra features like : clone entity, dump entity (XML or JSON format) + and QxService module. +

+ Other note : by default, all properties registered in QxOrm context are serializable. To + remove a property from the serialization engine, you can write :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  IxDataMember * pDataMember = t.data(& person::age, "age");
+  pDataMember->setSerialize(false);
+}}
+
+

+

Version number to manage + ascendant compatibility

+
+ Ascendant compatibility allows deserialization process (so restore a data structure) from a + stream generated by a previous version of an application. + QxOrm library requires a version number per class and a version number for each property + registered in QxOrm context to provide ascendant compatibility. +

+ For example, imagine a person class created in a version A of your application : + we put in QX_REGISTER_HPP macro a class version equals to 0 (means first version of our + person class), and each property class have also a version equals to 0 (0 is the default + value, optional parameter). + So our person class looks like : +

+ * person.h file :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _PERSON_H_
+
+
+ * person.cpp file :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name", 0);
+  t.data(& person::lastName, "last_name", 0);
+  t.data(& person::birthDate, "birth_date", 0);
+}}
+
+

+ In version B of the application, we modify our person class and we add 2 + properties : sex and address. + Our class has changed, so we have to increment its class version number, and new properties must + have a version equals to 1. + Now, our person class looks like : +

+ * person.h file :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+   QString sex;
+   QString address;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 1)
+
+#endif // _PERSON_H_
+
+
+ * person.cpp file :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name", 0);
+  t.data(& person::lastName, "last_name", 0);
+  t.data(& person::birthDate, "birth_date", 0);
+  t.data(& person::sex, "sex", 1);
+  t.data(& person::address, "address", 1);
+}}
+
+

+ Note : QxOrm library can serialize this person class from application in version + A, then deserialize this version A stream to create a cloned instance of person class in + version B of our application. +

+ Other note : remove a property breaks ascendant compatibility. + So it is recommended to never remove a property to work with QxOrm serialization engine : it is + possible for example to put a private visibility and to delete get/set accessors, + so property is hidden and can be considered as obsolete. +

+
+

Qt QDataStream engine +

+
+ Each C++ class registered in QxOrm context can be serialized using Qt QDataStream engine. + Functions to use Qt QDataStream serialization are available in namespace : qx::serialization::qt. + + Note : QDataStream + serialization is portable (support serialization/deserialization on all environments : Windows, + Linux, Mac OS X, etc...). + The output serialized stream is in binary format : so stream size is smaller than XML or JSON + for example. + QDataStream serialization + is based on introspection engine of QxOrm library, so it is slower than boost::serialization engine (based on C++ template). +

+ For example :
+ + + + + + + +
+
   // Fetch a drug with id '3' in a new variable
+   // drug is a C++ class registered in QxOrm context
+   drug d;
+   d.id = 3;
+   QSqlError daoError = qx::dao::fetch_by_id(d);
+
+   // Serialize the drug to a file
+   qx::serialization::qt::to_file(d, "export_drug.txt");
+
+   // Import drug from file in a new instance
+   drug d2;
+   qx::serialization::qt::from_file(d2, "export_drug.txt");
+
+   // Check if d == d2
+   qAssert(d == d2);
+
+
+ Note : in above example, we serialize a C++ instance. + All functions in qx::serialization namespace can serialize list of objects. + For more details about supported containers, please read this chapter : Supported containers. +

+
+

Qt JSON engine

+
+ Each C++ class registered in QxOrm context can be serialized to JSON using Qt QJson engine (requires Qt5). + Functions to use Qt JSON serialization are available in namespace : qx::serialization::json. + + Note : JSON serialization + engine is the most permissive (compared to XML engine for example) : + indeed, properties can be defined in any order, and properties can be removed or added. + JSON deserialization doesn't generate errors or throw exceptions : the engine ignores invalid or + removed properties (but JSON stream must be valid) : so JSON engine is much more flexible than + XML engine. +

+ Other note : JSON + serialization is based on introspection engine of QxOrm library, so it is slower than boost::serialization engine (based on C++ template). +

+ For example :
+ + + + + + + +
+
   // Fetch a list of authors from database and serialize them to a JSON file
+   list_author list_of_author;
+   qx::dao::fetch_all(list_of_author);
+   qx::serialization::json::to_file(list_of_author, "list_of_author.json");
+
+
+ Above example generates following JSON stream :
+
+
{
+    "author_id_2": {
+        "author_id": "author_id_2",
+        "birthdate": "2016-03-24",
+        "list_blog": [
+        ],
+        "name": "author_2",
+        "sex": 1
+    },
+    "author_id_3": {
+        "author_id": "author_id_3",
+        "birthdate": "2016-03-24",
+        "list_blog": [
+        ],
+        "name": "author_3",
+        "sex": 1
+    }
+}
+
+

+ Note : QxRestApi module provided by QxOrm library is based on + JSON serialization engine. +

+ Other note : you can customize output JSON format (to filter some properties generated by + JSON serialization process). + All JSON serialization functions provide an optional parameter of type QString named + format. + Prerequisites to use this format parameter are : +
    +
  • format parameter must start with prefix : filter: ;
  • +
  • output properties can be defined inside { } ;
  • +
  • relationships are splitted by character | ;
  • +
  • character * means : all relationships for 1 level ;
  • +
  • character - before { } means : all properties except. +
  • +
+
+ Example : here is a JSON serialization example defining an output format to filter some + properties on several levels of relationships : +

+ + + + + + + +
+
// Serialize a C++ instance to a JSON string
+QString jsonFormat = "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *";
+QString outputJsonFiltered = qx::serialization::json::to_string(blog, 1, jsonFormat);
+qDebug("[QxOrm] custom JSON serialization process (filtered) : \n%s", qPrintable(outputJsonFiltered));
+
+// Fill a C++ instance based on a JSON string
+blog_ptr blogFromJsonFiltered; blogFromJsonFiltered.reset(new blog());
+qx::serialization::json::from_string(blogFromJsonFiltered, outputJsonFiltered, 1, jsonFormat);
+qx::dump(blogFromJsonFiltered);
+qAssert(blogFromJsonFiltered->m_text != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_dt_creation.isNull()); // Not fetched
+qAssert(blogFromJsonFiltered->m_author->m_sex == author::unknown); // Not fetched
+qAssert(blogFromJsonFiltered->m_author->m_name != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_commentX.size() > 0);
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_dt_create.isNull()); // Not fetched
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_text != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_blog);
+
+

+
+

XML boost + serialization

+
+ XML boost::serialization engine is disabled by default : to enable this + feature, it is necessary to define _QX_ENABLE_BOOST_SERIALIZATION and + _QX_ENABLE_BOOST_SERIALIZATION_XML compilation options in QxOrm.pri + (or QxOrm.cmake) configuration file. + It is also required to build boost::serialization binary (because this module is not header + only), and to set the path to this boost serialization binary to + QX_BOOST_LIB_PATH, QX_BOOST_LIB_SERIALIZATION_DEBUG and + QX_BOOST_LIB_SERIALIZATION_RELEASE variables of QxOrm.pri (or + QxOrm.cmake) configuration file. +

+ Each C++ class registered in QxOrm context can be serialized using XML boost::serialization engine. + Functions to work with XML boost serialization are available in namespace : qx::serialization::xml (same functions as qx::serialization::qt namespace). +

+ XML boost serialization engine is : +
    +
  • portable : support serialization/deserialization on all environments : Windows, + Linux, Mac OS X, etc... ;
  • +
  • slowest : slower than binary and text serialization ;
  • +
  • largest : generated stream are bigger than binary and text + serialization ;
  • +
  • human-readable : a XML stream can easily be parsed by a text editor and can be + read by a human.
  • +
+
+
+

Binary boost + serialization

+
+ Binary boost::serialization engine is disabled by default : to enable this + feature, it is necessary to define _QX_ENABLE_BOOST_SERIALIZATION and + _QX_ENABLE_BOOST_SERIALIZATION_BINARY compilation options in QxOrm.pri (or QxOrm.cmake) configuration file. + It is also required to build boost::serialization binary (because this module is not header + only), and to set the path to this boost serialization binary to + QX_BOOST_LIB_PATH, QX_BOOST_LIB_SERIALIZATION_DEBUG and + QX_BOOST_LIB_SERIALIZATION_RELEASE variables of QxOrm.pri (or + QxOrm.cmake) configuration file. +

+ Each C++ class registered in QxOrm context can be serialized using binary boost::serialization engine. + Functions to work with binary boost serialization are available in namespace : qx::serialization::binary (same functions as qx::serialization::qt namespace). +

+ Binary boost serialization engine is : +
    +
  • non-portable : an instance serialized on Windows cannot be deserialized on Linux + for example : so you have to stay on the same environment ;
  • +
  • fastest : faster than XML and text serialization ;
  • +
  • smallest : generated stream are smaller than XML and text + serialization ;
  • +
  • non-human-readable : a binary stream cannot be read (not useful to log for + example).
  • +
+
+
+

Other boost + serialization

+
+ boost::serialization engine provides several formats to serialize C++ + classes. + All boost serialization process are disabled by default, so to use them (same functions as qx::serialization::qt namespace), it is necessary to define + compilation options in QxOrm.pri (or QxOrm.cmake) configuration file : + +
+
+

Clone a C++ instance +

+
+ Each C++ class registered in QxOrm context can be cloned using : + + For example : +

+ + + + + + + +
+
   drug_ptr d1;
+   d1.reset(new drug());
+   d1->name = "name1";
+   d1->description = "desc1";
+
+   // Clone a drug
+   drug_ptr d_clone = qx::clone(* d1);
+
+   // Check if (d1 == d_clone)
+   qAssert((* d1) == (* d_clone));
+
+
+ Important note : be careful when you clone a smart-pointer (boost::shared_ptr or + QSharedPointer for example) where the root item can be referenced several times in its + hierarchy (tree structure for example). + In this case, to protect the root pointer of a double deletion (2 smart-pointers which take + ownership of the same raw pointer), it is recommended to clone this way : +

+ + + + + + + +
+
// 'pOther' type is boost::shared_ptr<myClass> (smart-pointer)
+boost::shared_ptr<myClass> * pCloneTemp = qx::clone_to_nude_ptr(pOther);
+boost::shared_ptr<myClass> pClone = (pCloneTemp ? (* pCloneTemp) : boost::shared_ptr<myClass>());
+if (pCloneTemp) { delete pCloneTemp; pCloneTemp = NULL; }
+// Now use 'pClone' ...
+
+

+
+

Dump a C++ instance (XML + or JSON format)

+
+ Each C++ class registered in QxOrm context can be displayed to JSON + format. + If XML boost::serialization engine is enabled, then it is also + possible to display a XML dump of a C++ instance (second input parameter of qx::dump + function). + QxOrm dump feature can be useful to debug or to log for example. +

+ + + + + + + +
+
   blog_ptr b;
+   b.reset(new blog());
+   b->id = 36;
+   qx::dao::fetch_by_id_with_all_relation(b);
+
+   // Dump 'b' instance result from database (XML or JSON serialization)
+   // Second parameter is optional : 'true' = JSON format, 'false' = XML format
+   qx::dump(b, false);
+
+
+ Above source code generates output XML : +

+
+
+[QxOrm] start dump 'boost::shared_ptr<blog>'
+<boost.shared_ptr-blog- class_id="0" tracking_level="0" version="1">
+	<px class_id="1" tracking_level="1" version="0" object_id="_0">
+		<blog_id>113</blog_id>
+		<blog_text class_id="2" tracking_level="0" version="0">update blog_text_1</blog_text>
+		<date_creation class_id="3" tracking_level="0" version="0">20100409162612000</date_creation>
+		<author_id class_id="4" tracking_level="0" version="1">
+			<px class_id="5" tracking_level="1" version="0" object_id="_1">
+				<author_id>author_id_2</author_id>
+				<name>author_2</name>
+				<birthdate class_id="6" tracking_level="0" version="0">20100409</birthdate>
+				<sex>1</sex>
+				<list_blog class_id="7" tracking_level="0" version="0">
+					<count>0</count>
+					<item_version>1</item_version>
+				</list_blog>
+			</px>
+		</author_id>
+		<list_comment class_id="8" tracking_level="0" version="0">
+			<count>2</count>
+			<item class_id="9" tracking_level="0" version="1">
+				<px class_id="10" tracking_level="1" version="0" object_id="_2">
+					<comment_id>209</comment_id>
+					<comment_text>comment_1 text</comment_text>
+					<date_creation>20100409162612000</date_creation>
+					<blog_id>
+						<px class_id_reference="1" object_id="_3">
+							<blog_id>113</blog_id>
+							<blog_text></blog_text>
+							<date_creation></date_creation>
+							<author_id>
+								<px class_id="-1"></px>
+							</author_id>
+							<list_comment>
+								<count>0</count>
+							</list_comment>
+							<list_category class_id="11" tracking_level="0" version="0">
+								<count>0</count>
+							</list_category>
+						</px>
+					</blog_id>
+				</px>
+			</item>
+			<item>
+				<px class_id_reference="10" object_id="_4">
+					<comment_id>210</comment_id>
+					<comment_text>comment_2 text</comment_text>
+					<date_creation>20100409162612000</date_creation>
+					<blog_id>
+						<px class_id_reference="1" object_id="_5">
+							<blog_id>113</blog_id>
+							<blog_text></blog_text>
+							<date_creation></date_creation>
+							<author_id>
+								<px class_id="-1"></px>
+							</author_id>
+							<list_comment>
+								<count>0</count>
+							</list_comment>
+							<list_category>
+								<count>0</count>
+							</list_category>
+						</px>
+					</blog_id>
+				</px>
+			</item>
+		</list_comment>
+		<list_category>
+			<count>2</count>
+			<item class_id="12" tracking_level="0" version="0">
+				<first>355</first>
+				<second class_id="13" tracking_level="0" version="0">
+					<qt_shared_ptr class_id="14" tracking_level="1" version="0" object_id="_6">
+						<category_id>355</category_id>
+						<name>category_1</name>
+						<description>desc_1</description>
+						<list_blog class_id="15" tracking_level="0" version="0">
+							<count>0</count>
+						</list_blog>
+					</qt_shared_ptr>
+				</second>
+			</item>
+			<item>
+				<first>357</first>
+				<second>
+					<qt_shared_ptr class_id_reference="14" object_id="_7">
+						<category_id>357</category_id>
+						<name>category_3</name>
+						<description>desc_3</description>
+						<list_blog>
+							<count>0</count>
+						</list_blog>
+					</qt_shared_ptr>
+				</second>
+			</item>
+		</list_category>
+	</px>
+</boost.shared_ptr-blog->
+[QxOrm] end dump 'boost::shared_ptr<blog>'
+
+
+
+
+
+ +

Introspection - + Reflection

+
+ All C++ classes registered in QxOrm context (with qx::register_class<T>() function) + can be used by introspection engine (or reflection engine) of QxOrm library. + Introspection engine provides dynamically (so during program execution) some information about + types. + These information are called meta-datas and list some classes characteristics (properties, + methods, etc.). + Many programming languages (for example Java or C#) have natively this mechanism, but not C++, + that's why QxOrm library emulates an introspection engine. + For more details about introspection (or reflection), please read the + Wikipedia web page. +

+ Here is a list of QxOrm library classes to register/access to meta-datas : +
    +
  • qx::QxClassX : + singleton class to iterate over all classes registered in QxOrm context (with + qx::register_class<T>() function) ; +
  • +
  • qx::IxClass : + interface for a class registered in QxOrm context ;
  • +
  • qx::IxDataMemberX : list of properties associated to a class ;
  • +
  • qx::IxDataMember : interface for a class property ;
  • +
  • qx::IxFunctionX : + list of methods associated to a class ;
  • +
  • qx::IxFunction : + interface for a class method.
  • +
+ A qx::IxClass + instance contains the list of class properties (qx::IxDataMemberX) and the list of class methods (qx::IxFunctionX).
+
+ Introspection engine of QxOrm library provides : + +
+ Note : QxService + module of QxOrm library (click here to go to the + tutorial) is based on introspection engine to provide an easy and powerful way to create C++ + application server calling dynamically services methods (client request) on server side, and + creating automatically input/ouput services parameters instances.
+
+ Other note : you can add extra information to introspection engine using property bag + pattern. + Indeed, qx::IxClass, qx::IxDataMember and qx::IxFunction classes contain a + list of QVariant items associated to a QString key (read qx::QxPropertyBag + class documentation for more details). +

+ Other note : to initialize QxOrm introspection engine, it is recommanded to call following + function once in your main for example : +

+ + + + + + + +
+
// Following command is recommanded to initialize QxOrm introspection engine
+qx::QxClassX::registerAllClasses(true);
+
+

+

Get a data member value + dynamically

+
+ To get dynamically a data member value using introspection engine of QxOrm library, you have to + work with qx::IxDataMember base class (interface). + qx::IxDataMember + class provides several methods to get a data member value (each method has a generic pointer + void * as parameter which is the address of the current instance) : + + For example : we have a generic pointer void * to a person class. + We can get the QString value of firstName property writing : +

+ + + + + + + +
+
// Generic pointer of type void * : we know that p is of type 'person'
+void * p = ...;
+
+// Get a pointer to the registered data member 'firstName' of class 'person'
+qx::IxDataMember * pDataMember = qx::QxClassX::getDataMember("person", "firstName");
+
+// First method to get the data member value with the real type
+QString sFirstName = pDataMember->getValue<QString>(p);
+
+// Second method to get the data member value converted in QVariant
+QVariant vFirstName = pDataMember->toVariant(p);
+
+// Third method to get the value encapsulated in qx::any type
+boost::any aFirstName = pDataMember->getValueAnyPtr(p);
+
+// Check if all values are equals
+qAssert((sFirstName == vFirstName.toString()) && (sFirstName == (* boost::any_cast<QString *>(aFirstName))));
+
+

+
+

Set a data member value + dynamically

+
+ qx::IxDataMember + base class (interface) is able to set dynamically a new value to a property class (modify its + value). + qx::IxDataMember + class provides 2 methods (each method has a generic pointer void * as parameter which is + the address of the current instance, and the new value to change) : +
    +
  • fromVariant() : set a new data member value based on a QVariant parameter ; +
  • +
  • setValue<T>() : set a new data member value based on a real + type parameter (template T).
  • +
+ For example : we have a generic pointer void * to a person class. + We can modify firstName property of QString type writing : +

+ + + + + + + +
+
// Generic pointer of type void * : we know that p is of type 'person'
+void * p = ...;
+
+// Get a pointer to the registered data member 'firstName' of class 'person'
+qx::IxDataMember * pDataMember = qx::QxClassX::getDataMember("person", "firstName");
+
+// First method to change the data member value
+QVariant vFirstName = QVariant("my new firstname 1");
+pDataMember->fromVariant(p, vFirstName);
+
+// Other method to change the data member value (using real type)
+QString sFirstName = "other firstname 2";
+pDataMember->setValue<QString>(p, sFirstName);
+
+

+
+

Call function + dynamically

+
+ Like data members (class properties), it is possible to register class methods (functions) in + QxOrm context (support static and non static methods). + Introspection engine of QxOrm library can invoke dynamically class methods. + All functions registered in QxOrm context are associated to a qx::IxFunction + instance. + To register a class method in QxOrm context, you have to use these functions : + + For example : we want to register in QxOrm context several methods of a person + class : +

+ * person.h file :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+
+   long getId() const;
+   void myMethodWith2Params(int param1, const QString & param2);
+
+   static double myStaticMethodWith1Param(long param1);
+
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _PERSON_H_
+
+
+ * person.cpp file :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name");
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+
+  t.fct_0<long>(& person::getId, "getId");
+  t.fct_2<void, int, const QString &>(& person::myMethodWith2Params, "myMethodWith2Params");
+
+  t.fctStatic_1<double, long>(& person::myStaticMethodWith1Param, "myStaticMethodWith1Param");
+}}
+
+

+ Once registered in QxOrm context, it is possible to call functions dynamically using qx::QxClassX::invoke() + and qx::QxClassX::invokeStatic() : +

+ + + + + + + +
+
   // Generic pointer of type void * : we know that p is of type 'person'
+   void * p = ...;
+
+   // Call method 'long getId() const' and get return value
+   boost::any returnValue;
+   qx::QxClassX::invoke("person", "getId", p, "", (& returnValue));
+   long lId = boost::any_cast<long>(returnValue);
+
+   // Call method 'myMethodWith2Params' with 2 parameters encapsulated in a string (default separator for parameters is character '|')
+   // This way to pass parameters to the function works only if parameters are numeric or string
+   // If parameters are more complex, then you have to encapsulate parameters in a list of qx::any, as shown below
+   qx::QxClassX::invoke("person", "myMethodWith2Params", p, "36|my string param 2");
+
+   // Call method 'myMethodWith2Params' with 2 parameters encapsulated in a list of qx::any : std::vector<qx::any>
+   std::vector<boost::any> lstParams;
+   int iParam1 = 36; lstParams.push_back(iParam1); // Parameter at position 1
+   QString sParam2 = "my string param 2"; lstParams.push_back(sParam2); // Parameter at position 2
+   qx::QxClassX::invoke("person", "myMethodWith2Params", p, lstParams);
+
+   // Call static method 'myStaticMethodWith1Param' with 1 parameter and get return value
+   qx::QxClassX::invokeStatic("person", "myStaticMethodWith1Param", "19", (& returnValue));
+   double dValue = boost::any_cast<double>(returnValue);
+
+

+
+

Create a C++ instance + dynamically

+
+ Introspection engine of QxOrm library is able to create class instances dynamically based on + class name (QxFactory + module, design pattern factory) using following functions : + + For example : QxService module of QxOrm library creates services + instances dynamically (based on service name) to execute server routines automatically : +

+ + + + + + + +
+
   qx::service::IxService * ptr = qx::create_nude_ptr<qx::service::IxService>(m_sServiceName);   
+
+

+
+

Iterate over all + classes/properties registered in QxOrm context

+
+ Here is an example based on introspection engine of QxOrm library : how to iterate over all + classes, properties and methods registered in QxOrm context ?
+
+ + + + + + + +
+
QString QxClassX::dumpAllClasses()
+{
+   QxClassX::registerAllClasses();
+   QxCollection<QString, IxClass *> * pAllClasses = QxClassX::getAllClasses();
+   if (! pAllClasses) { qAssert(false); return ""; }
+
+   QString sDump;
+   long lCount = pAllClasses->count();
+   qDebug("[QxOrm] start dump all registered classes (%ld)", lCount);
+   _foreach(IxClass * pClass, (* pAllClasses))
+   { if (pClass) { sDump += pClass->dumpClass(); } }
+   qDebug("[QxOrm] %s", "end dump all registered classes");
+
+   return sDump;
+}
+
+QString IxClass::dumpClass() const
+{
+   QString sDump;
+   sDump += "-- class '" + m_sKey + "' (name '" + m_sName + "', ";
+   sDump += "description '" + m_sDescription + "', version '" + QString::number(m_lVersion) + "', ";
+   sDump += "base class '" + (getBaseClass() ? getBaseClass()->getKey() : "") + "')\n";
+
+   long lCount = (m_pDataMemberX ? m_pDataMemberX->count() : 0);
+   sDump += "\t* list of registered properties (" + QString::number(lCount) + ")\n";
+   if (m_pDataMemberX)
+   {
+      IxDataMember * pId = this->getId();
+      for (long l = 0; l < lCount; l++)
+      {
+         IxDataMember * p = m_pDataMemberX->get(l); if (! p) { continue; }
+         IxSqlRelation * pRelation = p->getSqlRelation();
+         QString sInfos = p->getKey() + ((p == pId) ? QString(" (id)") : QString());
+         sInfos += (pRelation ? (QString(" (") + pRelation->getDescription() + QString(")")) : QString());
+         sDump += "\t\t" + sInfos + "\n";
+      }
+   }
+
+   lCount = (m_pFctMemberX ? m_pFctMemberX->count() : 0);
+   sDump += "\t* list of registered functions (" + QString::number(lCount) + ")\n";
+   if (m_pFctMemberX)
+   {
+      _foreach_if(IxFunction_ptr p, (* m_pFctMemberX), (p))
+      { QString sKey = p->getKey(); sDump += "\t\t" + sKey + "\n"; }
+   }
+
+   qDebug("%s", qPrintable(sDump));
+   return sDump;
+}
+
+
+ If we execute the qx::QxClassX::dumpAllClasses() function with qxBlog tutorial, here are output logs :
+
+ + + + + + + +
+
[QxOrm] start dump all registered classes (4)
+-- class 'author' (name 'author', description '', version '0', base class '')
+	* list of registered properties (5)
+		author_id (id)
+		name
+		birthdate
+		sex
+		list_blog (relation one-to-many)
+	* list of registered functions (1)
+		age
+
+-- class 'blog' (name 'blog', description '', version '0', base class '')
+	* list of registered properties (6)
+		blog_id (id)
+		blog_text
+		date_creation
+		author_id (relation many-to-one)
+		list_comment (relation one-to-many)
+		list_category (relation many-to-many)
+	* list of registered functions (0)
+
+-- class 'comment' (name 'comment', description '', version '0', base class '')
+	* list of registered properties (4)
+		comment_id (id)
+		comment_text
+		date_creation
+		blog_id (relation many-to-one)
+	* list of registered functions (0)
+
+-- class 'category' (name 'category', description '', version '0', base class '')
+	* list of registered properties (4)
+		category_id (id)
+		name
+		description
+		list_blog (relation many-to-many)
+	* list of registered functions (0)
+
+[QxOrm] end dump all registered classes
+
+
+
+
+ +

Services : transfer + persistent data layer over network (QxService module)

+
+ QxService module of + QxOrm library provides an easy and powerful way to create C++ application server + (services with request from client and response from server). + A tutorial is available on + QxOrm web site to show how to work with QxService module. + QxService module is based on + introspection engine and serialization engine of + QxOrm library to transfer persistent data layer over network and execute automatically server + routines on server side. +

+ Note : to enable QxService module, you have to define _QX_ENABLE_QT_NETWORK compilation option in QxOrm.pri (or QxOrm.cmake) configuration file. + This compilation option adds a dependency to QxOrm library : QtNetwork provided by Qt + framework. +

+ Other note : QxEntityEditor application is deployed with QxEECppServicesExport + plugin : this plugin generates automatically all C++ source code to transfer all project entities + over network. + A list of client/server methods are generated automatically (to manage CRUD operations) : +
    +
  • count() : client/server query to count entities (possibility to add a SQL query + filter) ;
  • +
  • fetchById() : client/server query to fetch entity properties based on its identifier + ;
  • +
  • fetchAll() : client/server query to fetch properties of all entities (mapped to a + database table) ;
  • +
  • fetchByQuery() : client/server query to fetch properties of entities filtered by a + SQL query ;
  • +
  • insert() : client/server query to insert entity values ;
  • +
  • update() : client/server query to update entity values ;
  • +
  • save() : client/server query to save entity values (insert or update) ;
  • +
  • deleteById() : client/server query to delete an entity based on its identifier ;
  • +
  • deleteAll() : client/server query to delete all entities (mapped to a database table) + ;
  • +
  • deleteByQuery() : client/server query to delete entities filtered by a SQL query ; +
  • +
  • destroyById() : client/server query to delete an entity based on its identifier + (manage soft delete behaviour, logical delete) ;
  • +
  • destroyAll() : client/server query to delete all entities mapped to a database table + (manage soft delete behaviour, logical delete) ;
  • +
  • destroyByQuery() : client/server query to delete entities filtered by a SQL query + (manage soft delete behaviour, logical delete) ;
  • +
  • executeQuery() : client/server query to execute a custom SQL + query or stored procedure ;
  • +
  • exist() : client/server query to check if an entity already exists based on its + identifier ;
  • +
  • isValid() : client/server query to check entity validity (QxValidator module).
  • +
+ It is possible to add and to customize services generated by QxEntityEditor application. +

+ The goal of this chapter is to show QxService module concepts : + +
+

Input/output service + parameters (request/response)

+
+ Each function exposed by a service has input parameters (request from client) and output + parameters (response from server). + These input/output parameters must inherit from qx::service::IxParameter interface and must be registered in QxOrm + context (with void qx::register_class<T> function). +

+ For example : here is an example of input/output parameters generated by + QxEntityEditor application based on blog class of qxBlog tutorial : +

+ * blog.services.gen.h file :
+ + + + + + + +
+
namespace services {
+
+typedef boost::shared_ptr<blog> blog_ptr;
+typedef qx::QxCollection<long, blog_ptr> list_of_blog;
+typedef boost::shared_ptr<list_of_blog> list_of_blog_ptr;
+
+/* -- Service Input Parameters -- */
+
+class QXBLOG_SERVICES_EXPORT blog_input : public qx::service::IxParameter
+{
+
+public:
+
+   blog_input();
+   virtual ~blog_input();
+
+   long id;                   //!< Id to fetch or delete
+   blog_ptr instance;         //!< Single instance to fetch, insert, update, delete or validate
+   list_of_blog_ptr list;     //!< List of instances to fetch, insert, update, delete or validate
+   qx_query query;            //!< Query to execute when fetching, updating or deleting
+   QStringList columns;       //!< List of columns to fetch or update
+   QStringList relations;     //!< List of relations to fetch
+
+};
+
+typedef boost::shared_ptr<services::blog_input> blog_input_ptr;
+
+/* -- Service Output Parameters -- */
+
+class QXBLOG_SERVICES_EXPORT blog_output : public qx::service::IxParameter
+{
+
+public:
+
+   blog_output();
+   virtual ~blog_output();
+
+   blog_ptr instance;            //!< Single instance from server
+   list_of_blog_ptr list;        //!< List of instances from server
+   QSqlError error;              //!< If a SQL error occurred, this output parameter is not empty
+   qx::QxInvalidValueX invalid;  //!< Check if a single instance (or a list of instances) is valid
+   qx_query query;               //!< Query which contains all results
+   long count;                   //!< Count how many items in database using a query or not
+   qx_bool exist;                //!< Check if a single instance (or a list of instances) exist in database
+
+};
+
+typedef boost::shared_ptr<services::blog_output> blog_output_ptr;
+
+} // namespace services
+
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_input, qx::service::IxParameter, 0, services_blog_input)
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_output, qx::service::IxParameter, 0, services_blog_output)
+
+
+ * blog.services.gen.cpp file :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_input, services_blog_input)
+QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_output, services_blog_output)
+
+namespace qx {
+
+template <>
+void register_class(QxClass<services::blog_input> & t)
+{
+   t.data(& services::blog_input::id, "id");
+   t.data(& services::blog_input::instance, "instance");
+   t.data(& services::blog_input::list, "list");
+   t.data(& services::blog_input::query, "query");
+   t.data(& services::blog_input::columns, "columns");
+   t.data(& services::blog_input::relations, "relations");
+}
+
+template <>
+void register_class(QxClass<services::blog_output> & t)
+{
+   t.data(& services::blog_output::instance, "instance");
+   t.data(& services::blog_output::list, "list");
+   t.data(& services::blog_output::error, "error");
+   t.data(& services::blog_output::invalid, "invalid");
+   t.data(& services::blog_output::query, "query");
+   t.data(& services::blog_output::count, "count");
+   t.data(& services::blog_output::exist, "exist");
+}
+
+} // namespace qx
+
+

+ Note : input/output parameters can contain complex structures (containers, + smart-pointers, etc...). + So it is very easy to transfer complex classes (for example with relationships) with QxService module. +

+
+

Define service functions + exposed to clients

+
+ Each service registered in QxService module exposes a list of functions to clients (client/server + queries). + All services must inherit from qx::service::QxService<INPUT, OUTPUT> base class (INPUT and + OUTPUT template parameters are explained in chapter : Input/output + service parameters, request/response) and must be registered in QxOrm context (with + void qx::register_class<T> function). +

+ For example : here is a service example generated by QxEntityEditor application + based on blog class of qxBlog tutorial : +

+ * blog.services.gen.h file :
+ + + + + + + +
+
namespace services {
+
+/* -- Service Definition -- */
+
+typedef qx::service::QxService< blog_input, blog_output > blog_base_class;
+class QXBLOG_SERVICES_EXPORT blog_services : public blog_base_class
+{
+
+   QX_REGISTER_FRIEND_CLASS(services::blog_services)
+
+public:
+
+   blog_services();
+   virtual ~blog_services();
+
+protected:
+
+   void fetchById_();
+   void fetchAll_();
+   void fetchByQuery_();
+
+   void insert_();
+   void update_();
+   void save_();
+   void deleteById_();
+   void deleteAll_();
+   void deleteByQuery_();
+   void destroyById_();
+   void destroyAll_();
+   void destroyByQuery_();
+
+   void executeQuery_();
+   void callQuery_();
+   void exist_();
+   void count_();
+   void isValid_();
+
+#ifdef _QXBLOG_SERVICES_MODE_CLIENT
+
+public:
+
+   blog_ptr fetchById(long id, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchById(blog_ptr & p, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchById(list_of_blog_ptr & lst, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchAll(list_of_blog_ptr & lst, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchByQuery(const qx_query & query, list_of_blog_ptr & lst, const QStringList & columns = QStringList(),
+                                       const QStringList & relations = QStringList());
+
+   QSqlError insert(blog_ptr & p, const QStringList & relations = QStringList());
+   QSqlError insert(list_of_blog_ptr & lst, const QStringList & relations = QStringList());
+   QSqlError update(blog_ptr & p, const qx_query & query = qx_query(),
+                              const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError update(list_of_blog_ptr & lst, const qx_query & query = qx_query(),
+                              const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError save(blog_ptr & p, const QStringList & relations = QStringList());
+   QSqlError save(list_of_blog_ptr & lst, const QStringList & relations = QStringList());
+
+   QSqlError deleteById(long id);
+   QSqlError deleteById(blog_ptr & p);
+   QSqlError deleteById(list_of_blog_ptr & lst);
+   QSqlError deleteAll();
+   QSqlError deleteByQuery(const qx_query & query);
+   QSqlError destroyById(long id);
+   QSqlError destroyById(blog_ptr & p);
+   QSqlError destroyById(list_of_blog_ptr & lst);
+   QSqlError destroyAll();
+   QSqlError destroyByQuery(const qx_query & query);
+
+   QSqlError executeQuery(qx_query & query, blog_ptr & p);
+   QSqlError executeQuery(qx_query & query, list_of_blog_ptr & lst);
+   QSqlError callQuery(qx_query & query);
+   qx_bool exist(blog_ptr & p);
+   qx_bool exist(list_of_blog_ptr & lst);
+   QSqlError count(long & lCount, const qx_query & query = qx_query());
+   qx::QxInvalidValueX isValid(blog_ptr & p);
+   qx::QxInvalidValueX isValid(list_of_blog_ptr & lst);
+
+#endif // _QXBLOG_SERVICES_MODE_CLIENT
+
+};
+
+typedef boost::shared_ptr<services::blog_services> blog_services_ptr;
+
+} // namespace services
+
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_services, qx::service::IxService, 0, services_blog_services)
+
+
+ * blog.services.gen.cpp file :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_services, services_blog_services)
+
+namespace qx {
+
+template <>
+void register_class(QxClass<services::blog_services> & t)
+{
+   t.fct_0<void>(& services::blog_services::fetchById_, "fetchById");
+   t.fct_0<void>(& services::blog_services::fetchAll_, "fetchAll");
+   t.fct_0<void>(& services::blog_services::fetchByQuery_, "fetchByQuery");
+
+   t.fct_0<void>(& services::blog_services::insert_, "insert");
+   t.fct_0<void>(& services::blog_services::update_, "update");
+   t.fct_0<void>(& services::blog_services::save_, "save");
+   t.fct_0<void>(& services::blog_services::deleteById_, "deleteById");
+   t.fct_0<void>(& services::blog_services::deleteAll_, "deleteAll");
+   t.fct_0<void>(& services::blog_services::deleteByQuery_, "deleteByQuery");
+   t.fct_0<void>(& services::blog_services::destroyById_, "destroyById");
+   t.fct_0<void>(& services::blog_services::destroyAll_, "destroyAll");
+   t.fct_0<void>(& services::blog_services::destroyByQuery_, "destroyByQuery");
+
+   t.fct_0<void>(& services::blog_services::executeQuery_, "executeQuery");
+   t.fct_0<void>(& services::blog_services::callQuery_, "callQuery");
+   t.fct_0<void>(& services::blog_services::exist_, "exist");
+   t.fct_0<void>(& services::blog_services::count_, "count");
+   t.fct_0<void>(& services::blog_services::isValid_, "isValid");
+}
+
+} // namespace qx
+
+// Then there is the implementation of all functions provided by the service...
+
+

+ Note : once registered in QxOrm context, all clients connected to server can call these + functions exposed by the service : server routines are executed automatically. + Data serialization and network layer to transfer persistent classes are managed automatically by + QxService module. +

+
+

List of options available + on server side

+
+ C++ application server based on QxService module provides several parameters in qx::service::QxConnect singleton class : +
    +
  • setPort() : listening port number to receive request from client and send response + from server ;
  • +
  • setThreadCount() : threads count available on server side to manage several client + requests at the same time ;
  • +
  • setSerializationType() : serialization type used to send + response from server to client ;
  • +
  • setCompressData() : define if data sent from server to client are compressed or + not ;
  • +
  • setEncryptData() : define if data sent from server to client are encrypted or not + (with possibility to configure an encryption key).
  • +
+
+
+

Connection settings on + client side

+
+ Client layer based on QxService module provides several parameters in qx::service::QxConnect singleton class : +
    +
  • setIp() : IP address of C++ application server ;
  • +
  • setPort() : port number used by C++ application server ;
  • +
  • setSerializationType() : serialization type used by + client layer to send requests from client to server ;
  • +
  • setCompressData() : define if data sent from client to server are compressed or + not ;
  • +
  • setEncryptData() : define if data sent from client to server are encrypted or not + (with possibility to configure an encryption key).
  • +
+
+
+

Service + authentication

+
+ It is often necessary to add a control on server side to check users connected on client side. + qx::service::IxService interface (base class for all services registered + in QxService module) + provides virtual methods which can be overridden to manage authentication : +
    +
  • onBeforeProcess() : virtual method called before server routine execution ;
  • +
  • onAfterProcess() : virtual method called after server routine execution.
  • +
+
+ For example : here is a class named ParameterAuthentication which can be used as + base class for all other parameters, this class provides 3 properties login, + password and token : +

+ * ParameterAuthentication.h file :
+ + + + + + + +
+
class MY_DLL_EXPORT ParameterAuthentication : public qx::service::IxParameter
+{
+ 
+public:
+ 
+   ParameterAuthentication();
+   virtual ~ParameterAuthentication();
+ 
+   QString login;
+   QString password;
+   QString token;
+   // etc..., put here all properties required by the authentication process
+ 
+};
+ 
+typedef boost::shared_ptr<ParameterAuthentication> ParameterAuthentication_ptr;
+ 
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_MY_DLL(ParameterAuthentication, qx::service::IxParameter, 0, ParameterAuthentication)
+
+
+ * ParameterAuthentication.cpp file :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_MY_DLL(ParameterAuthentication, ParameterAuthentication)
+ 
+namespace qx {
+ 
+template <>
+void register_class(QxClass<ParameterAuthentication> & t)
+{
+   t.data(& ParameterAuthentication::login, "login");
+   t.data(& ParameterAuthentication::password, "password");
+   t.data(& ParameterAuthentication::token, "token");
+}
+ 
+} // namespace qx
+
+

+ We have a base class for all parameters (ParameterAuthentication), we will now create a + base class for all services named ServiceAuthentication<INPUT, OUTPUT>. + This service base class will override onBeforeProcess() virtual method to manage + authentication before each service routine execution : +

+ * ServiceAuthentication.h file :
+ + + + + + + +
+
#include "ParameterAuthentication.h"
+ 
+template <class INPUT, class OUTPUT>
+class ServiceAuthentication : public qx::service::QxService<INPUT, OUTPUT>
+{
+ 
+public:
+ 
+   ServiceAuthentication(const QString & sServiceName) : qx::service::QxService<INPUT, OUTPUT>(sServiceName) { ; }
+   virtual ~ServiceAuthentication() { ; }
+ 
+   virtual void onBeforeProcess()
+   {
+      // Here you can implement your own authentication control (checking login/password for example)
+      // You can get input authentication parameters like this :
+      ParameterAuthentication_ptr pParams = getInputParameter();
+      pParams->login, pParams->password, etc...
+ 
+      // If authentication is not valid, then you can throw an exception (and stop process before executing service function)
+      throw qx::exception("Authentication error !");
+   }
+ 
+};
+
+

+ Now we have ParameterAuthentication base class and ServiceAuthentication<INPUT, + OUTPUT> base class : all parameters and services must inherit from these classes to + manage automatically authentication, and return an error message to client when user settings + are not valid. +

+ Note : like authentication, it is possible to manage logs on server side using + onBeforeProcess() and onAfterProcess() virtual methods. +

+
+

Async client/server + queries

+
+ By default, all client/server queries are synchronous operations : that means that client layer + waits for server response to continue its execution. + With a user interface (GUI), a client/server query locks application (freeze) if + it is executed in the main thread : so if server response is not sent quickly, users could think + that the application is crashed. + QxService module provides + an easy way to perform asynchronous client/server queries (so without freezing GUI user + interface) with qx::service::QxClientAsync class. +

+ qx::service::QxClientAsync class is based on introspection engine of QxOrm library and Qt SIGNAL-SLOT + feature. + qx::service::QxClientAsync class requires : +
    +
  • a service instance ;
  • +
  • input/output service parameters ;
  • +
  • server routine name to execute (string format) ;
  • +
  • a callback function called at the end of the transaction (connection to finished() + signal event). +
  • +
+
+ Here is an example from qxClientServer tutorial which + runs a server routine asynchronously : +

+ + + + + + + +
+
void main_dlg::onClickBtnDateTimeAsync()
+{
+   if (m_pDateTimeAsync) { qDebug("[QxOrm] '%s' transaction is already running", "server_infos::get_current_date_time"); return; }
+
+   // Cr�ation d'une instance de service et appel � la m�thode pour recevoir la date-heure courante du serveur (mode asynchrone)
+   server_infos_ptr service = server_infos_ptr(new server_infos());
+   m_pDateTimeAsync.reset(new qx::service::QxClientAsync());
+   QObject::connect(m_pDateTimeAsync.get(), SIGNAL(finished()), this, SLOT(onDateTimeAsyncFinished()));
+   m_pDateTimeAsync->setService(service, "get_current_date_time");
+   m_pDateTimeAsync->start();
+}
+
+void main_dlg::onDateTimeAsyncFinished()
+{
+   if (! m_pDateTimeAsync || ! m_pDateTimeAsync->getService()) { return; }
+   updateLastTransactionLog(m_pDateTimeAsync->getService()->getTransaction());
+   m_pDateTimeAsync.reset();
+}
+
+

+ Note : above example shows how to perform an asynchronous client/server query with these + steps : +
    +
  • create a service instance (of server_infos_ptr type in this example) ;
  • +
  • create a qx::service::QxClientAsync instance ;
  • +
  • connect finished event to a callback function (named + onDateTimeAsyncFinished() in this example) ; +
  • +
  • pass service instance and service function name to execute to + qx::service::QxClientAsync object ; +
  • +
  • run the transaction calling start() method.
  • +
+
+
+
+ +

Model View engine + (QxModelView module)

+
+ QxModelView module + provides an easy way to work with Qt + model/view engine with all C++ classes registered in QxOrm context : +
    +
  • QML : each property defined in QxOrm context is exposed to QML + engine : QxModelView module makes easier integration between QML and + databases ;
  • +
  • Qt widgets : QTableView or QListView for example to + display/modify a database table content.
  • +
+ qx::IxModel interface + provides a generic way for all models linked to persistent classes registered in QxOrm context. + All methods of this class prefixed by 'qx' call functions from qx::dao namespace and then + communicate with database. + qx::IxModel interface + provides also Q_INVOKABLE methods which can be called in QML files + : +
    +
  • qxCount_() : entities count in table mapped to model (possibility to add a SQL query + filter) ;
  • +
  • qxFetchById_() : fetch model properties based on its identifier ;
  • +
  • qxFetchAll_() : fetch model with all entities in table mapped to model ;
  • +
  • qxFetchByQuery_() : fetch model with entities in table mapped to model filtered by a + SQL query ;
  • +
  • qxFetchRow_() : fetch (update) a model row (each model row provides its own + identifier) ;
  • +
  • qxInsert_() : insert all model entities (all model rows) to database ;
  • +
  • qxInsertRow_() : insert a model row to database ;
  • +
  • qxUpdate_() : update all model entities (all model rows) to database ;
  • +
  • qxUpdateRow_() : update a model row to database ;
  • +
  • qxSave_() : save all model entities (all model rows) to database (insert or update) ; +
  • +
  • qxSaveRow_() : save a model row to database (insert or update) ;
  • +
  • qxDeleteById_() : delete an entity from database based on the identifier parameter ; +
  • +
  • qxDeleteAll_() : delete all entities in table mapped to model ;
  • +
  • qxDeleteByQuery_() : delete entities in table mapped to model based on a SQL query ; +
  • +
  • qxDeleteRow_() : delete a model row in database (each model row provides its own + identifier) ;
  • +
  • qxDestroyById_() : delete an entity from database based on the identifier parameter + (support soft delete behaviour, logical delete) ;
  • +
  • qxDestroyAll_() : delete all entities in table mapped to model (support soft delete behaviour, logical delete) ;
  • +
  • qxDestroyByQuery_() : delete entities in table mapped to model based on a SQL query + (support soft delete behaviour, logical delete) ;
  • +
  • qxDestroyRow_() : delete a model row in database (each model row provides its own + identifier), support soft delete behaviour, logical delete ;
  • +
  • qxExecuteQuery_() : fetch model using a custom SQL query or + stored procedure ;
  • +
  • qxExist_() : check if an entity already exists based on the identifier parameter ; +
  • +
  • qxValidate_() : check validity of all model content (QxValidator module) ;
  • +
  • qxValidateRow_() : check validity of a model row (QxValidator + module).
  • +
+
+ Note : qxBlogModelView sample project in ./test/ directory of QxOrm package + shows how to create quickly a QxOrm model and associate it to the Qt model/view engine + (first with a Qt widget, then with a QML view). +

+

Simple model (without + relationship)

+
+ All classes registered in QxOrm context can be used as a model to display/modify values in + views. + qx::IxModel QxOrm model + base class inherits from Qt QAbstractItemModel base class : so QxOrm models are full compatible with + Qt model/view engine. +

+ Only 1 line in C++ source code to instantiate a QxOrm model : +

+ + + + + + + +
+
   qx::IxModel * pModel = new qx::QxModel<MyClass>();   
+
+
+ Note : the QxOrm model created with this line of code exposes automatically all + properties registered in QxOrm context to Qt model/view engine. +

+
+

Model with relationships + (nested models)

+
+ Associate class relationships (1-n, n-1 and n-n) to Qt model/view engine is + complex : the solution provided by QxOrm library is based on nested models concept. + For more details about nested models concept, a french tutorial is available on famous developpez.com forum. +

+ To use relationships (1-n, n-1 and n-n) with QxModelView module, it + is very important to understand that there is a hierarchy between models (a parent model + can be associated to several child models, this is the nested models concept). +

+ To be able to work with relationships (nested models), it is necessary to create derived classes + based on qx::QxModel<T> base class. + This way, all simple properties (not relationship) are automatically exposed to views (thanks to + the base class), the only thing to do is to write accessors to manage relationships. + QxEntityEditor application is deployed with QxEECppModelViewExport plugin : + this plugin generates source code automatically to work with nested models. +

+ Here is a source code example generated by QxEntityEditor application to create a QxOrm + model based on blog class (read qxBlog + tutorial for more details). + blog class defines 3 relationships : author (n-1), list_of_comment (1-n) + and list_of_category (n-n) : +

+ * blog.model_view.gen.h file :
+ + + + + + + +
+
namespace model_view {
+
+typedef qx::QxModel<blog> blog_model_base_class;
+
+class QXBLOG_MODEL_VIEW_EXPORT blog_model : public blog_model_base_class
+{
+
+   Q_OBJECT
+
+public:
+
+   blog_model(QObject * parent = 0);
+   blog_model(qx::IxModel * other, QObject * parent);
+   virtual ~blog_model();
+
+   Q_INVOKABLE QObject * author(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+   Q_INVOKABLE QObject * list_of_comment(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+   Q_INVOKABLE QObject * list_of_category(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+
+   /* List of properties exposed by the model (3) :
+      - blog_id
+      - title
+      - text
+   */
+
+protected:
+
+   virtual void syncNestedModel(int row, const QStringList & relation);
+   virtual void syncAllNestedModel(const QStringList & relation);
+
+};
+
+} // namespace model_view
+
+
+ * blog.model_view.gen.cpp file :
+
+
namespace model_view {
+
+blog_model::blog_model(QObject * parent /* = 0 */) : blog_model_base_class(parent) { ; }
+
+blog_model::blog_model(qx::IxModel * other, QObject * parent) : blog_model_base_class(other, parent) { ; }
+
+blog_model::~blog_model() { ; }
+
+QObject * blog_model::author(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "author";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_author value = ptr->getauthor();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getauthor();
+      ptr->setauthor(value);
+   }
+
+   model_view::author_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "author", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+QObject * blog_model::list_of_comment(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "list_of_comment";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_list_of_comment value = ptr->getlist_of_comment();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getlist_of_comment();
+      ptr->setlist_of_comment(value);
+   }
+
+   model_view::comment_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "list_of_comment", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+QObject * blog_model::list_of_category(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "list_of_category";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_list_of_category value = ptr->getlist_of_category();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getlist_of_category();
+      ptr->setlist_of_category(value);
+   }
+
+   model_view::category_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "list_of_category", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+void blog_model::syncNestedModel(int row, const QStringList & relation)
+{
+   Q_UNUSED(relation);
+   qx::IxModel * pNestedModel = NULL;
+   if ((row < 0) || (row >= this->m_model.count())) { return; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { return; }
+
+   pNestedModel = this->getChild(row, "author");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_author value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setauthor(value);
+   }
+
+   pNestedModel = this->getChild(row, "list_of_comment");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_list_of_comment value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setlist_of_comment(value);
+   }
+
+   pNestedModel = this->getChild(row, "list_of_category");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_list_of_category value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setlist_of_category(value);
+   }
+}
+
+void blog_model::syncAllNestedModel(const QStringList & relation)
+{
+   if (this->m_lstChild.count() <= 0) { return; }
+   for (long l = 0; l < this->m_model.count(); l++)
+   { this->syncNestedModel(static_cast<int>(l), relation); }
+}
+
+} // namespace model_view
+
+

+ Note : above example shows that the source code required to work with nested models is + verbose. + So to be able to work with models and relationships, it is strongly recommended to use + QxEntityEditor application to generate all C++ source code automatically. +

+
+

Interaction with QML + views

+
+ Here is an example in QML (with Qt5, QxModelView module supports Qt4 too). + This example uses 'author' table defined in qxBlog tutorial (source code of this QML example is available in + qxBlogModelView project sample of QxOrm package) :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QML view and display it
+QQuickView qmlView;
+qmlView.rootContext()->setContextProperty("myModel", pModel);
+qmlView.setSource(QUrl("qrc:/documents/main.qml"));
+qmlView.show();
+
+
+ Here is the 'main.qml' file content :
+
+ + + + + + + +
+
import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+Item {
+   width: 400
+   height: 300
+   Row {
+      height: 20
+      spacing: 20
+      Button {
+         text: "Clear"
+         onClicked: myModel.clear()
+      }
+      Button {
+         text: "Fetch All"
+         onClicked: myModel.qxFetchAll_()
+      }
+      Button {
+         text: "Save"
+         onClicked: myModel.qxSave_()
+      }
+   }
+   ListView {
+      y: 30
+      height: 270
+      model: myModel
+      delegate: Row {
+         height: 20
+         spacing: 10
+         Text { text: "id: " + author_id }
+         TextField {
+            text: name
+            onTextChanged: name = text
+         }
+      }
+   }
+}
+
+
+ After executing this code, following window should be displayed :
+
+ qx_model_view_02
+
+ Note : as you can see in the 'main.qml' file, 'author_id' and 'name' + properties of 'author' model (myModel variable) can be automatically read and + write (because they are registered in QxOrm context).
+ Moreover, qx::IxModel + interface provides a list of methods for QML side (Q_INVOKABLE) to communicate with + database : for example, the 'Save' button will save the model in database without having + to write a C++ function.
+
+ Other note : a QxEntityEditor plugin generates automatically + source code to manage relationships using nested models concept (for more details about + nested models concept, please read this french tutorial on famous developpez.com web site). +

+
+

Interaction with QtWidget + views

+
+ Here is an example to display/modify data from 'author' table (read qxBlog tutorial for 'author' class + definition) in a QTableView + (source code of this example is available in qxBlogModelView project sample of QxOrm + package) :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QTableView and display it
+QTableView tableView;
+tableView.setModel(pModel);
+tableView.show();
+
+
+ After executing this code, following window should be displayed :
+
+ qx_model_view_01
+
+ Note : Qt provides several QtWidget views which can be mapped to a model, for + example : QListView, QTableView, QTreeView. + It is also possible to use QDataWidgetMapper class to create your own form based on a model (a french tutorial is available on developpez.com web site). +

+
+

Connect model to + QxService module

+
+ QxModelView module + provides qx::QxModelService<T, S> class template (which inherits from : qx::QxModel<T> + >> qx::IxModel + >> QAbstractItemModel). + This class has 2 template parameters : +
    +
  • T : class registered in QxOrm context with all properties exposed to Qt model/view engine ; +
  • +
  • S : service class of QxService module to access/modify + data from model (client/server requests).
  • +
+ Data provided by this model comes from client/server requests thanks to QxService module (so data are not received from a database SQL query). + The S service class must provide some methods : +
    +
  • count() : client/server request to count entities in table mapped to model (with + possibility to add a SQL query filter) ;
  • +
  • fetchById() : client/server request to fetch model properties based on identifier + parameter ;
  • +
  • fetchAll() : client/server request to fetch model with all entities in table + mapped to model ;
  • +
  • fetchByQuery() : client/server request to fetch model with entities in table + mapped to model filtered by a SQL query ;
  • +
  • insert() : client/server request to insert model data to database ;
  • +
  • update() : client/server request to update model data to database ;
  • +
  • save() : client/server request to save model data to database (insert or update) ; +
  • +
  • deleteById() : client/server request to delete an entity based on identifier + parameter ;
  • +
  • deleteAll() : client/server request to delete all entities in table mapped to + model ;
  • +
  • deleteByQuery() : client/server request to delete entities in table mapped to + model based on a SQL query ;
  • +
  • destroyById() : client/server request to delete an entity based on identifier + parameter (support soft delete behaviour, logical delete) ; +
  • +
  • destroyAll() : client/server request to delete all entities in table mapped to + model (support soft delete behaviour, logical delete) ;
  • +
  • destroyByQuery() : client/server request to delete entities in table mapped to + model based on a SQL query (support soft delete behaviour, logical + delete) ;
  • +
  • executeQuery() : client/server request to execute a custom + SQL query or stored procedure ;
  • +
  • exist() : client/server request to check if model exists based on its identifier ; +
  • +
  • isValid() : client/server request to check model validity (QxValidator module).
  • +
+
+ Note : QxEntityEditor application is deployed with QxEECppServicesExport + and QxEECppModelViewExport plugins : these plugins generate automatically all C++ source + code required to work with QxOrm models and the QxService module. + So to use qx::QxModelService<T, S> class, it is strongly recommended to + use QxEntityEditor application to generate source code automatically. +

+
+
+ +

QxOrm and MongoDB database + (C++ ODM Object Document Mapper)

+
+ QxOrm library is able to connect to standard relational databases (MySQL, PostgreSQL, SQLite, + Oracle, Microsoft SQLServer, MariaDB, etc...), and is also able to connect to the NoSQL MongoDB database. +

+ From Wikipedia website : + MongoDB is a free and open-source cross-platform document-oriented database program. + Classified as a NoSQL database program, MongoDB uses JSON-like documents with schemas. +

+ MongoDB database has several advantages compared to standard relational databases (non-exhaustive + list) : +
    +
  • Schema-less : you don't have to maintain tables and columns (so you don't need to + write some complex scripts to migrate your database from one version to another version). + MongoDB Collections can contain Documents with different fields, of different + sizes, etc... About QxOrm library, that means that you can write your C++ persistent classes + without having to deal with DDL database schema (useful in AGILE development + environment for example) ;
  • +
  • Data are stored in BSON format (similar to JSON) : easy to read even with complex + data structures ;
  • +
  • Powerful and flexible JSON query engine with possibility to put indexes on any fields + of MongoDB Documents ;
  • +
  • MongoDB database is free of charge, and provides a support for professionals ; +
  • +
  • From MongoDB version 3.6 : MongoDB query engine provides a way to simulate JOINS + queries (between Documents) like standard relational databases.
  • +
+
+ QxOrm library API is the same for MongoDB database and any other standard relational databases. + All QxOrm library features are available for MongoDB database : so everything in this user guide + can be applied to MongoDB database. + Main differences to take into account are : +
    +
  • It is recommended to define a C++ primary key of type QString. There is no numeric + auto-incremented value : MongoDB provides an ObjectId type which can be mapped to QString C++ + type and generated automatically (you can also create your own custom C++ type to map to + MongoDB ObjectId).
  • +
  • Queries are not SQL : MongoDB provides a JSON query engine.
  • +
+
+ Note : QxOrm package provides a sample project named qxBlogMongoDB (in ./test/ + directory). + This sample project shows how to connect and work with MongoDB database and QxOrm library. +

+

Prerequisites : driver + libmongoc and libbson

+
+ QxOrm library is based on QtSql + module from Qt framework : this module doesn't provide connectors to MongoDB database. + So QxOrm library requires 2 extra-dependencies to connect to MongoDB database : + +
+ A guide is + available to install these libraries (libmongoc and libbson) on your + development environment. +

+
+

QxOrm.pri (or + QxOrm.cmake) configuration file

+
+ Once libmongoc and libbson libraries are installed on your development + environment, you have to enable _QX_ENABLE_MONGODB compilation option in QxOrm.pri + (or QxOrm.cmake) configuration file. +

+ + + + + + + +
+
#######################################
+# MongoDB Driver Library Dependencies #
+#######################################
+
+# If you enable _QX_ENABLE_MONGODB option, then QxOrm library will be able to use mongoc driver to store all QxOrm registered classes in a MongoDB database
+# When _QX_ENABLE_MONGODB compilation option is defined, you must provide following paths to manage mongoc library dependencies :
+#  - a BSON_INCLUDE environment variable to define where bson library source code is located (or a QX_BSON_INCLUDE_PATH qmake variable)
+#  - a MONGOC_INCLUDE environment variable to define where mongoc library source code is located (or a QX_MONGOC_INCLUDE_PATH qmake variable)
+#  - a BSON_LIB environment variable to define where bson library is located (or a QX_BSON_LIB_PATH qmake variable)
+#  - a MONGOC_LIB environment variable to define where mongoc library is located (or a QX_MONGOC_LIB_PATH qmake variable)
+
+

+ Note : once _QX_ENABLE_MONGODB compilation option is defined, you can build and + execute qxBlogMongoDB sample project in ./test/ directory to validate your + development environment with QxOrm and MongoDB. +

+
+

Connection to MongoDB + database

+
+ Here is an example of settings to connect to MongoDB database : +

+ + + + + + + +
+
// Parameters to connect to MongoDB database
+qx::QxSqlDatabase * pDatabase = qx::QxSqlDatabase::getSingleton();
+pDatabase->setDriverName("QXMONGODB");
+pDatabase->setDatabaseName("qxBlog");
+pDatabase->setHostName("localhost");
+pDatabase->setPort(27017);
+pDatabase->setUserName("");
+pDatabase->setPassword("");
+
+

+
+

Register a MongoDB + persistent class (Collection) in QxOrm context (mapping)

+
+ Register a MongoDB persistent class in QxOrm context is similar to register a persistent class for any other standard relational + databases. + Here is a persistent class example from qxBlogMongoDB sample project : +

+ File blog.h : + + + + + + + +
+
#ifndef _QX_BLOG_BLOG_H_
+#define _QX_BLOG_BLOG_H_
+
+#include "author.h"
+#include "comment.h"
+#include "category.h"
+
+class QX_BLOG_DLL_EXPORT blog
+{
+public:
+// -- properties
+   QString        m_id;
+   QString        m_text;
+   QDateTime      m_dt_creation;
+   author_ptr     m_author;
+   list_comment   m_commentX;
+   list_category  m_categoryX;
+// -- contructor, virtual destructor
+   blog() { ; }
+   virtual ~blog() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(blog, QString)
+QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)
+
+typedef std::shared_ptr<blog> blog_ptr;
+typedef std::vector<blog_ptr> list_blog;
+
+#endif // _QX_BLOG_BLOG_H_
+
+
+ File blog.cpp : + + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(blog)
+
+namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   t.id(& blog::m_id, "blog_id");
+
+   t.data(& blog::m_text, "blog_text");
+   t.data(& blog::m_dt_creation, "date_creation");
+   t.data(& blog::m_categoryX, "list_category"); // Embedded relationship
+
+   t.relationManyToOne(& blog::m_author, "author_id"); // Referenced relationship
+   t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); // Referenced relationship
+}}
+
+
+ Note : this example shows how to define : + +
+

Manage ObjectId + (primary key)

+
+ It is recommended to define a C++ primary key of type QString. + There is no numeric auto-incremented value : MongoDB + provides an ObjectId type which can be mapped to QString C++ type and generated + automatically (you can also create your own custom C++ type to map to MongoDB ObjectId). +

+
+
+

Insert a C++ instance + (Document) in MongoDB database

+
+ Here is an example to insert a document in MongoDB database with primary key generated + automatically (MongoDB ObjectId) : +

+ + + + + + + +
+
// Insert one author without id
+author_ptr author_1 = std::make_shared<author>();
+author_1->m_name = "author_1";
+author_1->m_sex = author::male;
+author_1->m_birthdate = QDate(1998, 07, 12);
+daoError = qx::dao::insert(author_1);
+
+

+ Here is an example to insert a document in MongoDB database providing a custom primary key : +

+ + + + + + + +
+
// Insert one author with a custom id
+author_ptr author_2 = std::make_shared<author>();
+author_2->m_id = "my_custom_id_author_2";
+author_2->m_name = "author_2";
+author_2->m_sex = author::female;
+author_2->m_birthdate = QDate(2003, 02, 28);
+daoError = qx::dao::insert(author_2);
+
+

+

Insert many C++ + instances (list of Documents) in MongoDB database

+
+ Here is an example to insert several documents in MongoDB database : +

+ + + + + + + +
+
// Insert many authors with/without ids
+QList<author> authorX;
+author author_3; author_3.m_name = "author_3"; author_3.m_sex = author::female; author_3.m_birthdate = QDate(1968, 05, 01);
+author author_4; author_4.m_id = "my_custom_id_author_4"; author_4.m_name = "author_4"; author_4.m_sex = author::male;
+author author_5; author_5.m_name = "author_5"; author_5.m_sex = author::female; author_5.m_birthdate = QDate(1978, 03, 03);
+authorX.append(author_3); authorX.append(author_4); authorX.append(author_5);
+daoError = qx::dao::insert(authorX);
+
+

+ Note : QxOrm library supports several C++ types to manage lists + and collections. +

+
+
+

Update a C++ instance + (Document) in MongoDB database

+
+ Here is an example to update a document in MongoDB database : +

+ + + + + + + +
+
// Update one author
+author author_4;
+author_4.m_id = "my_custom_id_author_4";
+author_4.m_name = "author_4_modified";
+daoError = qx::dao::update(author_4);
+
+

+

Update many C++ + instances (list of Documents) in MongoDB database

+
+ Here is an example to update several documents in MongoDB database : +

+ + + + + + + +
+
// Update many authors
+QList<author> authorX;
+author_3.m_name = "author_3_modified_twice"; authorX.append(author_3);
+author_2->m_name = "author_2_modified"; authorX.append(* author_2);
+author_1->m_name = "author_1_modified"; authorX.append(* author_1);
+daoError = qx::dao::update(authorX);
+
+

+ Note : QxOrm library supports several C++ types to manage lists + and collections. +

+
+
+

Delete a C++ instance + (Document) from MongoDB database

+
+ Here is an example to delete a document from MongoDB database : +

+ + + + + + + +
+
// Delete one author by id
+author_ptr pAuthor = std::make_shared<author>();
+pAuthor->m_id = "my_custom_id_author_4";
+daoError = qx::dao::delete_by_id(pAuthor);
+
+

+

Delete many C++ + instances (list of Documents) from MongoDB database

+
+ Here is an example to delete several documents from MongoDB database by identifier (primary + key) : +

+ + + + + + + +
+
// Delete many authors by id
+QList<author> authorX;
+author_3.m_id = "id_author_3"; authorX.append(author_3);
+author_2->m_id = "id_author_2"; authorX.append(* author_2);
+author_1->m_id = "id_author_1"; authorX.append(* author_1);
+daoError = qx::dao::delete_by_id(authorX);
+
+

+ Here is an example to delete several documents from MongoDB database by JSON query : +

+ + + + + + + +
+
// Delete authors by query (all male)
+qx_query query{ { "sex", author::male } };
+daoError = qx::dao::delete_by_query<author>(query);
+
+

+ To delete all documents from author collection : +

+ + + + + + + +
+
// Delete all authors
+daoError = qx::dao::delete_all<author>();
+
+

+ Note : QxOrm library supports several C++ types to manage lists + and collections. +

+
+
+

Fetch a C++ instance + (Document) from MongoDB database

+
+ Here is an example to fetch a document from MongoDB database by identifier (primary key) : +

+ + + + + + + +
+
// Fetch one author by id
+author_ptr pAuthor = std::make_shared<author>();
+pAuthor->m_id = "my_custom_id_author_2";
+daoError = qx::dao::fetch_by_id(pAuthor);
+
+

+

Fetch many C++ + instances (list of Documents) from MongoDB database

+
+ Here is an example to fetch several documents from MongoDB database by identifier (primary + key) : +

+ + + + + + + +
+
// Fetch many authors by id
+QList<author> authorX;
+author_3.m_id = "id_author_3"; authorX.append(author_3);
+author_2->m_id = "id_author_2"; authorX.append(* author_2);
+author_1->m_id = "id_author_1"; authorX.append(* author_1);
+daoError = qx::dao::fetch_by_id(authorX);
+
+

+ Here is an example to fetch several documents from MongoDB database by JSON query : +

+ + + + + + + +
+
// Fetch many authors by query (only female)
+list_author list_of_female_author;
+qx_query query{ { "sex", author::female } };
+daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+
+

+ Here is an example to fetch all documents from author collection in MongoDB database : +

+ + + + + + + +
+
// Fetch all authors
+list_author allAuthors;
+daoError = qx::dao::fetch_all(allAuthors);
+
+

+ Here is an example to fetch all documents from author collection in MongoDB database + (providing which fields/columns to fetch) : +

+ + + + + + + +
+
// Fetch all authors (with only 'date_creation' and 'name' properties)
+list_author allAuthors;
+QStringList columns = QStringList() << "date_creation" << "name";
+daoError = qx::dao::fetch_all(allAuthors, NULL, columns);
+
+

+ Note : QxOrm library supports several C++ types to manage lists + and collections. +

+
+
+

JSON queries

+
+ The main difference between standard relational databases and MongoDB database is query format : + instead of SQL, MongoDB provides a JSON query + engine. +

+

Using qx::QxSqlQuery + class (or qx_query alias)

+
+ qx::QxSqlQuery class (or qx_query alias) used to build standard + SQL queries is also able to build JSON queries for MongoDB database. + This class is based on C++11 std::initializer_list feature to write C++ queries like JSON + queries (similar syntax). + Please note that you can also write your JSON query with a string (if your compiler doesn't + support C++11 std::initializer_list feature for example). + For example : +

+ + + + + + + +
+
// Fetch many authors by query (only female)
+list_author list_of_female_author;
+qx_query query { { "sex", author::female } };
+daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+
+

+
+

Using MongoDB + aggregation framework

+
+ MongoDB database provides a powerful aggregation framework to build queries. + Here is an example to call this MongoDB aggregation engine with qx::QxSqlQuery class (or qx_query alias), the first constructor + parameter must be equal to aggregate : +

+ + + + + + + +
+
// Fetch by query using MongoDB aggregation framework (only female)
+list_author list_of_female_author;
+qx_query queryAggregate("aggregate",
+               "[ { \"$match\" : { \"sex\" : " + QString::number(static_cast<int>(author::female)) + " } } ]");
+daoError = qx::dao::fetch_by_query(queryAggregate, list_of_female_author);
+
+

+
+

Add 'sort', 'limit', + 'skip', etc..., properties to JSON query

+
+ It is often required to limit data received from database, or to sort them. + To manage these operations, MongoDB database provides projection. + Here is an example of projection with qx::QxSqlQuery class (or + qx_query alias), see the QStringList constructor parameter (or second + constructor parameter with std::initializer_list) : +

+ + + + + + + +
+
// Fetch by query (only female) adding 'sort', 'limit', 'skip', etc... commands (see second query QStringList parameter)
+list_of_female_author.clear();
+qx_query queryOpts(QStringList() << "{ \"sex\" : " + QString::number(static_cast(author::female)) + " }"
+                              << "{ \"sort\" : { \"sex\" : -1 }, \"limit\" : 2 }");
+daoError = qx::dao::fetch_by_query(queryOpts, list_of_female_author);
+
+

+
+

Execute a custom + query

+
+ To execute a custom query in MongoDB database, QxOrm library provides the qx::dao::call_query() function. + Query results can be converted to QVariantMap or QList<QVariantMap> (if query returns a cursor) to + iterate over all database response. + Here are some examples of custom queries : +

+ + + + + + + +
+
// Drop database
+qx_query dropDB("{ \"dropDatabase\" : 1 }");
+QSqlError daoError = qx::dao::call_query(dropDB);
+
+

+ + + + + + + +
+
// Call a custom query and get JSON response as QVariantMap
+qx_query customQuery("{ \"find\": \"author\", \"filter\": { } }");
+daoError = qx::dao::call_query(customQuery); qAssert(! daoError.isValid());
+QString responseCustomQuery = customQuery.response().toString();
+QVariantMap responseCustomQueryAsJson;
+qx::serialization::json::from_string(responseCustomQueryAsJson, responseCustomQuery);
+
+

+ + + + + + + +
+
// Call a custom query with cursor and get JSON response as QList<QVariantMap>
+qx_query customQueryCursor("cursor", "{ \"find\": \"author\", \"filter\": { } }");
+daoError = qx::dao::call_query(customQueryCursor); qAssert(! daoError.isValid());
+QString responseCustomQueryCursor = customQueryCursor.response().toString();
+QList<QVariantMap> responseCustomQueryCursorAsJson;
+qx::serialization::json::from_string(responseCustomQueryCursorAsJson, responseCustomQueryCursor);
+
+

+
+
+

Relationships engine + (MongoDB version 3.6 or + is required)

+
+ QxOrm library relationship engine supports MongoDB database (MongoDB + version 3.6 or + is required). + So QxOrm library is able to fetch Document fields over several Collections using only one query + (similar to JOINS in SQL). +

+ Here is an example to fetch a Document and 1 level of relationships (parent > children) : +

+ + + + + + + +
+
// Fetch blog with all relations : 'author', 'comment' and 'category' (MongoDB version 3.6+ is required for relationships)
+blog_ptr blog = std::make_shared<blog>();
+blog->m_id = "id_blog_1";
+daoError = qx::dao::fetch_by_id_with_all_relation(blog);
+
+

+ Here is an example to fetch a Document and 4 levels of relationships (using + *->*->*->* syntax) : +

+ + + + + + + +
+
// Fetch blog with many relations using "*->*->*->*" (4 levels of relationships)
+blog_ptr blog = std::make_shared<blog>();
+blog->m_id = "id_blog_1";
+daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog);
+
+

+ Here is an example to fetch a Document providing a list of relationships and fields to fetch + (using { <col_1>, <col_2>, etc... } syntax) : +

+ + + + + + + +
+
// Fetch relations defining fields to fetch with syntax { col_1, col_2, etc... }
+list_blog lstBlogComplexRelation;
+QStringList relations = QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *";
+daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation);
+
+

+ Here is an example to fetch a Document providing a list of relationships and fields to not fetch + (using -{ <col_1>, <col_2>, etc... } syntax) : +

+ + + + + + + +
+
// Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... }
+list_blog lstBlogComplexRelation2;
+QStringList relations = QStringList() << "-{ blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *";
+daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation2);
+
+

+

Embedded vs + Referenced

+
+ One big advantage of MongoDB database is the possibility to store complex data structure (not + limited by a 2 dimensions table/column structure like standard relational databases). + A MongoDB Document can contain an objet and several sub-objects (hierarchy in Document + structure). + Include a sub-object in a Document has some advantages (no JOIN for example, so faster + to fetch) and some disadvantages (a same object can be duplicated in database). + So it is important to adopt the right strategy to store your data. +

+ QxOrm library supports both : +
    +
  • Embedded relationship : the sub-object is included in the Document ;
  • +
  • Referenced relationship : create a JOIN like standard relational + databases.
  • +
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   t.id(& blog::m_id, "blog_id");
+
+   t.data(& blog::m_text, "blog_text");
+   t.data(& blog::m_dt_creation, "date_creation");
+   t.data(& blog::m_categoryX, "list_category"); // Embedded relationship
+
+   t.relationManyToOne(& blog::m_author, "author_id"); // Referenced relationship
+   t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); // Referenced relationship
+}}
+
+

+
+
+

Create automatically + indexes

+
+ QxOrm library provides a way to generate indexes automatically (this function should be called + at the beginning of your program, for example in the main) : +
    +
  • all indexes to manage relationships between Collections (to optimize JOINS) ;
  • +
  • all indexes defined by qx::IxDataMember::setIndex() method (in qx::register_class() + function).
  • +
+
+ + + + + + + +
+
// To optimize queries : create automatically indexes based on relationships and properties marked as 'index'
+daoError = qx::dao::mongodb::QxMongoDB_Helper::autoCreateIndexes(true);
+
+

+
+

+
+ +

HTTP/HTTPS web server + (QxHttpServer module)

+
+ QxOrm library provides a standalone, multi-threaded and easy to use HTTP 1.1 web server named + QxHttpServer module (based on QxService module). + QxHttpServer module doesn't require any Apache or Nginx + installation. +

+ QxHttpServer module supports several features : + + Combined with QxRestApi module (which provides a JSON API to request your + persistent data layer), QxHttpServer module is designed to develop modern web applications. + For example, SPA + (Single-Page Applications) web applications with famous Javascript frameworks like AngularJS, React, Meteor.js, + etc... +

+ Note : to enable QxHttpServer module, you have to define _QX_ENABLE_QT_NETWORK compilation option in QxOrm.pri (ou QxOrm.cmake) configuration file. + _QX_ENABLE_QT_NETWORK compilation option adds a dependency to QtNetwork binary provided + by Qt library. +

+ Other note : QxOrm package contains a test project named + qxBlogRestApi. + This test project is a web application with several examples to request a persistent data layer + from a web page (HTML and Javascript). +

+

Hello World !

+
+ Here is a HTTP web server source code based on QxHttpServer module (this web server just + returns Hello World ! to web client) : +

+ + + + + + + +
+
#include <QtCore/qcoreapplication.h>
+#include <QxOrm.h>
+
+int main(int argc, char * argv[])
+{
+   QCoreApplication app(argc, argv);
+
+   // HTTP server settings
+   qx::service::QxConnect * serverSettings = qx::service::QxConnect::getSingleton();
+   serverSettings->setPort(9642); // HTTP server listening port
+   serverSettings->setKeepAlive(5000); // Keep-alive connection with client during 5s, then socket is disconnected and thread becomes available for other clients
+   serverSettings->setThreadCount(50); // Number of threads waiting for client's requests,
+                                                           // which means also how many requests can be handled simultaneously (in parallel) by HTTP server
+
+   // Create a QxOrm HTTP server instance
+   qx::QxHttpServer httpServer;
+
+   // Define all HTTP server routes (dispatcher) to handle requests
+   // Each callback is executed in a dedicated thread, so QxOrm HTTP server can handle several requests in parallel
+   httpServer.dispatch("GET", "/", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+      response.data() = "Hello World !";
+   });
+
+   // Start HTTP server
+   httpServer.startServer();
+
+   // Start event loop
+   return app.exec();
+}
+
+

+ Result : open a web browser (Chrome, Firefox, Safari, Internet Explorer, Opera, etc...) + and go to this URL : http://localhost:9642/. Your web browser should display : +

+ QxHttpServer Hello World ! +

+
+

HTTP/HTTPS web server + settings

+
+ HTTP web server settings are available with qx::service::QxConnect singleton class : +
    +
  • setPort() : web server listening port (default web server port is 80 but you can + define what you want) ;
  • +
  • setThreadCount() : number of threads used by web server to handle HTTP requests + (which means number of simultaneous clients managed by web server) ;
  • +
  • setMaxWait() : timeout in milli-seconds (for example to read/write on socket), -1 + value means no timeout ;
  • +
  • setCompressData() : if HTTP client supports GZIP compression, then text responses + (HTML / Javascript / CSS files, JSON stream, etc...) will be compressed as GZIP ;
  • +
  • setKeepAlive() : socket stay connected to client during X milli-seconds, -1 + value means never disconnect ;
  • +
  • setSessionTimeOut() : timeout in milli-seconds before deleting unused sessions (server side storage per client).
  • +
+
+

Secured connections + SSL/TLS

+
+ qx::service::QxConnect singleton class provides also some parameters + to manage HTTPS secured connections (SSL and/or TLS).
+ Here is a secured connection settings example with server certificate and CA certificate + authority (you can test this code with qxBlogRestApi project + example) : +

+ + + + + + + +
+
// Certificates created with this tutorial : https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/
+QFile::copy(":/documents/cert_qxorm_ca.pem", appPath.filePath("files/cert_qxorm_ca.pem"));
+QFile::copy(":/documents/cert_qxorm_server.crt", appPath.filePath("files/cert_qxorm_server.crt"));
+QFile::copy(":/documents/cert_qxorm_server.key", appPath.filePath("files/cert_qxorm_server.key"));
+
+QFile fileCertCA(appPath.filePath("files/cert_qxorm_ca.pem"));
+fileCertCA.open(QIODevice::ReadOnly);
+QList<QSslCertificate> certCA; certCA << QSslCertificate(fileCertCA.readAll());
+
+QFile fileCertServerPublic(appPath.filePath("files/cert_qxorm_server.crt"));
+fileCertServerPublic.open(QIODevice::ReadOnly);
+QSslCertificate certServerPublic(fileCertServerPublic.readAll());
+
+QFile fileCertServerPrivate(appPath.filePath("files/cert_qxorm_server.key"));
+fileCertServerPrivate.open(QIODevice::ReadOnly);
+QSslKey certServerPrivate(fileCertServerPrivate.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "qxorm");
+
+qx::service::QxConnect * serverSettings = qx::service::QxConnect::getSingleton();
+serverSettings->setSSLEnabled(true);
+serverSettings->setSSLCACertificates(certCA);
+serverSettings->setSSLLocalCertificate(certServerPublic);
+serverSettings->setSSLPrivateKey(certServerPrivate);
+
+
+

+ Note : by default, all SSL errors are ignored (often certificates errors). + To manage your own security level, you can use following functions (from qx::service::QxConnect singleton class) : + +
+
+
+

Routing URL (dispatcher / + endpoints)

+
+ QxHttpServer module provides an URL routing engine (dispatcher) to define + functions (or lambda) to execute based on HTTP request parameters (HTTP method GET, POST, + DELETE, etc... + URL).
+ Functions (or lambda) must be defined with this signature : void myRequestHandler(qx::QxHttpRequest & request, + qx::QxHttpResponse & response); +

+ qx::QxHttpServer class (or its qx_http_server alias) has following methods : +
    +
  • setCustomRequestHandler() : define a function (or lambda) executed if dispatcher + doesn't find any other matched function ;
  • +
  • dispatch() : first parameter is HTTP method (GET, POST, DELETE, etc...), + second parameter is requested URL (or its pattern), third parameter is function (or + lambda) to execute ;
  • +
  • beforeDispatching() : function (or lambda) executed before handling HTTP request + (can be used for example to log, or to manage an authentication process) ;
  • +
  • afterDispatching() : function (or lambda) executed after handling HTTP request + (can be used for example to log) ;
  • +
  • clearDispatcher() : remove all routing rules from dispatcher (only function or + lambda defined by setCustomRequestHandler() will be executed).
  • +
+ Note : dispatcher is thread-safe, so you can define URL routing rules even if web server + is running. +

+ Other note : each function (or lambda) is + executed in its own thread + . + So QxOrm library HTTP web server can handle several HTTP requests simultaneously. +

+ Example n�1 : this routing rule handles all HTTP requests with method GET + URL + starts with /files/, and returns a static file content stored on server + (QDir::currentPath() is static files root directory, and 5000 is chunked response + size, this last parameter is optional) : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/files/*", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseStaticFile(request, response, QDir::currentPath(), 5000);
+});
+
+

+ Example n�2 : this routing rule handles all HTTP requests with method POST + URL + is /qx, and calls QxRestApi module (which provides a JSON API to + request persistent data layer). + Example n�1 (static files) and example n�2 (QxRestApi module) are a good starting + point to develop a SPA (Single-Page Applications) web application with famous Javascript + frameworks like AngularJS, React, Meteor.js, etc... +

+ + + + + + + +
+
httpServer.dispatch("POST", "/qx", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseQxRestApi(request, response);
+});
+
+

+ Example n�3 : this routing rule handles all HTTP requests with method GET + URL is + /test_big_json, and builds a JSON response with an array of 10000 items : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/test_big_json", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   // To compare with this benchmark : https://blog.binaryspaceship.com/2017/cpp-rest-api-frameworks-benchmark/
+   // This is more a JSON benchmark than HTTP server benchmark (RapidJSON is faster than Qt QJson engine)
+   QJsonArray arr; Q_UNUSED(request);
+   for (int i = 0; i < 10000; ++i)
+   {
+      QJsonObject item;
+      item.insert("id", QString::number(i));
+      item.insert("name", QString("Hello World"));
+      item.insert("type", QString("application"));
+      arr.append(item);
+   }
+   QJsonDocument doc(arr);
+   response.headers().insert("Content-Type", "application/json; charset=utf-8");
+   response.data() = doc.toJson(QJsonDocument::Compact);
+});
+
+

+ Note : + dispatch() order is very important. + The first item found by the dispatcher which matches requested URL is executed (all other + dispatcher items are ignored). + So you have to define first the most specific URL, and you have to define last the most generic + URL (for example, pattern /* matches all URLs, so this is the most generic dispatcher + item). +

+

Dynamic URL + routing

+
+ QxHttpServer dispatcher supports dynamic URL routing.
+ You can define some variables inside URL pattern with this syntax : <var_name:var_type> (var_type + is optional, and can be equal to : int, long, float, double, string). +

+ Dynamic URL routing is useful to define REST API.
+ For example, /blog/<blog_id:int> pattern + GET HTTP method can be used to + fetch a blog based on its numeric unique identifier (fetch_by_id). +

+ URL is a list of segments splitted by character /.
+ QxHttpServer dispatcher checks each segment from requested URL : if all segments match + the pattern, then the function (or lambda) is executed.
+ To get dynamic variables values from URL, you must write : request.dispatchParams().value("var_name") + (which returns a QVariant). +

+ Example : this routing rule handles all HTTP requests with method GET + URL + starts with /params/, followed by a segment which will contain the value of + var1 variable, followed by a numeric segment which will contain the + value of var2 variable. + The lambda returns a HTTP response which displays the values of var1 and var2 + variables from URL. + If the web browser calls /params/abc/123/ URL then the function (or lambda) will be + executed, BUT if the web browser calls /params/abc/def/ URL then the function + (or lambda) won't be executed (because def is not numeric) and dispatcher will search + another item to execute : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/params/<var1>/<var2:int>", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   response.data() = "Test URL dispatch parameters :\r\n";
+   response.data() += " - var1 = " + request.dispatchParams().value("var1").toByteArray() + "\r\n";
+   response.data() += " - var2 = " + request.dispatchParams().value("var2").toByteArray() + "\r\n";
+});
+
+

+ Note : you can also define a regular expression to route URLs with this syntax : <var_name:{my_reg_exp}>. +

+
+
+

Get HTTP request + parameters

+
+ qx::QxHttpRequest class (or its qx_http_request alias) contains all HTTP request parameters : +
    +
  • QUrl & url() : web browser requested URL ;
  • +
  • QString & command() : HTTP method (GET, POST, PUT, DELETE, etc...) ;
  • +
  • QString & version() : HTTP version provided by web browser (for example + HTTP/1.1) ; +
  • +
  • QByteArray & data() : HTTP request content ;
  • +
  • QByteArray header(const QByteArray & key) : get a HTTP header value provided by + web browser (for example : request.header("Accept-Encoding")) ;
  • +
  • QxHttpCookie cookie(const QByteArray & name) : get a HTTP + cookie provided by web browser ;
  • +
  • QString param(const QString & key) : get a HTTP parameter value (from URL, or from + HTTP request content if 'content-type' is + 'application/x-www-form-urlencoded') ; +
  • +
  • QHash<QString, QVariant> & dispatchParams() : list of URL dynamic parameters + computed by dispatcher (routing engine) ;
  • +
  • QString & sourceAddress() : IP address of client web browser ;
  • +
  • long & sourcePort() : port used by client web browser ;
  • +
  • QString guid() : internal HTTP request unique identifier (can be used to log for + example).
  • +
+
+
+

Build HTTP response +

+
+ qx::QxHttpResponse class (or its qx_http_response alias) is used to build HTTP response : +
    +
  • int & status() : HTTP response code (by default 200 which means OK) ;
  • +
  • QByteArray & data() : HTTP response content ;
  • +
  • QByteArray header(const QByteArray & key) : send a HTTP header to web browser (by + default, some headers are created automatically : Server, Date, + Content-Type and Connection) ; +
  • +
  • QxHttpCookie cookie(const QByteArray & name) : send a HTTP + cookie to web browser ;
  • +
  • qx_bool writeChunked(const QByteArray & data) : can be used to send chunked responses.
  • +
+
+
+

Sessions (storage per + client on server side)

+
+ HTTP sessions are a way to store some data related to a client on server side. + Session data are available for each client's requests (until session is expired). + The first time server access to a client's session, a HTTP cookie with + a unique identifier is generated and attached to HTTP response. + Then all HTTP requests sent by client web browser will contain automatically a HTTP cookie with the same unique identifier. + When a session is unused and expired, then it is deleted automatically. +

+ qx::QxHttpSession class (or its qx_http_session alias) is a HTTP session on server side.
+ qx::QxHttpSessionManager singleton class must be used to access to a + session : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   // If this is the first time to access to session, then a cookie is created automatically and attached to the response
+   // Then each request sent by web browser will contain a cookie with the session id
+   // The session expires on server side after qx::service::QxConnect::setSessionTimeOut() milliseconds
+   qx::QxHttpSession_ptr session = qx::QxHttpSessionManager::getSession(request, response);
+   if (session) { session->set("last_request_per_user", QDateTime::currentDateTime()); }
+});
+
+

+ Note : qx::QxHttpSession class contains a hash-map + (QHash<QByteArray, QVariant>) to store any values related to a client. +

+ Other note : qx::service::QxConnect::setSessionTimeOut() method can be used to define + a timeout (in milli-seconds) to delete unused sessions. +

+
+

Cookies

+
+ From Wikipedia website : + an HTTP cookie (also called web cookie, Internet cookie, browser cookie, or simply cookie) is a + small piece of data sent from a website and stored on the user's computer by the user's web + browser while the user is browsing. + Cookies were designed to be a reliable mechanism for websites to remember stateful information + (such as items added in the shopping cart in an online store) or to record the user's browsing + activity (including clicking particular buttons, logging in, or recording which pages were + visited in the past). +

+ qx::QxHttpRequest and qx::QxHttpResponse + classes provide the method cookies() to get cookies sent by web browser or + generate some cookies in HTTP response. + For example : +

+ + + + + + + +
+
qx::QxHttpCookie cookie;
+cookie.name = "my_http_cookie";
+cookie.value = "my_value";
+response.cookies().insert(cookie.name, cookie);
+
+

+ Note : an HTTP cookie is added automatically to HTTP response when accessing for the + first time to a session (server side storage per client). +

+
+

Static files

+
+ qx::QxHttpServer class (or its qx_http_server alias) provides a static method to send to client + web browser a file content stored on server side (for example : HTML, Javascript, CSS, PNG, + JPEG, videos, etc...). +

+ + + + + + + +
+
httpServer.dispatch("GET", "/files/*", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseStaticFile(request, response, QDir::currentPath(), 5000);
+});
+
+
+
    +
  • The third parameter (QDir::currentPath() in the example) defines the root + directory where files are stored on the server ;
  • +
  • The fourth parameter (5000 in the example) is optional and defines chunked response size. This parameter can be useful to send big + files (streaming).
  • +
+
+
+

Chunked responses

+
+ From Wikipedia + website : Chunked transfer encoding is a streaming data transfer mechanism available in + version 1.1 of the Hypertext Transfer Protocol (HTTP). + In chunked transfer encoding, the data stream is divided into a series of non-overlapping + "chunks". + The chunks are sent out and received independently of one another. + No knowledge of the data stream outside the currently-being-processed chunk is necessary for + both the sender and the receiver at any given time. + Each chunk is preceded by its size in bytes. + The transmission ends when a zero-length chunk is received. + The chunked keyword in the Transfer-Encoding header is used to indicate chunked transfer. +

+ The introduction of chunked encoding in HTTP 1.1 provided various benefits : +
    +
  • Chunked transfer encoding allows a server to maintain an HTTP persistent connection for + dynamically generated content.
  • +
  • Chunked encoding allows the sender to send additional header fields after the message + body. This is important in cases where values of a field cannot be known until the content + has been produced, such as when the content of the message must be digitally signed.
  • +
+
+ qx::QxHttpResponse class provides the qx_bool writeChunked(const + QByteArray & data) method to send chunked response. + It is used for example to send big static files (streaming) : +

+ + + + + + + +
+
while (! file.atEnd())
+{
+   if (! response.writeChunked(file.read(chunkedSize))) { return; }
+}
+
+

+ Note : the first response.writeChunked() call sends automatically all HTTP + response headers. + So you have to define all HTTP response headers before calling response.writeChunked(). +

+
+

Requests using JSON API + (QxRestApi module)

+
+ QxRestApi module provides a generic JSON API to request your persistent + data layer (CRUD operations, complex queries, several levels of relationships, custom JSON + output format, call dynamically native C++ functions registered in QxOrm context, instance + validation, call custom database queries). +

+ This user manual has a full chapter dedicated to QxRestApi module : it + contains several examples to request persistent data layer. + Combining QxRestApi module and QxHttpServer module : you have + all tools to develop modern web applications. + For example, SPA + (Single-Page Applications) web applications with famous Javascript frameworks like + AngularJS, React, Meteor.js, + etc... +

+ Note : QxOrm package provides a test project named + qxBlogRestApi. + This project includes a HTTP web server developed with QxOrm library, and a client source code + developed with HTML + Javascript (with jQuery). +

+ For example, here is the Javascript function used to send JSON requests (POST method) from + client web browser to QxOrm HTTP web server (all requests are sent to the same URL /qx) : +

+ + + + + + + +
+
function sendRequest(request) {
+   $.post("/qx", request, function(data, status, xhr) {
+      $("#txtResponse").val(JSON.stringify(data, null, 3));
+   }, "json").fail(function(error) {
+      alert("An error occurred sending request to QxOrm HTTP server : " + error);
+   });
+}
+
+

+ On server side, handling these requests is very easy : qx::QxHttpServer class (or its qx_http_server alias) provides the + qx::QxHttpServer::buildResponseQxRestApi() static method : +

+ + + + + + + +
+
httpServer.dispatch("POST", "/qx", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseQxRestApi(request, response);
+});
+
+

+ Here is a JSON request example sent by client web browser to get the list of all blogs stored in + database (fetch_all) : +

+
+
{
+   "request_id": "2b393e4c-a00c-45dc-a279-e9d76f1c55cf",
+   "action": "fetch_all",
+   "entity": "blog"
+}
+
+

+ Here is the JSON response with the list of all blogs : +

+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "2b393e4c-a00c-45dc-a279-e9d76f1c55cf"
+}
+
+

+
+

WebSocket

+
+ From Wikipedia website : + WebSocket is a computer communications protocol, providing full-duplex communication channels + over a single TCP connection. + The WebSocket protocol enables interaction between a web browser (or other client application) + and a web server with lower overheads, facilitating real-time data transfer from and to the + server. + This is made possible by providing a standardized way for the server to send content to the + client without being first requested by the client, and allowing messages to be passed back and + forth while keeping the connection open. + In this way, a two-way ongoing conversation can take place between the client and the server. +

+ QxOrm library is based on Qt framework which already provides a WebSocket + implementation.
+ Create a web server with Qt WebSocket is very easy : there are several examples in + Qt documentation. +

+ So you can implement a web server like this : +
    +
  • a listening port for HTTP connections (using QxHttpServer module) ;
  • +
  • another listening port for WebSocket connections (using QtWebSockets + module provided by Qt).
  • +
+
+ Note : a WebSocket connection is often created in Javascript code from client web + browser, so having 2 listening ports (1 for HTTP, and another for WebSocket) is not a problem. +

+
+

Performance (tested with + Apache Benchmark)

+
+ Here is a performance test result with following parameters : +
    +
  • Operating System (OS) : Windows 2010 64bits ;
  • +
  • CPU : Intel Core i7-6820HQ @ 2.70GHz (laptop) ;
  • +
  • Qt version : 5.1.1 (release mode) ;
  • +
  • QxOrm version : 1.4.6 (built in release mode with Visual Studio 2012, default + parameters, no specific optimization) ;
  • +
  • HTTP web server : qxBlogRestApi test project ;
  • +
  • Tool to execute the test : Apache Benchmark ;
  • +
  • Simulate 20000 requests with 50 concurrents connections simultaneously : ab -n + 20000 -c 50 -k http://localhost:9642/params/abc/123
  • +
+
+ Test results show that QxOrm HTTP web server can handle + more than 12000 requests per second : +

+ QxHttpServer performance +

+

Improve performance + with epoll dispatcher on Linux

+
+ On Linux, you can improve HTTP web server performance using epoll to manage your + sockets. + By default, Qt framework is based on a slower process (select), but a method exists to + define another event loop and dispatcher. + Several libraries are available, for example : + +
+ qx::QxHttpServer class (or its qx_http_server alias) provides a method to define a custom + epoll event dispatcher (you must call it before running the QxOrm HTTP web server) : +

+ + + + + + + +
+
   httpServer.setEventDispatcher(new QEventDispatcherEpoll());   
+
+

+
+
+
+ +

JSON REST API (QxRestApi + module)

+
+ QxRestApi module is a JSON API to manage (in a generic way) your persistent data layer + (database) or call C++ native functions (registered in QxOrm context). + QxRestApi module is based on a request/response mechanism : send a request in JSON format + and receive a response in JSON format. + QxRestApi module can be used for example to develop REST + services. +

+ QxRestApi module supports following features : +
    +
  • CRUD operations ;
  • +
  • complex queries with several levels of relationships ;
  • +
  • custom JSON output format ;
  • +
  • call dynamically C++ native functions registered in QxOrm context ;
  • +
  • instance validation ;
  • +
  • call custom database queries or stored procedures.
  • +
+
+

How it works

+
+ QxRestApi module is very easy to use : qx::QxRestApi + class has only 1 main method : processRequest().
+ Prerequisites : all classes registered into QxOrm context must implement qx::IxPersistable + interface. +

+ A JSON query contains following properties : +

+
+
{
+   "request_id" : // [optional] unique identifier generated by client to associate response to request (if provided by caller, then the response will contain the same unique identifier)
+   "action" : // [required] what is the action to execute on the server
+   "entity" : // [optional or required depending on action] C++ class registered in QxOrm context
+   "data" : // [optional or required depending on action] data in JSON format needed to execute action
+   "columns" : // [optional] list of columns to fetch or update (if empty, means all columns)
+   "relations" : // [optional] list of relationships to fetch or save
+   "query" : // [optional or required depending on action] query to execute on database
+   "output_format" : // [optional] output fields for the response (filter), if empty then response will contain all fields
+   "fct" : // [required only with action 'call_entity_function'] used to call C++ native functions
+   "save_mode" : // [optional] used only with action 'save' to define insert or update or check both insert/update
+}
+
+

+ A JSON response contains following properties : +

+
+
{
+   "request_id" : // unique identifier generated by client's request (if any)
+   "data" : // contain the response data
+   "error" : // if an error occured, then contain a code and description of the error
+}
+
+

+

Use cases

+
+ Several programming languages support natively JSON format (Javascript, PHP, Python, etc...). + QxRestApi module provides an interoperability between QxOrm library and any other + applications developed with another technology (not C++/Qt for example). +

+ QxRestApi module can be useful for : + +
+
+
+

qxBlogRestApi example + project (QML and HTTP web server)

+
+ QxOrm package contains a test project named qxBlogRestApi (in + ./test/qxBlogRestApi/ directory).
+ This test project shows 2 ways to work with QxRestApi module : +
    +
  • The first screen is a QML application which + uses embedded QML Javascript engine to request a persistent data layer or call C++ native + functions : +

    QxHttpServer performance


    +
  • +
  • The second screen runs an HTTP web server + based on QxHttpServer module, then opens default web browser (to + load HTML + Javascript with jQuery) : +

    QxHttpServer performance
    +
  • +
+
+ These 2 windows are developed with different programming languages (QML versus HTML + + Javascript), but provide exactly same features : +
    +
  • On top-left position : a text area to write a JSON request to send to QxRestApi + module ;
  • +
  • Just below the JSON request text area : a button to send JSON request to QxRestApi + module ;
  • +
  • On bottom-left position : a list of pre-loaded JSON requests examples (a click on this + list fills automatically the JSON request text area) ;
  • +
  • On right side : a JSON response text area received from QxRestApi module (after + executing a JSON request).
  • +
+
+
+

Fetch

+
+ This chapter provides several ways to get data from database (fetch) : + +
+

fetch_all

+
+ The fetch_all action gets all items from a table in database (and eventually several levels of relationships). +

+ -- Example n�1 -- fetch all blogs (as + list format) : +

+ JSON request :
+
+
{
+   "request_id": "5e988bac-c812-4cb1-b0d8-6a2c9dc4478b",
+   "action": "fetch_all",
+   "entity": "blog"
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "5e988bac-c812-4cb1-b0d8-6a2c9dc4478b"
+}
+
+

+ -- Example n�2 -- fetch all blogs (as + hash-map with key/value format) : +

+ JSON request :
+
+
{
+   "request_id": "ad400135-19fd-40e0-8034-201be6a2ff7a",
+   "action": "fetch_all",
+   "entity": "blog",
+   "data": [
+      {
+         "key": "",
+         "value": ""
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "key": 1,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 1,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 2,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 2,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 3,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 3,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 4,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 4,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      }
+   ],
+   "request_id": "ad400135-19fd-40e0-8034-201be6a2ff7a"
+}
+
+

+ -- Example n�3 -- fetch all blogs and 2 levels of relationships : +

+ JSON request :
+
+
{
+   "request_id": "cf9ea2a8-3e41-438f-9a48-bbc8593d2b99",
+   "action": "fetch_all",
+   "entity": "blog",
+   "relations": [
+      "*->*"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 1,
+               "value": {
+                  "category_id": 1,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 1,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 3,
+               "value": {
+                  "category_id": 3,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 1,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": [
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 1,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 3,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 5,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 7,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 2,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 4,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 6,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 8,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 4,
+               "value": {
+                  "category_id": 4,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 2,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 2,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 5,
+               "value": {
+                  "category_id": 5,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 2,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 2,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 6,
+               "value": {
+                  "category_id": 6,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 3,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 3,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 7,
+               "value": {
+                  "category_id": 7,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 3,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 3,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 8,
+               "value": {
+                  "category_id": 8,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 4,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 4,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 9,
+               "value": {
+                  "category_id": 9,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 4,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 4,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      }
+   ],
+   "request_id": "cf9ea2a8-3e41-438f-9a48-bbc8593d2b99"
+}
+
+

+ -- Example n�4 -- fetch all blogs and some relationships + define an output JSON format (all properties + will not be exported to JSON response) : +

+ JSON request :
+
+
{
+   "request_id": "4c45fdf9-8001-4509-bb4b-ce27a4a8708a",
+   "action": "fetch_all",
+   "entity": "blog",
+   "relations": [
+      "<blog_alias> { blog_text }",
+      "author_id <author_alias> { name, birthdate }",
+      "list_comment <list_comment_alias> { comment_text } -> blog_id <blog_alias_2> -> * <..._my_alias_suffix>"
+   ],
+   "output_format": [
+      "{ blog_text }",
+      "author_id { name, birthdate }",
+      "list_comment { comment_text } -> blog_id -> *"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": [
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 1,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 3,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 5,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 7,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 2,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 4,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 6,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 8,
+               "comment_text": "comment_2 text"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      }
+   ],
+   "request_id": "4c45fdf9-8001-4509-bb4b-ce27a4a8708a"
+}
+
+

+
+

fetch_by_id

+
+ The fetch_by_id action gets an item from a table based on its unique + identifier. +

+ -- Example n�1 -- fetch a blog which has + an unique identifier equals to 1 : +

+ JSON request :
+
+
{
+   "request_id": "4d6fbb9e-e088-482a-abfa-4e7ddee80569",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "author_id": {
+         "author_id": "author_id_2",
+         "birthdate": null,
+         "list_blog": [],
+         "name": "",
+         "sex": 2
+      },
+      "blog_id": 1,
+      "blog_text": "blog property 'text' modified => blog is dirty !!!",
+      "date_creation": "2019-04-01T16:18:54",
+      "list_category": [],
+      "list_comment": []
+   },
+   "request_id": "4d6fbb9e-e088-482a-abfa-4e7ddee80569"
+}
+
+

+ -- Example n�2 -- fetch only some blog's + columns which has an unique identifier equals to 1 (other columns are part of JSON response + but with an empty or null value) : +

+ JSON request :
+
+
{
+   "request_id": "72c9b362-d194-410e-98ed-23797a34318e",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   },
+   "columns": [
+      "blog_text",
+      "date_creation"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "author_id": null,
+      "blog_id": 1,
+      "blog_text": "blog property 'text' modified => blog is dirty !!!",
+      "date_creation": "2019-04-01T16:18:54",
+      "list_category": [],
+      "list_comment": []
+   },
+   "request_id": "72c9b362-d194-410e-98ed-23797a34318e"
+}
+
+

+ -- Example n�3 -- fetch a list of blogs + based on their unique identifier : +

+ JSON request :
+
+
{
+   "request_id": "59c37f70-26ee-42e5-9177-b32c331adce1",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 2
+      },
+      {
+         "blog_id": 3
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "59c37f70-26ee-42e5-9177-b32c331adce1"
+}
+
+

+ -- Example n�4 -- fetch a list of blogs + (with some relationships) based on their unique identifier, and define a JSON output format + (all properties will not be exported to JSON response) : +

+ JSON request :
+
+
{
+   "request_id": "325d64f4-29ac-47ab-9846-d6a71a9e9d73",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 2
+      }
+   ],
+   "relations": [
+      "{ blog_text }",
+      "author_id <author_alias> { name, birthdate }",
+      "list_comment <list_comment_alias> { comment_text }"
+   ],
+   "output_format": [
+      "{ blog_text }",
+      "author_id { name, birthdate }",
+      "list_comment { comment_text }"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": [
+            {
+               "comment_id": 1,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 2,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 3,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 4,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 5,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 6,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 7,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 8,
+               "comment_text": "comment_2 text"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      }
+   ],
+   "request_id": "325d64f4-29ac-47ab-9846-d6a71a9e9d73"
+}
+
+

+
+

fetch_by_query +

+
+ The fetch_by_query action gets some items from a table filtered by a query. +

+ -- Example n�1 -- fetch only items from + author table with a sex of type female (female == enum equals to 1) : +

+ JSON request :
+
+
{
+   "request_id": "c178194c-a76f-4a77-af12-2b97fc7078e4",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [],
+         "name": "author name modified at index 1 => container is dirty !!!",
+         "sex": 1
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3",
+         "sex": 1
+      }
+   ],
+   "request_id": "c178194c-a76f-4a77-af12-2b97fc7078e4"
+}
+
+

+ -- Example n�2 -- fetch some items from + author table (and all relationships) with a sex of type + female : +

+ JSON request :
+
+
{
+   "request_id": "84e2e13a-0bf9-4d78-b655-970568a97e4c",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1,
+            "type": "in"
+         }
+      ]
+   },
+   "relations": [
+      "*"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 1,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 2,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 3,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 4,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            }
+         ],
+         "name": "author name modified at index 1 => container is dirty !!!",
+         "sex": 1
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3",
+         "sex": 1
+      }
+   ],
+   "request_id": "84e2e13a-0bf9-4d78-b655-970568a97e4c"
+}
+
+

+ -- Example n�3 -- fetch some items from + author table (and all relationships) with a sex of type + female, and define a JSON output format (all properties will not be exported to JSON + response) : +

+ JSON request :
+
+
{
+   "request_id": "c18b59e7-54f9-4a4f-843d-f0797f4fb676",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1,
+            "type": "in"
+         }
+      ]
+   },
+   "relations": [
+      "*"
+   ],
+   "output_format": [
+      "{ birthdate, name }",
+      "list_blog { blog_text, date_creation }"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [
+            {
+               "blog_id": 1,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 2,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 3,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 4,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            }
+         ],
+         "name": "author name modified at index 1 => container is dirty !!!"
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3"
+      }
+   ],
+   "request_id": "c18b59e7-54f9-4a4f-843d-f0797f4fb676"
+}
+
+

+
+

count

+
+ The count action returns a number of items from a table in database with or + without a query (and with or without relationships). +

+ -- Example n�1 -- count all blogs stored + in database : +

+ JSON request :
+
+
{
+   "request_id": "1ef62fd7-d847-4d67-9fd0-0207af463aa4",
+   "action": "count",
+   "entity": "blog"
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "count": 4
+   },
+   "request_id": "1ef62fd7-d847-4d67-9fd0-0207af463aa4"
+}
+
+

+ -- Example n�2 -- count items from + author table with a sex of type female : +

+ JSON request :
+
+
{
+   "request_id": "a80646d1-5a42-46fb-9306-3b91c7f594c8",
+   "action": "count",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "count": 2
+   },
+   "request_id": "a80646d1-5a42-46fb-9306-3b91c7f594c8"
+}
+
+

+ -- Example n�3 -- count all blogs + associated to an author with a sex of type female : +

+ JSON request :
+
+
{
+   "request_id": "6ef252f7-385c-465e-8304-b9afa9fea490",
+   "action": "count",
+   "entity": "blog",
+   "query": {
+      "sql": "WHERE author_alias.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   },
+   "relations": [
+      "author_id <author_alias> { sex }"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "count": 4
+   },
+   "request_id": "6ef252f7-385c-465e-8304-b9afa9fea490"
+}
+
+

+
+

exist

+
+ The exist action checks if an item from a table exists in database based on its + unique identifier. +

+ -- Example n�1 -- check if a blog with + unique identifier equals to 1 exists in database : +

+ JSON request :
+
+
{
+   "request_id": "e8db33db-b249-4349-93fe-ad12e208520e",
+   "action": "exist",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "exist": true
+   },
+   "request_id": "e8db33db-b249-4349-93fe-ad12e208520e"
+}
+
+

+ -- Example n�2 -- check if several blogs + exist (based on their unique identifier) : +

+ JSON request :
+
+
{
+   "request_id": "f2d6ca3f-36de-4920-8f4c-c04842603467",
+   "action": "exist",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 999
+      },
+      {
+         "blog_id": 3
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "exist": false
+   },
+   "request_id": "f2d6ca3f-36de-4920-8f4c-c04842603467"
+}
+
+

+ -- Example n�3 -- check if an + author exists : +

+ JSON request :
+
+
{
+   "request_id": "2c7df172-8010-4816-b8e1-3edbb0b0b90e",
+   "action": "exist",
+   "entity": "author",
+   "data": {
+      "author_id": "author_id_2"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "exist": true
+   },
+   "request_id": "2c7df172-8010-4816-b8e1-3edbb0b0b90e"
+}
+
+

+
+
+

Insert

+
+ The insert action adds 1 or several items in database. + Unique identifiers generated by database (for example auto-incremented identifiers) are provided + in JSON response. +

+ -- Example n�1 -- insert a blog in database + : +

+ JSON request :
+
+
{
+   "request_id": "573e4940-607a-4037-8a09-11ec52deb21c",
+   "action": "insert",
+   "entity": "blog",
+   "data": {
+      "blog_text": "this is a new blog from QxOrm REST API !",
+      "date_creation": "2018-01-30T12:42:01",
+      "author_id": "author_id_2"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 5
+   },
+   "request_id": "573e4940-607a-4037-8a09-11ec52deb21c"
+}
+
+

+ -- Example n�2 -- insert a list of blogs in + database : +

+ JSON request :
+
+
{
+   "request_id": "6ade2d01-086c-45d6-971b-b65e8836475f",
+   "action": "insert",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_text": "new blog from QxOrm REST API !",
+         "date_creation": "2018-01-30T12:42:01",
+         "author_id": "author_id_2"
+      },
+      {
+         "blog_text": "another blog from QxOrm REST API !",
+         "date_creation": "2016-06-12T08:33:12",
+         "author_id": "author_id_1"
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "blog_id": 6
+      },
+      {
+         "blog_id": 7
+      }
+   ],
+   "request_id": "6ade2d01-086c-45d6-971b-b65e8836475f"
+}
+
+

+ -- Example n�3 -- insert an author in + database : +

+ JSON request :
+
+
{
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57",
+   "action": "insert",
+   "entity": "author",
+   "data": {
+      "author_id": "author_id_from_rest_api",
+      "birthdate": "1978-05-11",
+      "name": "new author created by QxOrm REST API",
+      "sex": 1
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "author_id": "author_id_from_rest_api"
+   },
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57"
+}
+
+
+ Note : the author table requires an unique identifier filled by caller (because + it's not auto-incremented). + If we execute the same JSON request a second time, then we have following error : +
+
+
{
+   "error": {
+      "code": 19,
+      "desc": "Unable to fetch row\ncolumn author_id is not unique"
+   },
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57"
+}
+
+

+
+

Update

+
+ The update action modifies 1 or several items in database. +

+ -- Example n�1 -- update a blog with unique + identifier equals to 1 : +

+ JSON request :
+
+
{
+   "request_id": "4fa24a7f-a3d8-4bbf-85c1-c86df83dec0b",
+   "action": "update",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": "author_id_1"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "4fa24a7f-a3d8-4bbf-85c1-c86df83dec0b"
+}
+
+

+ -- Example n�2 -- update only some columns + of a blog : +

+ JSON request :
+
+
{
+   "request_id": "d0704db1-5c3a-48ad-b27e-14aa54ac0efb",
+   "action": "update",
+   "entity": "blog",
+   "data": {
+      "blog_id": 2,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33"
+   },
+   "columns": [
+      "blog_text",
+      "date_creation"
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 2
+   },
+   "request_id": "d0704db1-5c3a-48ad-b27e-14aa54ac0efb"
+}
+
+

+ -- Example n�3 -- update a list of + author : +

+ JSON request :
+
+
{
+   "request_id": "26ec3a7b-cf2d-47f7-bab7-db303f15ee51",
+   "action": "update",
+   "entity": "author",
+   "data": [
+      {
+         "author_id": "author_id_from_rest_api",
+         "birthdate": "1992-11-03",
+         "name": "modify author from QxOrm REST API",
+         "sex": 0
+      },
+      {
+         "author_id": "author_id_1",
+         "birthdate": "1978-12-25",
+         "name": "modify another author from QxOrm REST API",
+         "sex": 2
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_from_rest_api"
+      },
+      {
+         "author_id": "author_id_1"
+      }
+   ],
+   "request_id": "26ec3a7b-cf2d-47f7-bab7-db303f15ee51"
+}
+
+

+
+

Save (insert or + update)

+
+ The save action adds or modifies (insert or update) 1 or several + items in database. + When inserting, unique identifiers generated by database (for example auto-incremented + identifiers) are provided in JSON response. +

+ JSON request has an optional parameter named save_mode which can have following values : +
    +
  • check_insert_or_update : save the instance and its relationships recursively + (several levels of relations) checking for each relation if an insert or + update is required (can be slow with a lot of relations) ; +
  • +
  • insert_only : insert recursively (several levels of relations) the instance and + its relationships ;
  • +
  • update_only : update recursively (several levels of relations) the instance and + its relationships.
  • +
+
+ -- Example n�1 -- save (insert or update + based on the unique identifier) a blog in database : +

+ JSON request :
+
+
{
+   "request_id": "ec3c71eb-5014-4b36-85a0-aeb7ae48a5e9",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": "author_id_1"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "ec3c71eb-5014-4b36-85a0-aeb7ae48a5e9"
+}
+
+

+ -- Example n�2 -- save (insert or update + based on the unique identifier) a list of blogs in database : +

+ JSON request :
+
+
{
+   "request_id": "dc7c804e-f95a-4a9b-a4e3-547adcacf090",
+   "action": "save",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1,
+         "blog_text": "save blog from QxOrm REST API !",
+         "date_creation": "2018-01-30T12:42:01",
+         "author_id": "author_id_2"
+      },
+      {
+         "blog_text": "save another blog from QxOrm REST API !",
+         "date_creation": "2016-06-12T08:33:12",
+         "author_id": "author_id_1"
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 5
+      }
+   ],
+   "request_id": "dc7c804e-f95a-4a9b-a4e3-547adcacf090"
+}
+
+

+ -- Example n�3 -- save (insert or update + based on the unique identifier) a blog and all its relationships recursively (several levels) : +

+ JSON request :
+
+
{
+   "request_id": "5b78e468-2fa3-4aeb-82ce-4d85408f5fa7",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "save recursive blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": {
+         "author_id": "author_id_1",
+         "birthdate": "1965-07-21",
+         "name": "save recursive author from QxOrm REST API",
+         "sex": 0
+      }
+   },
+   "save_mode": "check_insert_or_update"
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "5b78e468-2fa3-4aeb-82ce-4d85408f5fa7"
+}
+
+

+ -- Example n�4 -- insert (save_mode = + insert_only) a blog and all its relationships recursively (several levels) : +

+ JSON request :
+
+
{
+   "request_id": "ef147c62-74e0-4be2-a294-ffeb020d5304",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_text": "save recursive - new blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": {
+         "author_id": "author_id_save_recursive",
+         "birthdate": "1965-07-21",
+         "name": "save recursive (insert only) author from QxOrm REST API",
+         "sex": 0
+      }
+   },
+   "save_mode": "insert_only"
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 7
+   },
+   "request_id": "ef147c62-74e0-4be2-a294-ffeb020d5304"
+}
+
+

+
+

Delete

+
+ This chapter provides several ways to remove data from database (delete or destroy) : + +
+ Note : difference between delete and destroy is soft + delete behaviour (logical delete). +

+

delete_all / + destroy_all

+
+ The delete_all and destroy_all actions remove all items (rows) + from a table. + The difference between delete and destroy is soft delete + behaviour (logical delete). +

+ -- Example n�1 -- delete all rows from + the comment table : +

+ JSON request :
+
+
{
+   "request_id": "7b06b5c0-409f-4e0d-bfc4-acafbfe7e796",
+   "action": "delete_all",
+   "entity": "comment"
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "deleted": true
+   },
+   "request_id": "7b06b5c0-409f-4e0d-bfc4-acafbfe7e796"
+}
+
+

+
+

delete_by_query / + destroy_by_query

+
+ The delete_by_query and destroy_by_query actions remove some + items (rows) from a table based on a query. + The difference between delete and destroy is soft delete + behaviour (logical delete). +

+ -- Example n�1 -- delete all rows from + the author table with a sex of type female (female = enum with value 1) + : +

+ JSON request :
+
+
{
+   "request_id": "169ff0be-6e49-457b-a99c-22bd7141dc02",
+   "action": "delete_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "deleted": true
+   },
+   "request_id": "169ff0be-6e49-457b-a99c-22bd7141dc02"
+}
+
+

+
+

delete_by_id / + destroy_by_id

+
+ The delete_by_id and destroy_by_id actions remove some items + (rows) from a table based on the unique identifier. + The difference between delete and destroy is soft delete + behaviour (logical delete). +

+ -- Example n�1 -- delete from database + the blog with unique identifier equals to 4 : +

+ JSON request :
+
+
{
+   "request_id": "80bff383-8ebd-4bde-bb42-37b6f67bc39f",
+   "action": "delete_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 4
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "blog_id": 4
+   },
+   "request_id": "80bff383-8ebd-4bde-bb42-37b6f67bc39f"
+}
+
+

+ -- Example n�2 -- delete from database a + list of 2 blogs with unique identifier equals to 3 and 2 : +

+ JSON request :
+
+
{
+   "request_id": "38020cb7-d725-4c0e-80a0-63db7569155e",
+   "action": "delete_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 3
+      },
+      {
+         "blog_id": 2
+      }
+   ]
+}
+
+ JSON response :
+
+
{
+   "data": [
+      {
+         "blog_id": 3
+      },
+      {
+         "blog_id": 2
+      }
+   ],
+   "request_id": "38020cb7-d725-4c0e-80a0-63db7569155e"
+}
+
+

+
+
+

Validate

+
+ The validate action checks some properties of your instance (without triggering + any action to database). + The validate action calls the QxValidator module from + QxOrm library. +

+ -- Example n�1 -- a blog must contain + some text (blog_text property) to be saved in database. + With the following JSON request, we get a JSON response with an error message which means that + the blog instance is not valid : +

+ JSON request :
+
+
{
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba",
+   "action": "validate",
+   "entity": "blog",
+   "data": {
+      "blog_id": 9999,
+      "blog_text": ""
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "invalid_values": [
+         "blog",
+         [
+            {
+               "message": "'blog_text' property cannot be empty",
+               "path": "blog"
+            }
+         ]
+      ]
+   },
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba"
+}
+
+

+ -- Example n�2 -- we add a value to + blog_text property, so the blog instance becomes valid (the JSON response has an + invalid_values property with a null value) : +

+ JSON request :
+
+
{
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba",
+   "action": "validate",
+   "entity": "blog",
+   "data": {
+      "blog_id": 9999,
+      "blog_text": "my blog text !!!"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "invalid_values": null
+   },
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba"
+}
+
+

+
+

Custom SQL query or + stored procedure

+
+ The call_custom_query action executes a custom SQL query or a stored procedure. +

+ -- Example n�1 -- insert in database a new + author with a custom SQL query : +

+ JSON request :
+
+
{
+   "request_id": "ff2a2256-041d-4c5f-bd86-3745ce46ead8",
+   "action": "call_custom_query",
+   "query": {
+      "sql": "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)",
+      "params": [
+         {
+            "key": ":author_id",
+            "value": "author_id_custom_query"
+         },
+         {
+            "key": ":name",
+            "value": "new author inserted by custom query"
+         },
+         {
+            "key": ":birthdate",
+            "value": "20190215"
+         },
+         {
+            "key": ":sex",
+            "value": 2
+         }
+      ]
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "query_output": {
+         "distinct": false,
+         "list_values": {
+            ":author_id": [
+               "author_id_custom_query",
+               1
+            ],
+            ":birthdate": [
+               "20190215",
+               1
+            ],
+            ":name": [
+               "new author inserted by custom query",
+               1
+            ],
+            ":sex": [
+               2,
+               1
+            ]
+         },
+         "parenthesis_count": 0,
+         "query": [
+            "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)"
+         ],
+         "response": "",
+         "result_position_by_key": {},
+         "result_values": [],
+         "sql_element_index": 0,
+         "sql_element_list": [],
+         "sql_element_temp_type": 0,
+         "type": ""
+      }
+   },
+   "request_id": "ff2a2256-041d-4c5f-bd86-3745ce46ead8"
+}
+
+

+
+

Call C++ natives + functions

+
+ The call_entity_function action executes C++ natives functions registered into + QxOrm context.
+ Prerequisites : the C++ native function must be a static method with this + signature : + static QJsonValue myNativeCppFct(const QJsonValue & + request); + +

+ Here is an example of C++ function registered into QxOrm context, this function can be called by + the JSON API engine (QxRestApi module) : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   // Register 'helloWorld()' static function in QxOrm context (can be called by QxRestApi JSON API module)
+   t.fctStatic_1<QJsonValue, const QJsonValue & >(& blog::helloWorld, "helloWorld");
+}}
+
+// 'helloWorld()' static function implementation
+QJsonValue blog::helloWorld(const QJsonValue & request)
+{
+   QJsonObject response;
+   response.insert("request", request);
+   response.insert("response", QString("Hello World !"));
+   return response;
+}
+
+

+ Here is how to execute the C++ helloWorld function from JSON API using + call_entity_function action : +

+ JSON request :
+
+
{
+   "request_id": "ab1ba7d3-9f98-4b18-a310-a9c34498d043",
+   "action": "call_entity_function",
+   "entity": "blog",
+   "fct": "helloWorld",
+   "data": {
+      "param1": "test",
+      "param2": "static fct call"
+   }
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "request": {
+         "param1": "test",
+         "param2": "static fct call"
+      },
+      "response": "Hello World !"
+   },
+   "request_id": "ab1ba7d3-9f98-4b18-a310-a9c34498d043"
+}
+
+

+
+

Meta-data (C++ classes + registered into QxOrm context)

+
+ The get_meta_data action fetches some meta-data from 1 or all entities registered + into QxOrm context (C++ classes structure with list of properties and relationships). +

+ -- Example n�1 -- get all meta-data of qxBlogRestApi example project : +

+ JSON request :
+
+
{
+   "request_id": "842ed7b5-9b94-455f-86dc-32992866b3d5",
+   "action": "get_meta_data",
+   "entity": "*"
+}
+
+ JSON response :
+
+
{
+   "data": {
+      "entities": [
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "author_id",
+               "type": "QString"
+            },
+            "key": "author",
+            "name": "author",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "name",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "birthdate",
+                  "type": "QDate"
+               },
+               {
+                  "description": "",
+                  "key": "sex",
+                  "type": "enum author::enum_sex *"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "list_blog",
+                  "target": "blog",
+                  "type": "std::vector<std::shared_ptr<blog>>",
+                  "type_relation": "relation one-to-many"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "blog_id",
+               "type": "long"
+            },
+            "key": "blog",
+            "name": "blog",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "blog_text",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "date_creation",
+                  "type": "QDateTime"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "author_id",
+                  "target": "author",
+                  "type": "std::shared_ptr<author>",
+                  "type_relation": "relation many-to-one"
+               },
+               {
+                  "description": "",
+                  "key": "list_comment",
+                  "target": "comment",
+                  "type": "QList<std::shared_ptr<comment>>",
+                  "type_relation": "relation one-to-many"
+               },
+               {
+                  "description": "",
+                  "key": "list_category",
+                  "target": "category",
+                  "type": "qx::QxCollection<long, QSharedPointer<category>>",
+                  "type_relation": "relation many-to-many"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "comment_id",
+               "type": "long"
+            },
+            "key": "comment",
+            "name": "comment",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "comment_text",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "date_creation",
+                  "type": "QDateTime"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "blog_id",
+                  "target": "blog",
+                  "type": "std::shared_ptr<blog>",
+                  "type_relation": "relation many-to-one"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "category_id",
+               "type": "long"
+            },
+            "key": "category",
+            "name": "category",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "name",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "description",
+                  "type": "QString"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "list_blog",
+                  "target": "blog",
+                  "type": "qx::QxCollection<long, std::shared_ptr<blog>>",
+                  "type_relation": "relation many-to-many"
+               }
+            ],
+            "version": 0
+         }
+      ]
+   },
+   "request_id": "842ed7b5-9b94-455f-86dc-32992866b3d5"
+}
+
+

+
+

Send a list of JSON + requests

+
+ To limit transactions count between client and server, it is possible to send a list of JSON + requests to QxRestApi module. + Each JSON request can contain its own unique identifier request_id (to match a JSON + response with the right JSON request). + When a list of JSON requests is sent to QxRestApi module, then a + transaction (commit/rollback) is automatically created (so if an error occurred, then all + actions in database are cancelled). +

+ -- Example n�1 -- send a list of 4 JSON + requests to QxRestApi module (1 request to fetch project + meta-data + 3 requests to fetch_all blogs with several ways + to get relationships) : +

+ JSON request :
+
+
[
+   {
+      "request_id": "53c96a23-2566-4b3d-ae6c-bff634600e79",
+      "action": "get_meta_data",
+      "entity": "*"
+   },
+   {
+      "request_id": "56e3ca99-5c12-4aca-aa6c-7d0e43c1e636",
+      "action": "fetch_all",
+      "entity": "blog"
+   },
+   {
+      "request_id": "692968e4-8885-41ad-b918-6ce2791b3bb8",
+      "action": "fetch_all",
+      "entity": "blog",
+      "data": [
+         {
+            "key": "",
+            "value": ""
+         }
+      ]
+   },
+   {
+      "request_id": "4ffe38a6-d642-44b0-8be1-198e84256321",
+      "action": "fetch_all",
+      "entity": "blog",
+      "relations": [
+         "*->*"
+      ]
+   }
+]
+
+ JSON response :
+
+
[
+   {
+      "data": {
+         "entities": [
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "author_id",
+                  "type": "QString"
+               },
+               "key": "author",
+               "name": "author",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "name",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "birthdate",
+                     "type": "QDate"
+                  },
+                  {
+                     "description": "",
+                     "key": "sex",
+                     "type": "enum author::enum_sex *"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "list_blog",
+                     "target": "blog",
+                     "type": "std::vector<std::shared_ptr<blog>>",
+                     "type_relation": "relation one-to-many"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "blog_id",
+                  "type": "long"
+               },
+               "key": "blog",
+               "name": "blog",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "blog_text",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "date_creation",
+                     "type": "QDateTime"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "author_id",
+                     "target": "author",
+                     "type": "std::shared_ptr<author>",
+                     "type_relation": "relation many-to-one"
+                  },
+                  {
+                     "description": "",
+                     "key": "list_comment",
+                     "target": "comment",
+                     "type": "QList<std::shared_ptr<comment>>",
+                     "type_relation": "relation one-to-many"
+                  },
+                  {
+                     "description": "",
+                     "key": "list_category",
+                     "target": "category",
+                     "type": "qx::QxCollection<long, QSharedPointer<category>>",
+                     "type_relation": "relation many-to-many"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "comment_id",
+                  "type": "long"
+               },
+               "key": "comment",
+               "name": "comment",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "comment_text",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "date_creation",
+                     "type": "QDateTime"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "blog_id",
+                     "target": "blog",
+                     "type": "std::shared_ptr<blog>",
+                     "type_relation": "relation many-to-one"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "category_id",
+                  "type": "long"
+               },
+               "key": "category",
+               "name": "category",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "name",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "description",
+                     "type": "QString"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "list_blog",
+                     "target": "blog",
+                     "type": "qx::QxCollection<long, std::shared_ptr<blog>>",
+                     "type_relation": "relation many-to-many"
+                  }
+               ],
+               "version": 0
+            }
+         ]
+      },
+      "request_id": "53c96a23-2566-4b3d-ae6c-bff634600e79"
+   },
+   {
+      "data": [
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 1,
+            "blog_text": "save recursive blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 5,
+            "blog_text": "save another blog from QxOrm REST API !",
+            "date_creation": "2016-06-12T08:33:12",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 6,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 7,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         }
+      ],
+      "request_id": "56e3ca99-5c12-4aca-aa6c-7d0e43c1e636"
+   },
+   {
+      "data": [
+         {
+            "key": 1,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_1",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 1,
+               "blog_text": "save recursive blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 5,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_1",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 5,
+               "blog_text": "save another blog from QxOrm REST API !",
+               "date_creation": "2016-06-12T08:33:12",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 6,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_save_recursive",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 6,
+               "blog_text": "save recursive - new blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 7,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_save_recursive",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 7,
+               "blog_text": "save recursive - new blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         }
+      ],
+      "request_id": "692968e4-8885-41ad-b918-6ce2791b3bb8"
+   },
+   {
+      "data": [
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": "2019-04-02",
+               "list_blog": [
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 5,
+                     "blog_text": "save another blog from QxOrm REST API !",
+                     "date_creation": "2016-06-12T08:33:12",
+                     "list_category": [],
+                     "list_comment": []
+                  },
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 1,
+                     "blog_text": "save recursive blog from QxOrm REST API",
+                     "date_creation": "2013-11-25T09:56:33",
+                     "list_category": [],
+                     "list_comment": []
+                  }
+               ],
+               "name": "author_1",
+               "sex": 0
+            },
+            "blog_id": 1,
+            "blog_text": "save recursive blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": "2019-04-02",
+               "list_blog": [
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 5,
+                     "blog_text": "save another blog from QxOrm REST API !",
+                     "date_creation": "2016-06-12T08:33:12",
+                     "list_category": [],
+                     "list_comment": []
+                  },
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 1,
+                     "blog_text": "save recursive blog from QxOrm REST API",
+                     "date_creation": "2013-11-25T09:56:33",
+                     "list_category": [],
+                     "list_comment": []
+                  }
+               ],
+               "name": "author_1",
+               "sex": 0
+            },
+            "blog_id": 5,
+            "blog_text": "save another blog from QxOrm REST API !",
+            "date_creation": "2016-06-12T08:33:12",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 6,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 7,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         }
+      ],
+      "request_id": "4ffe38a6-d642-44b0-8be1-198e84256321"
+   }
+]
+
+

+
+
+ +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/manual_qxee.html b/doc/qxorm_en/manual_qxee.html new file mode 100644 index 0000000..d8e64c5 --- /dev/null +++ b/doc/qxorm_en/manual_qxee.html @@ -0,0 +1,5630 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Manual - QxEntityEditor application user guide + + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + + +
+ Select a manual : + + QxOrm user guide + QxEntityEditor user guide +
+
+
+ + + + + + + + + +
+

QxEntityEditor application manual - Table of Contents

+
+
    +
  1. + Introduction +
      +
    1. + QxEntityEditor : graphic editor for QxOrm library +
    2. +
    3. + Download and installation +
    4. +
    5. + QxEntityEditor videos +
    6. +
    +
  2. +
  3. + Main features +
      +
    1. + Main screen views +
        +
      1. + Zoom on entities diagram +
      2. +
      3. + "Splitter" view mode +
      4. +
      +
    2. +
    3. + QxEntityEditor application settings +
    4. +
    5. + Register a license key +
    6. +
    7. + Create/open a *.qxee project +
        +
      1. + Architecture of a *.qxee project file (SQLite + database) +
      2. +
      +
    8. +
    9. + Project settings +
    10. +
    11. + Manage entities +
        +
      1. + Create a new entity +
      2. +
      3. + Modify an entity +
      4. +
      5. + Delete an entity +
      6. +
      7. + Clone an entity +
      8. +
      9. + Entity settings +
      10. +
      11. + Colors associated to an entity +
      12. +
      +
    12. +
    13. + Manage list of properties of an entity +
        +
      1. + Add/modify/delete a property +
      2. +
      3. + Property settings +
      4. +
      +
    14. +
    15. + Manage relationships between entities +
        +
      1. + Add/modify/delete a relationship +
      2. +
      3. + Relationship settings +
      4. +
      +
    16. +
    17. + Manage enumerations +
        +
      1. + Add/modify/delete/clone an enumeration +
      2. +
      3. + Enumeration settings +
      4. +
      5. + Colors associated to an enumeration +
      6. +
      +
    18. +
    19. + Manage namespaces +
        +
      1. + Rename a namespace +
      2. +
      3. + Manage colors of a namespace +
      4. +
      +
    20. +
    21. + Manage post-it/comments +
        +
      1. + Add/modify/delete/clone a post-it +
      2. +
      3. + Colors associated to a post-it +
      4. +
      +
    22. +
    23. + Organize diagram layout +
    24. +
    25. + Project historic (tag project state) +
    26. +
    27. + C++ source code preview +
    28. +
    29. + Naming convention (snake_case, camelCase) +
    30. +
    31. + List of available plugins +
    32. +
    +
  4. +
  5. + Import plugins +
      +
    1. + Import from a directory linked to a + Source Control manager (Git, Perforce, CVS, etc.) +
    2. +
    3. + Import project based on JSON file +
    4. +
    5. + Import from MySQL or MariaDB database +
    6. +
    7. + Import from PostgreSQL database +
    8. +
    9. + Import from SQLite database +
    10. +
    11. + Import from database using ODBC driver (Oracle, MS + SQL Server, etc.) +
    12. +
    +
  6. +
  7. + Export plugins +
      +
    1. + Export to C++ project +
        +
      1. + C++ export settings +
      2. +
      3. + Overview of generated C++ + project +
      4. +
      5. + Build generated C++ project + (using qmake or cmake) +
      6. +
      7. + Example : how to use generated + C++ project +
      8. +
      +
    2. +
    3. + Export to C++ model/view project +
        +
      1. + Export settings +
      2. +
      3. + Overview of + generated project +
      4. +
      +
    4. +
    5. + Export to C++ services project +
        +
      1. + Export settings +
      2. +
      3. + Overview of generated + project +
      4. +
      5. + Generic application + server to provide services +
      6. +
      +
    6. +
    7. + Export SQL DDL database schema +
    8. +
    9. + Print entities diagram +
    10. +
    11. + Export to a directory linked to a + Source Control manager (Git, Perforce, CVS, etc.) +
    12. +
    13. + Export project to XML or JSON format +
    14. +
    +
  8. +
  9. + Javascript engine to customize export +
      +
    1. + Architecture and workflow of Javascript + engine +
        +
      1. + Input parameters of Javascript + engine +
      2. +
      +
    2. +
    3. + Available functions in Javascript +
        +
      1. + Get entity details +
      2. +
      3. + Iterate over list of + properties of an entity +
      4. +
      5. + Get property details +
      6. +
      7. + Get enumeration details +
      8. +
      9. + Get meta-data of + entity/property/enumeration +
      10. +
      11. + Get environment variable +
      12. +
      13. + Read and write to files +
      14. +
      15. + Get list of entities/enumerations of + a project +
      16. +
      17. + Fetch all application settings (at + global level, project level and plugin level) +
      18. +
      +
    4. +
    5. + Add a custom action (placeholder) in C++ + export template +
    6. +
    7. + Script example : add automatically + Q_PROPERTY definition on all generated C++ properties +
    8. +
    9. + Enable Javascript debugger editor +
    10. +
    +
  10. +
  11. + Execute custom scripts (shell/bat) before/after plugin + execution +
  12. +
  13. + QxEntityEditor command-line interface +
  14. +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt + Ambassador Program + +
+
+
+
+ +

Introduction

+
+ The goal of this documentation is to provide a user guide to learn how to work with + QxEntityEditor application features (the graphic editor for QxOrm library). + This manual is intended for developers and software architects who are looking for a solution to + manage a persistent data layer in C++/Qt. + Technical skills in C++ and databases are required to understand this document. +

+ Note : another documentation dedicated to QxOrm library is + available. +

+

QxEntityEditor : graphic + editor for QxOrm library

+
+ QxEntityEditor is a graphic editor for QxOrm library : QxEntityEditor + provides a graphic way to manage the data model.
+ QxEntityEditor is multi-platform (available for Windows, Linux and Mac OS X) and + generates native code for all environments : desktop (Windows, Linux, Mac OS X), embedded and + mobile (Android, iOS, Windows Phone, Raspberry Pi, etc.).
+
+ QxEntityEditor is based on plugins and provides many ways to import/export your data + model : + + + + + + + + + + + + + + + + + +
QxEntityEditor on Windows + QxEntityEditor on Linux + QxEntityEditor on Mac OS X +
QxEntityEditor on WindowsQxEntityEditor on LinuxQxEntityEditor on Mac OS X
+

+ QxEntityEditor application is developed by XDL Team, a software development engineer + since 2003.
+

+
+

Download and + installation

+
+ QxEntityEditor application can be downloaded on QxOrm web site, � + Download � web page. + Several QxEntityEditor versions are available : +
    +
  • Windows (from Windows XP to Windows 10) 32bits and 64bits mode ;
  • +
  • Linux (Ubuntu, Fedora, etc...) 32bits and 64bits mode ;
  • +
  • Mac OS X (64bits only).
  • +
+ For Windows, QxEntityEditor is available with an installation setup or a portable ZIP file.
+ For Linux and Mac OS X, QxEntityEditor is available only with a portable ZIP file.
+ No extra dependency is required, QxEntityEditor installation is very easy : you just have to + unzip downloaded file and run QxEntityEditor executable. +

+
+

QxEntityEditor + videos

+
+ Here is a quick overview of + QxEntityEditor features :
+
+
+
+ Video presentation step by step : +
    +
  • Download and install QxOrm library (10s) ;
  • +
  • Download and install QxEntityEditor (56s) ;
  • +
  • Create a QxEntityEditor project (1m 46s) ;
  • +
  • Export entities to a C++/Qt project (8m 26s) ;
  • +
  • Export entities to a DDL SQL database script (10m 22s) ;
  • +
  • Create a client/server application to transfer entities over network (12m 31s) ; +
  • +
  • Export QxEntityEditor project to a XML or JSON file (17m 13s) ;
  • +
  • Execute QxEntityEditor with command line (no GUI) (18m 07s).
  • +
+
+
+
+ Here is another video of + QxEntityEditor application to show how to import an existing database structure (MySQL + Workbench project) :
+
+
+
+ Video step by step : +
    +
  • MySQL Workbench project - Sakila sample database (10s) ;
  • +
  • Create a DSN to connect to MySQL by ODBC (46s) ;
  • +
  • Import database structure in a QxEntityEditor project (1m 15s) ;
  • +
  • Export QxEntityEditor project to a C++ Qt project (3m 10s) ;
  • +
  • Build the generated C++ Qt project (4m 22s).
  • +
+
+
+
+ +

Main features

+
+ QxEntityEditor is a graphic editor to manage : entities, properties, relationships between + entities, enumerations, namespaces. + To link database and C++ source code : +
    +
  • an entity is a table on database side, and a class on C++ source code side ;
  • +
  • a property is a column of a table on database side, and a data member of a class on C++ + source code side ;
  • +
  • a relationship (1-n, n-1, 1-1 or n-n) is a link between 2 tables + (foreign key) on database side, and a link between 2 classes on C++ source code side ;
  • +
  • an enumeration is a list of values available on C++ source code side (for now, this is just + a converted numeric value on database side) ;
  • +
  • a namespace is a database schema, and where classes are located on C++ source code side. +
  • +
+
+

Main screen views

+
+ Here is a screenshot which shows all areas of QxEntityEditor main view : +

+ All views +

+
    +
  • Area 1 : main menu and toolbar of QxEntityEditor application ==> all actions are + available with these buttons ;
  • +
  • Area 2 : listbox to load quickly recent projects ;
  • +
  • Area 3 : treeview to display all project items (entities, properties, + relationships, enumerations, namespaces) ;
  • +
  • Area 4 : "Navigator" view to move quickly on entities diagram (useful for + large projects) ;
  • +
  • Area 5 : entities diagram to display all project items on a graphical view ;
  • +
  • Area 6 : settings screen (with tabs) for entities, properties, relationships, + enumerations + C++ source code preview ;
  • +
  • Area 7 : zoom on entities diagram.
  • +
+
+

Zoom on entities + diagram

+
+ QxEntityEditor application provides several ways to zoom on entities diagram : +
    +
  • using the main menu : View >> Zoom view to XX% ;
  • +
  • using the slider at the bottom-right of the screen ;
  • +
  • using a contextual menu, right-click on entities diagram, sub-menu : View >> + Zoom view to XX% ;
  • +
  • using left-click + mouse wheel on entities diagram.
  • +
+
+ Zoom +

+
+

"Splitter" view + mode

+
+ View >> Show/hide splitter mode menu switches tabs settings (entities, + properties, relationships, enumerations + C++ source code preview) : +
    +
  • on the right part of the screen to provide a quick access on selected item settings ; +
  • +
  • hidden to display entities diagram on full screen (default value).
  • +
+
+ Splitter mode +

+
+
+

QxEntityEditor + application settings

+
+ QxEntityEditor application global parameters (for all projects) are accessible via main menu + Tools >> Global settings : +

+ Global settings +
+
    +
  • Field � QxOrm library path � : define where QxOrm library is located. + This parameter is required to run a C++ export process to find QxOrm.pri (or + QxOrm.cmake) configuration file. + You can put an absolute path, or use an environment variable, for example : + $$(QXORM_DIR) ; +
  • +
  • Field � Auto load last opened project at startup � : run QxEntityEditor + application loading automatically the last opened project ;
  • +
  • Field � Display property type in entities viewer � : if option enabled, then each + property type is displayed on entities diagram ;
  • +
  • Field � Use old style to draw relationships � : simplify relationships display + (1-n, n-1, 1-1 or n-n) on entities diagram ;
  • +
  • Field � Disable undo/redo feature � : can be useful to optimize performance with + large projects ;
  • +
  • Fields � Entity/Enum/Comment width � : define default items width on entities + diagram.
  • +
+
+
+

Register a license + key

+
+ Without a valid license key, a QxEntityEditor project is limited to 5 entities per project. + To remove this limitation, you can register a license key via main menu Help >> License + information : +

+ License +

+ Just copy/past your license key in the field License key, then push the Save + button. + A web access is required to register a license key. + If no error occurred, then the license key is registered and QxEntityEditor application can be + used without any limitation until Expiration date field. +

+ Note : if a web access error occurred during registration, you could try to enable � + If you are behind a proxy... � option. +

+ Other note : to get a valid license key, please contact us at : ic-east.com +

+
+

Create/open a + *.qxee project

+
+ A new QxEntityEditor project is created via main menu File >> New project : +

+ Project new +
+
    +
  • Field � Project name � : the QxEntityEditor project name. Project file has the + same name with *.qxee extension ;
  • +
  • Field � Project location � : define where QxEntityEditor project is located. You + can use the "..." button to select a directory.
  • +
+
+ An existing QxEntityEditor project can be opened via main menu File >> Open project + : then just select a project file with *.qxee extension. + Under the main toolbar of QxEntityEditor application, a list of recent projects is available to + switch quickly from a project to another : +

+ Project list +

+

Architecture of a + *.qxee project file (SQLite database)

+
+ A *.qxee project file of QxEntityEditor application is a SQLite database.
+ A same QxEntityEditor project can be shared on all environments : Windows, Linux and Mac OS + X.
+ A *.qxee project file can be opened by a SQLite database manager tool : for example, + the free Firefox plugin SQLite Manager : +

+ Project database +

+ Note : using the Execute custom scripts (shell/bat) + before/after plugin execution feature, it is possible for example to apply a script + (.bat or .sh) to modify some imported data in the *.qxee SQLite database + file after an import process. +

+
+
+

Project + settings

+
+ QxEntityEditor *.qxee project parameters are accessible via main menu Tools >> + Project settings : +

+ Project settings tab 1 +

+
    +
  • Field � Default entity namespace � : default namespace when an entity is created + (it is possible to define another namespace in Entity + settings screen) ;
  • +
  • Field � Table name prefix � : prefix used to set table name associated to entity ; +
  • +
  • Field � Table name suffix � : suffix used to set table name associated to entity ; +
  • +
  • Field � Primary key prefix � : prefix used to set primary key name associated to + entity ;
  • +
  • Field � Primary key suffix � : suffix used to set primary key name associated to + entity ;
  • +
  • Field � Default primary key type � : default C++ type for primary keys ;
  • +
  • Field � Default property type � : default C++ type for properties.
  • +
+
+ The second tab of project parameters screen provides a way to manage items colors in the + entities diagram at a project level : +

+ Project settings tab 2 +

+ Note : items colors in the entities diagram can be defined at several levels (from the + more global level to the more specific level) : + +
+
+

Manage entities

+
+ An entity in QxEntityEditor application is a table from a database point of view, and is a + persistent class (registered in QxOrm context) in C++ source code. + QxEntityEditor application provides features to create, modify, delete and clone entity. +

+

Create a new + entity

+
+ A new entity can be created via : +
    +
  • Main menu : Actions >> New entity ;
  • +
  • Right-click contextual menu on entities diagram : Entity >> New entity ; +
  • +
  • The � Create a new entity � button on entity parameters screen when no entity + is selected.
  • +
+
+ Entity new +

+ Note : these actions open the entity parameters screen in + creation context. + The entity will be really created and added to the *.qxee project after saving it in + the entity parameters screen. +

+
+

Modify an + entity

+
+ An entity can be modified via : +
    +
  • Main menu : Actions >> Modify entity ;
  • +
  • Right-click contextual menu on entities diagram : Entity >> Modify entity + ;
  • +
  • A double-click on entity name in the entities diagram.
  • +
+
+ Entity modify +

+ Note : these actions open the entity parameters screen in + change context. + All entity changes will be really applied to the *.qxee project after saving it in the + entity parameters screen. +

+
+

Delete an + entity

+
+ An entity (or several entities) can be deleted via : +
    +
  • Main menu : Actions >> Delete entity ;
  • +
  • Right-click contextual menu on entities diagram : Entity >> Delete entity + ;
  • +
  • The "Del" keyboard shortcut when 1 or several entities are selected.
  • +
+
+ Entity delete +

+
+

Clone an + entity

+
+ An entity can be cloned via : +
    +
  • Main menu : Actions >> Clone entity ;
  • +
  • Right-click contextual menu on entities diagram : Entity >> Clone entity + ;
  • +
+
+ Entity clone +

+ Note : a cloned entity has all properties from source entity. Relationships are not + cloned. +

+
+

Entity settings +

+
+ Entity parameters are accessible via Entity settings tab : +

+ Entity settings +

+ This parameters screen is divided in several sections : +

+ -- Section Entity information (version XX) : entity version is incremented by + each project historic. +
    +
  • Field � Name � : entity name and generated C++ class name ;
  • +
  • Field � Table name � : database table name mapped to the entity (uses default prefix/suffix defined in project settings) ; +
  • +
  • Field � Namespace � : namespace where entity and generated C++ class are + located, each sub-namespace must be separated by :: characters, for example : + ns1::ns2::ns3 ; +
  • +
  • Field � Description � : entity description (displayed in generated C++ source + code) ;
  • +
  • Field � Inherit from � : parent entity (or C++ base class) : child entity gets + automatically primary key and all properties defined in parent entity ;
  • +
  • Field � Read only � : if enabled, then entity is in read-only mode : QxOrm + library only allows SQL queries of type SELECT (qx::dao fetch functions of QxOrm). + if enabled, then SQL queries of type INSERT, UPDATE and DELETE are + not available. + This parameter can be used for example to map an entity to a database view (read-only) + ;
  • +
  • Field � Abstract � : an abstract entity is not mapped to a database table, and + generated C++ class cannot be instantiated (abstract + class) : this parameter can be used for example to create parent entities which + contain a list of common properties to share with all other entities ;
  • +
  • Field � Soft delete column � : if empty, then remove an entity from database + means delete physically the row from database. + If not empty, this field defines the database + column used to process a soft delete behaviour (or logical delete) : the entity + is not physically removed in database.
  • +
  • Field � Validator method name � : validation function name (for example : + IsValid) used to validate an entity before inserting or updating it in database. + Validation method implementation must be written by the developper in its own + *.cpp file : see QxOrm library QxValidator + module for more details. +
  • +
+
+ -- Section Entity triggers : +
    +
  • Checkbox � Before fetch, After fetch, Before insert, etc... � : + if checked, add C++ triggers methods definition onBeforeFetch(), + onAfterFetch(), onBeforeInsert(), etc... + Trigger method implementation must be written by the developper in its own *.cpp + file : see QxOrm library user manual for more + details. +
  • +
+
+ -- Section Primary key property : fast definition of primary key (detailled settings of primary key is available). + +
+ -- Section List of properties : fast definition of list of properties (detailled settings for each property is available). + This list can be manually sorted using arrow up and arrow down buttons. +
    +
  • Column � Name � : property name, and data member name in C++ source code ;
  • +
  • Column � Type � : C++ property type (default type can be defined in project settings screen) ;
  • +
  • Column � Decoration � : C++ decoration type (for example boost::optional to manage database + NULL value) ;
  • +
  • Column � Collection � : if property is a list of, then define C++ list type ; +
  • +
  • Column � Default value � : property default value ;
  • +
  • Column � Index � : define a database index to optimize SELECT SQL + queries ;
  • +
  • Column � Transient � : if enabled, then C++ data member is not mapped to a + database column (property is registered in QxOrm context but is not persistent) ;
  • +
  • Button � Delete � : remove property from the list.
  • +
+
+ -- Section List of relationships : fast definition of list of relationships (detailled settings for each relationship is available). + This list can be manually sorted using arrow up and arrow down buttons. +
    +
  • Column � Name � : relationship name, and data member name in C++ source code ; +
  • +
  • Column � Target � : target entity ;
  • +
  • Column � n-1 � : relationship of type many-to-one ;
  • +
  • Column � 1-n � : relationship of type one-to-many ;
  • +
  • Column � n-n � : relationship of type many-to-many ;
  • +
  • Column � 1-1 � : relationship of type one-to-one ;
  • +
  • Column � Decoration � : C++ decoration type (for relationships, QxOrm library + recommends smart-pointer : boost::shared_ptr, std::shared_ptr or + QSharedPointer) ; +
  • +
  • Column � Collection � : if relationship is a list of (1-n and + n-n), then define C++ list type ; +
  • +
  • Column � Foreign key � : relationship foreign key : property name of target + entity ;
  • +
  • Button � Delete � : remove relationship from the list.
  • +
+
+ -- Section List of meta-data : meta-data provides a way to add and manage + extra-parameters and are available in C++ source code (QxOrm introspection engine) and Javascript engine to customize QxEntityEditor export + process. +
    +
  • Column � Key � : meta-data key ;
  • +
  • Column � Value � : meta-data value ;
  • +
  • Button � Delete � : remove meta-data from the list.
  • +
+
+
+

Colors + associated to an entity

+
+ Entity colors can be defined via right-click contextual menu Define entity colors : +

+ Entity colors +

+ Note : items colors in the entities diagram can be defined at several levels (from the + more global level to the more specific level) : + +
+
+
+

Manage list of properties + of an entity

+
+ A property in QxEntityEditor application is a column (of a table) from a database point of view, + and is a data member in a C++ class (registered in QxOrm context). + QxEntityEditor application provides features to create, modify, delete and sort properties of an + entity. +

+

Add/modify/delete a property

+
+ Add and delete a property is done via entity parameters screen : + the List of properties section of this settings screen provides a way to add/remove + properties. + It is also possible to sort manually this list of properties. +

+ Modify a property is accessible via a button which is displayed on entities diagram when the + mouse is closed to a property : +

+ Property settings access +

+
+

Property + settings

+
+ Detailled property parameters are accessible via Property settings tab : +

+ Property settings +

+ This parameters screen is divided in several sections : +

+ -- Section Property information (version XX) : property version depends on project historic. +
    +
  • Field � Name � : property name, and data member name in C++ source code ;
  • +
  • Field � Column name � : database column name (if empty, then Column name + == Name) ;
  • +
  • Field � Description � : property description (displayed in generated C++ source + code) ;
  • +
  • Field � Index � : define a database index to optimize SELECT SQL queries + ;
  • +
  • Field � Transient � : if enabled, then C++ data member is not mapped to a + database column (property is registered in QxOrm context but is not persistent) ;
  • +
  • Field � Serializable � : if enabled, property is managed by serialization engine of QxOrm library ;
  • +
  • Field � Obsolete � : enable this option to remove a property without breaking ascendant compatibility of + serialization engine of QxOrm library : property becomes private without + Get/Set accessors. +
  • +
+
+ -- Section Property type : +
    +
  • Field � Type � : C++ property type (default type can be defined in project settings screen) ;
  • +
  • Field � Decoration � : C++ decoration type (for example boost::optional to manage database + NULL value) ;
  • +
  • Field � Default value � : property default value ;
  • +
  • Field � Collection � : if property is a list of, then define C++ list type. +
  • +
+
+ -- Section Property validation : validate a property before inserting/updating + in database using QxValidator module of QxOrm library. +
    +
  • Field � Min value � : minimal value allowed for a property (numeric type) ; +
  • +
  • Field � Max value � : maximal value allowed for a property (numeric type) ; +
  • +
  • Field � Min length � : minimal length allowed for a property (string type) ; +
  • +
  • Field � Max length � : maximal length allowed for a property (string type) ; +
  • +
  • Field � Regular expression � : regular expression used to validate a property + value (for example, an e-mail regular expression to check if property contains a valid + e-mail address) ;
  • +
  • Field � Not NULL � : check if property value + is not NULL ;
  • +
  • Field � Unique � : unique value in database, 2 rows in a same table cannot have + the same value in the column mapped to current property.
  • +
+
+ -- Section Advanced : +
    +
  • Field � Accessibility �, values � public, protected or + private � : a public property is accessible without Get/Set + methods, a protected property is only accessible by inherited classes, a + private property is only accessible via Get/Set methods ; +
  • +
  • Field � SQL type � : QxOrm library provides a default mapping SQL type / C++ type, it is + possible to override default SQL type with this parameter ;
  • +
  • Field � SQL alias � : force a SQL alias to database column used by QxOrm + library to build SQL queries ;
  • +
  • Field � Format � : define property format (printf syntax) for database + storage (can be useful to manage dates and times for example) ;
  • +
  • Field � Get/Set accessors � : if enabled, Get/Set accessors are + generated in C++ source code to access and modify property value ;
  • +
  • Field � Read only � : if enabled, only Get accessor is generated in C++ + source code, so property becomes read-only ;
  • +
  • Field � Get method implementation � : provides a way to override default + Get method implementation in C++ source code to access property value ; +
  • +
  • Field � Set method implementation � : provides a way to override default + Set method implementation in C++ source code to modify property value. +
  • +
+
+ -- Section List of meta-data : meta-data provides a way to add and manage + extra-parameters and are available in C++ source code (QxOrm introspection engine) and Javascript engine to customize QxEntityEditor export + process. +
    +
  • Column � Key � : meta-data key ;
  • +
  • Column � Value � : meta-data value ;
  • +
  • Button � Delete � : remove meta-data from the list.
  • +
+
+
+
+

Manage relationships + between entities

+
+ A relationship between 2 entities (1-n, n-1, 1-1 or n-n) in + QxEntityEditor application links 2 tables in database, and links 2 classes in C++ source code. + QxEntityEditor application provides features to create, modify, delete and sort relationships of + an entity. +

+

Add/modify/delete a relationship

+
+ Add and delete a relationship is done via entity parameters + screen : the List of relationships section of this settings screen provides a + way to add/remove relationships. + It is also possible to sort manually this list of relationships. +

+ Modify a relationship is accessible via a button which is displayed on entities diagram when + the mouse is closed to a relationship : +

+ Relation settings access +

+
+

Relationship + settings

+
+ Detailled relationship parameters are accessible via Relationship settings tab : +

+ Relation settings +

+ This parameters screen is divided in several sections : +

+ -- Section Relationship information (version XX) : relationship version depends + on project historic. +
    +
  • Field � Name � : relationship name, and data member name in C++ source code ; +
  • +
  • Field � Target � : target entity ;
  • +
  • Field � Description � : relationship description (displayed in generated C++ + source code) ;
  • +
  • Fields � 1-n, n-1, 1-1 or n-n � : relationship type, depending on selected option, + some other fields are enabled or disabled ;
  • +
  • Field � Column name � : enabled only for relationships of type n-1, + column name in database (if empty, then Column name == Name) ;
  • +
  • Field � Decoration � : C++ decoration type (for relationships, QxOrm library + recommends smart-pointer : boost::shared_ptr, std::shared_ptr or + QSharedPointer) ; +
  • +
  • Field � Collection � : if relationship is a list of (1-n and + n-n), then define C++ list type ; +
  • +
  • Field � Foreign key � : relationship foreign key : property name of target + entity ;
  • +
  • Field � FK owner � : used only by n-n relationships ;
  • +
  • Field � Extra-table � : used only by n-n relationships, extra-table name + which links source and target entities ;
  • +
  • Field � Index � : define a database index to optimize SELECT SQL queries + ;
  • +
  • Field � Serializable � : if enabled, relationship is managed by serialization engine of QxOrm library ;
  • +
  • Field � Obsolete � : enable this option to remove a relationship without breaking ascendant compatibility of + serialization engine of QxOrm library : relationship becomes private without + Get/Set accessors. +
  • +
+
+ -- Section Advanced : +
    +
  • Field � Accessibility �, values � public, protected or + private � : a public relationship is accessible without Get/Set + methods, a protected relationship is only accessible by inherited classes, a + private relationship is only accessible via Get/Set methods ; +
  • +
  • Field � Get/Set accessors � : if enabled, Get/Set accessors are + generated in C++ source code to access and modify relationship value ;
  • +
  • Field � Read only � : if enabled, only Get accessor is generated in C++ + source code, so relationship becomes read-only ;
  • +
  • Field � Get method implementation � : provides a way to override default + Get method implementation in C++ source code to access relationship value ; +
  • +
  • Field � Set method implementation � : provides a way to override default + Set method implementation in C++ source code to modify relationship value. +
  • +
+
+ -- Section List of meta-data : meta-data provides a way to add and manage + extra-parameters and are available in C++ source code (QxOrm introspection engine) and Javascript engine to customize QxEntityEditor export + process. +
    +
  • Column � Key � : meta-data key ;
  • +
  • Column � Value � : meta-data value ;
  • +
  • Button � Delete � : remove meta-data from the list.
  • +
+
+
+
+

Manage enumerations

+
+ An enumeration in QxEntityEditor application is a list of values available in C++ source code + (converted to a numeric value in database). + QxEntityEditor application provides features to create, modify, delete and clone enumeration. +

+

Add/modify/delete/clone an enumeration

+
+ Add, modify, delete and clone an enumeration is done via equivalent menu for an entity (just replace entity word by enumeration).
+ So QxEntityEditor application provides exactly same menus as an + entity to manage enumeration. +

+
+

Enumeration + settings

+
+ Enumeration parameters are accessible via Enumeration settings tab : +

+ Enumeration settings +

+ This parameters screen is divided in several sections : +

+ -- Section Enumeration information (version XX) : enumeration version is + incremented by each project historic. +
    +
  • Field � Name � : enumeration name and generated C++ class name ;
  • +
  • Field � Description � : enumeration description (displayed in generated C++ + source code) ;
  • +
  • Field � Namespace � : namespace where enumeration and generated C++ class are + located, each sub-namespace must be separated by :: characters, for example : + ns1::ns2::ns3 ; +
  • +
  • Field � Use Qt macro Q_ENUM � : uses Q_ENUM macro + provided by Qt framework to define an enumeration compatible with Qt + introspection engine ;
  • +
+
+ -- Section List of values : +
    +
  • Column � Key � : value key ;
  • +
  • Column � Value � : value ;
  • +
  • Button � Delete � : remove value from the list.
  • +
+
+ -- Section List of meta-data : meta-data provides a way to add and manage + extra-parameters and are available in C++ source code (QxOrm introspection engine) and Javascript engine to customize QxEntityEditor export + process. +
    +
  • Column � Key � : meta-data key ;
  • +
  • Column � Value � : meta-data value ;
  • +
  • Button � Delete � : remove meta-data from the list.
  • +
+
+
+

Colors associated to + an enumeration

+
+ Enumeration colors can be defined via right-click contextual menu Define enumeration + colors : +

+ Enumeration colors +

+ Note : items colors in the entities diagram can be defined at several levels (from the + more global level to the more specific level) : + +
+
+
+

Manage namespaces

+
+ A namespace in QxEntityEditor application is used to group several items (entities and + enumerations) in a same area. + From a database point of view, a namespace is generally a schema. + In C++ source code, a namespace defines where classes and functions are located (to group them). +

+ Namespaces are used by the following QxEntityEditor feature : Organize diagram layout (to group items automatically). +

+ The QxEntityEditor application treeview (which displays all loaded items in a project) provides + some menus to manage namespaces : +

+ Namespace menu +

+

Rename a + namespace

+
+ To rename a namespace, just do a right-click on project treeview, then contextual menu + Move entities to another namespace : +

+ Namespace rename +

+
+

Manage colors of a namespace

+
+ To define items colors at a namespace level, just do a right-click on project treeview, then + contextual menu Define colors by namespace : +

+ Namespace colors +

+ The left part of this screen displays all namespaces available in *.qxee + project.
+ The right part of this screen provides a way to manage colors for all items located in the + selected namespace. + It is also possible to define a background color (generally a light color) to group all items + in entities diagram. +

+ Note : items colors in the entities diagram can be defined at several levels (from the + more global level to the more specific level) : + +
+
+
+

Manage + post-it/comments

+
+ A comment (or post-it) in QxEntityEditor application is a tag displayed on entities diagram to + provide some details about data model or *.qxee project. + A post-it can be moved everywhere in the entities diagram. + A post-it has a title and a free text area. + It is possible to write some text using HTML format to add colors, put text in bold, italic, + etc... +

+ QxEntityEditor application provides features to create, modify, delete and clone + comment/post-it. +

+ Post-it / comments +

+

Add/modify/delete/clone a post-it

+
+ Add, modify, delete and clone a post-it is done via equivalent menu for an entity (just replace entity word by comment).
+ So QxEntityEditor application provides exactly same menus as an + entity to manage post-it. +

+
+

Colors associated + to a post-it

+
+ Post-it colors can be defined via right-click contextual menu Define comment colors : +

+ Post-it colors +

+ Note : items colors in the entities diagram can be defined at several levels (from the + more global level to the more specific level) : + +
+
+
+

Organize + diagram layout

+
+ A feature is available in QxEntityEditor application to group automatically all items in + entities diagram depending on namespace, and depending on relationships between entities : main + menu View >> Organize diagram layout. + This feature can be useful for example to organize entities diagram after executing an import process. +

+ Organize diagram layout +

+
+

Project historic + (tag project state)

+
+ A QxEntityEditor project can have several versions/historics : main menu Actions >> Tag + project state. +

+ Each project historic changes project items version number (entities, properties, relationships, + etc...). + Version number is used to manage ascendant compatibility with + serialization engine of QxOrm library. + Project historic is also used by database DDL SQL export + plugin : manage database schema evolution (add a table, remove a column, add an index, + etc...). +

+ Tag project state tab 1 +

+ The first tab of this historic screen provides a way to create a new historic title (for example + : date/time, project version number, etc...) and a comment in free text. +

+ Tag project state tab 2 +

+ The second tab of this historic screen displays the list of all project historics already saved. + This list of historics provides buttons to restore a project state in several formats (XML, JSON + or QxEntityEditor *.qxee project file). +

+
+

C++ source code + preview

+
+ It is possible to display a preview of generated C++ source code (header *.h and source + *.cpp files) for the selected item in entities diagram (entity or enumeration). + This C++ source code can be generated by C++ export plugin of + QxEntityEditor. + C++ preview is accessible after selecting an item in entities diagram, then go to C++ + preview tab : +

+ C++ preview +

+
+

Naming convention + (snake_case, camelCase)

+
+ QxEntityEditor application provides a feature to apply quickly a naming convention on all + project items (entities, properties, relationships, etc...). + This feature keeps (doesn't break) mapping with database. This feature is available via main + menu : Naming convention. + 3 styles of naming convention are provided : snake_case, camelCase and + PascalCase. +

+ Naming convention +

+ Note : this feature can be useful for example after executing an import process to harmonize generated C++ source code. +

+
+

List of available + plugins

+
+ QxEntityEditor application is based on plugins to manage import/export process. + A list of available plugins with version number and description is available via main menu : + Help >> About plugins. +

+ List of plugins +

+
+
+ +

Import plugins

+
+ All import process in QxEntityEditor application are accessible via main menu Import : +

+ Import plugins +

+

Import + from a directory linked to a Source Control manager (Git, Perforce, CVS, etc.)

+
+ A QxEntityEditor project (*.qxee file) can be managed by a developers team : the source + code of a QxEntityEditor project can be exported/imported (manually or using command line) with + QxEESourceControlExport and QxEESourceControlImport plugins.
+
+ Associated with a Source Control manager (Git, Perforce, CVS, etc.), these 2 plugins provide : +
    +
  • several people can work simultaneously on the same project ;
  • +
  • a project can easily be versioned in the source code manager ;
  • +
  • each element of a project can be compared (difference between 2 versions of the same + entity for example).
  • +
+ Here is a use case of QxEESourceControlExport and QxEESourceControlImport plugins, with 2 + developers named 'dev A' and 'dev B' (this example can be extended to X developers) : +
    +
  • dev A and dev B work on a same QxEntityEditor project (*.qxee file) ;
  • +
  • dev A creates/changes/deletes some entities in QxEntityEditor application ;
  • +
  • dev B creates/changes/deletes other entities in QxEntityEditor application ;
  • +
  • dev A and dev B export the *.qxee project file with the QxEESourceControlExport plugin + (manually or using command line) ;
  • +
  • once the project is exported to a directory, dev A and dev B check-in (or submit) + all generated JSON files to the Source Control manager (Git, Perforce, CVS, etc.) on their + own branch ;
  • +
  • from the Source Control manager, dev A and dev B merge (or integrate) their own + branch to the development branch DEV (or MAIN or MASTER or LATEST); Note : even if + there are conflicts to resolve, they will be easy to correct because the JSON format is + easily readable ;
  • +
  • dev A and dev B can now get latest files from Source Control manager from DEV branch (or + MAIN or MASTER or LATEST) : these JSON files contain both modifications from dev A and + dev B ;
  • +
  • dev A and dev B can import these JSON files into the QxEntityEditor application using the + import plugin QxEESourceControlImport + (manually or using command line).
  • +
+ Import plugin settings are accessible from the main menu Import >> Import from Source + Control repository (Git, Perforce, CVS, etc.) : +

+ Source Control import plugin +

+ The parameter to enter corresponds to the JSON file present at the root of the directory where + the *.qxee project was exported.
+ This JSON file is named <project_name>.qxee.export.json, for example with + the qxBlog sample project : qxBlog.qxee.export.json. +

+ Source Control output directory +

+ Warning : an import deletes all elements of the current project (entities, properties, + relationships, etc.). +

+ Note : It is possible to start QxEntityEditor from the command line to automatically load + a directory associated with a source code manager when the application starts. +

+ Command line example :
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlImport --QxEESourceControlImport_path="<path_to_the_root_source_control_json_file>"
+
+
+

+
+

Import project based + on JSON file

+
+ + Note : + to work with a source code manager (Git, Perforce, CVS, etc.), it is recommended to use QxEESourceControlExport and QxEESourceControlImport plugins (instead of + creating a single file).
+
+ A QxEntityEditor project can be managed with a text file in JSON format : main menu Import + >> Import from JSON file.
+ To know the JSON structure of a *.qxee project, it is recommended to do a first export process to JSON file. +

+ Import JSON +

+ The JSON import screen is simple and has only 1 field to define : the JSON file to import. +

+ Warning : a JSON import process removes all items from current project (entities, + properties, relationships, etc...). +

+ Note : QxEntityEditor application can be executed with a command-line to load + automatically a JSON file at startup. +

+ Here is a command-line example :
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEEJsonImport --QxEEJsonImport_file="<path_to_your_json_file>"
+
+
+
+ Here is a JSON file example (deployed in ./samples/qxBlog.json directory of + QxEntityEditor package) :
+
+
+{
+    "app_version": 0,
+    "description": "",
+    "dt_creation": "20131206221737",
+    "dt_modification": "20131206221737",
+    "id": 1,
+    "list_all_entities": [
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221810",
+            "dt_modification": "20140617214144",
+            "id": 1,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 1,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "author_id",
+                    "order_level": 0,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 1,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 1
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 2,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "firstname",
+                    "order_level": 1,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 2,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 2
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 3,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "lastname",
+                    "order_level": 2,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 3,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 3
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 4,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "birthdate",
+                    "order_level": 3,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 4,
+                        "list_meta_data": null,
+                        "primitive_type": "QDateTime",
+                        "property_id": {
+                            "id": 4
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 5,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "sex",
+                    "order_level": 4,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": {
+                            "id": 1
+                        },
+                        "id": 5,
+                        "list_meta_data": null,
+                        "primitive_type": "sex::enum_sex",
+                        "property_id": {
+                            "id": 5
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 18,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_blog",
+                    "order_level": 17,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214144",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 18,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 18
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214144",
+                        "extra_table": "",
+                        "foreign_key": "author",
+                        "foreign_key_owner": "",
+                        "id": 2,
+                        "inverse_property_id": {
+                            "id": 15
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 18
+                        },
+                        "type_relation": "one-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "author",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221810",
+                "dt_modification": "20140617214144",
+                "entity_id": {
+                    "id": 1
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 1,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "author_id",
+                "order_level": 0,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 1,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 1
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_author",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206222031",
+            "dt_modification": "20140617214043",
+            "id": 4,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 12,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "blog_id",
+                    "order_level": 11,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 12,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 12
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 13,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "title",
+                    "order_level": 12,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 13,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 13
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 14,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "text",
+                    "order_level": 13,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 14,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 14
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 15,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "author",
+                    "order_level": 14,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 1
+                        },
+                        "enumeration_id": null,
+                        "id": 15,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 15
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "",
+                        "foreign_key": "",
+                        "foreign_key_owner": "",
+                        "id": 1,
+                        "inverse_property_id": {
+                            "id": 18
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 15
+                        },
+                        "type_relation": "many-to-one",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 16,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_comment",
+                    "order_level": 15,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 3
+                        },
+                        "enumeration_id": null,
+                        "id": 16,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 16
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "",
+                        "foreign_key": "blog_id",
+                        "foreign_key_owner": "",
+                        "id": 3,
+                        "inverse_property_id": {
+                            "id": 19
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 16
+                        },
+                        "type_relation": "one-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 17,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_category",
+                    "order_level": 16,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 2
+                        },
+                        "enumeration_id": null,
+                        "id": 17,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 17
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "t_qxee_blog_category",
+                        "foreign_key": "blog_id",
+                        "foreign_key_owner": "category_id",
+                        "id": 5,
+                        "inverse_property_id": {
+                            "id": 20
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 17
+                        },
+                        "type_relation": "many-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "blog",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206222031",
+                "dt_modification": "20140617214043",
+                "entity_id": {
+                    "id": 4
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 12,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "blog_id",
+                "order_level": 11,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 12,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 12
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_blog",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221933",
+            "dt_modification": "20140617214115",
+            "id": 2,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 6,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "category_id",
+                    "order_level": 5,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 6,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 6
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 7,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "name",
+                    "order_level": 6,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 7,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 7
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 8,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "description",
+                    "order_level": 7,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 8,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 8
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 20,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_blog",
+                    "order_level": 19,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214115",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 20,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 20
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214115",
+                        "extra_table": "t_qxee_blog_category",
+                        "foreign_key": "category_id",
+                        "foreign_key_owner": "blog_id",
+                        "id": 6,
+                        "inverse_property_id": {
+                            "id": 17
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 20
+                        },
+                        "type_relation": "many-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "category",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221933",
+                "dt_modification": "20140617214115",
+                "entity_id": {
+                    "id": 2
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 6,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "category_id",
+                "order_level": 5,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 6,
+                    "list_meta_data": null,
+                    "primitive_type": "QString",
+                    "property_id": {
+                        "id": 6
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_category",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221951",
+            "dt_modification": "20131206221951",
+            "id": 3,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 9,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "comment_id",
+                    "order_level": 8,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 9,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 9
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 10,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "title",
+                    "order_level": 9,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 10,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 10
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 11,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "text",
+                    "order_level": 10,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 11,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 11
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20131206222031",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 19,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "blog_id",
+                    "order_level": 18,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20131206222031",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 19,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 19
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20131206222031",
+                        "extra_table": "",
+                        "foreign_key": "",
+                        "foreign_key_owner": "",
+                        "id": 4,
+                        "inverse_property_id": {
+                            "id": 16
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 19
+                        },
+                        "type_relation": "many-to-one",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "comment",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221951",
+                "dt_modification": "20131206221951",
+                "entity_id": {
+                    "id": 3
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 9,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "comment_id",
+                "order_level": 8,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 9,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 9
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_comment",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        }
+    ],
+    "list_comments": [
+        {
+            "app_version": 0,
+            "comment_text": "- Design the entity model in few minutes\n\n- Generate C++ persistent classes automatically\n\n- Generate DDL SQL script automatically\n\n- Manage schema evolution for each project version\n\n- Compile C++ native code everywhere : Windows, Linux, MacOSX, Android, iOS, etc...\n\n- Transfer your data model over network and create quickly client/server applications",
+            "comment_text_html": false,
+            "comment_title": "qxBlog project",
+            "dt_creation": "20131206222130",
+            "dt_modification": "20140107093142",
+            "id": 1,
+            "list_meta_data": null,
+            "user_id_creation": 0,
+            "user_id_modification": 0
+        }
+    ],
+    "list_enumerations": [
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221840",
+            "dt_modification": "20131210205552",
+            "id": 1,
+            "key": "",
+            "list_meta_data": null,
+            "list_of_key_value": {
+                "female": 2,
+                "male": 1,
+                "unknown": 3
+            },
+            "name": "sex",
+            "namespace": "",
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "qt_enum": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "version": 0
+        }
+    ],
+    "list_groups": null,
+    "list_meta_data": null,
+    "list_namespaces": null,
+    "location": "C:/Temp/qxee",
+    "name": "qxBlog",
+    "project_guid": "{16335d56-73ac-48cf-8fcd-f74cc7d97201}",
+    "project_parameters": {
+        "app_version": 0,
+        "default_entity_namespace": "",
+        "default_primary_key_type": "long",
+        "default_property_type": "QString",
+        "dt_creation": "20131206221737",
+        "dt_modification": "20131206221737",
+        "id": 1,
+        "list_meta_data": null,
+        "lst_plugin_script": {
+        },
+        "primary_key_prefix": "",
+        "primary_key_suffix": "_id",
+        "project_id": {
+            "id": 1
+        },
+        "table_name_prefix": "t_",
+        "table_name_suffix": "",
+        "user_id_creation": 0,
+        "user_id_modification": 0
+    },
+    "user_id_creation": 0,
+    "user_id_modification": 0,
+    "version": 0
+}
+
+
+

+
+

Import from MySQL + or MariaDB database

+
+ A MySQL (or MariaDB) database structure can be imported in QxEntityEditor application via main + menu : Import >> Import from MySQL (or MariaDB) database : +

+ Import MySQL or MariaDB +

+ This import parameters screen is divided in several sections : +

+ -- Section MySQL (or MariaDB) database connection : +
    +
  • Field � Database server address (IP) � : the MySQL server name or IP address ; +
  • +
  • Field � Database port � : MySQL server port number to connect to database ;
  • +
  • Field � Database name � : database name to import ;
  • +
  • Field � Database login � : user name to connect to database ;
  • +
  • Field � Database password � : password to connect to database ;
  • +
  • Button � Connect to database � : if an error occurred, a warning message is + displayed, otherwise all database tables and columns are displayed in � Database items + to import to QxEntityEditor project � section (treeview).
  • +
+
+ -- Section Import settings : +
    +
  • Field � Namespace � : namespace used to group all imported + items in current project ;
  • +
  • Field � Delete all entities in the namespace before importing � : remove all + entities from above namespace before running import from database process ;
  • +
  • Field � Import tables/columns comment to entities/properties description � : + import tables and columns description defined in database ;
  • +
  • Field � Add boost::optional<T> decoration if a column definition allows NULL + value � : add automatically boost::optional + decoration to manage NULL value ;
  • +
  • Field � Import columns default value � : import default values defined in database + columns ;
  • +
  • Field � Organize diagram layout after import process � : run automatically the organize entities diagram feature after executing + import process.
  • +
+
+ -- Section Relationship import settings : +
    +
  • Field � Decoration � : default relationship C++ type decoration (for + relationships, QxOrm library recommends smart-pointer : boost::shared_ptr, + std::shared_ptr or QSharedPointer) ; +
  • +
  • Field � Collection � : if relationship is a list of (1-n and n-n), + then define C++ list type ;
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor provides a + default mapping SQL type / C++ type. + You can use this list to override default behaviour : +
    +
  • Column � SQL type � : SQL type to map. SQL type search is case insensitive, and is + applied on first characters (STARTS WITH behaviour) : for example, varchar + matches VARCHAR(255) ;
  • +
  • Column � C++ type � : C++ type to use when SQL type is found ;
  • +
  • Button � Delete � : remove SQL type / C++ type mapping.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : when + QxEntityEditor is connected to database, all items (tables, columns, primary keys, + relationships, views, etc...) are displayed in this section. + By default, there is no item selected. + You can select all items to import with 1 click on the treeview root item. + It is also possible to select quickly items from a specific schema. + Once items to import are selected, the � Ok � button becomes enabled to run import + process. +


+ Note : all import parameters (database connection, import settings and relationships, SQL + type / C++ type mapping, etc...) are automatically saved when closing the import screen. + All import parameters are automatically re-loaded when opening the import screen. +

+ Other note : a QxEntityEditor video is available to show how + to import the MySQL database sample named sakila. +

+
+

Import from + PostgreSQL database

+
+ A PostgreSQL database structure can be imported in QxEntityEditor application via main menu : + Import >> Import from PostgreSQL database : +

+ Import PostgreSQL +

+ This import parameters screen is divided in several sections : +

+ -- Section PostgreSQL database connection : +
    +
  • Field � Database server address (IP) � : the PostgreSQL server name or IP address + ;
  • +
  • Field � Database port � : PostgreSQL server port number to connect to database ; +
  • +
  • Field � Database name � : database name to import ;
  • +
  • Field � Database login � : user name to connect to database ;
  • +
  • Field � Database password � : password to connect to database ;
  • +
  • Button � Connect to database � : if an error occurred, a warning message is + displayed, otherwise all database tables and columns are displayed in � Database items + to import to QxEntityEditor project � section (treeview).
  • +
+
+ -- Section Import settings : +
    +
  • Field � Namespace � : namespace used to group all imported + items in current project ;
  • +
  • Field � Delete all entities in the namespace before importing � : remove all + entities from above namespace before running import from database process ;
  • +
  • Field � Import tables/columns comment to entities/properties description � : + import tables and columns description defined in database ;
  • +
  • Field � Add boost::optional<T> decoration if a column definition allows NULL + value � : add automatically boost::optional + decoration to manage NULL value ;
  • +
  • Field � Import columns default value � : import default values defined in database + columns ;
  • +
  • Field � Organize diagram layout after import process � : run automatically the organize entities diagram feature after executing + import process.
  • +
+
+ -- Section Relationship import settings : +
    +
  • Field � Decoration � : default relationship C++ type decoration (for + relationships, QxOrm library recommends smart-pointer : boost::shared_ptr, + std::shared_ptr or QSharedPointer) ; +
  • +
  • Field � Collection � : if relationship is a list of (1-n and n-n), + then define C++ list type ;
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor provides a + default mapping SQL type / C++ type. + You can use this list to override default behaviour : +
    +
  • Column � SQL type � : SQL type to map. SQL type search is case insensitive, and is + applied on first characters (STARTS WITH behaviour) : for example, varchar + matches VARCHAR(255) ;
  • +
  • Column � C++ type � : C++ type to use when SQL type is found ;
  • +
  • Button � Delete � : remove SQL type / C++ type mapping.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : when + QxEntityEditor is connected to database, all items (tables, columns, primary keys, + relationships, views, etc...) are displayed in this section. + By default, there is no item selected. + You can select all items to import with 1 click on the treeview root item. + It is also possible to select quickly items from a specific schema. + Once items to import are selected, the � Ok � button becomes enabled to run import + process. +


+ Note : all import parameters (database connection, import settings and relationships, SQL + type / C++ type mapping, etc...) are automatically saved when closing the import screen. + All import parameters are automatically re-loaded when opening the import screen. +

+ Other note : a QxEntityEditor video is available to show how + to import the MySQL database sample named sakila. +

+
+

Import from SQLite + database

+
+ A SQLite database structure can be imported in QxEntityEditor application via main menu : + Import >> Import from SQLite database : +

+ Import SQLite +

+ This import parameters screen is divided in several sections : +

+ -- Section Database connection : +
    +
  • Field � Database path � : SQLite database file path ;
  • +
  • Button � Connect to database � : if an error occurred, a warning message is + displayed, otherwise all database tables and columns are displayed in � Database items + to import to QxEntityEditor project � section (treeview).
  • +
+
+ -- Section Import settings : +
    +
  • Field � Namespace � : namespace used to group all imported + items in current project ;
  • +
  • Field � Delete all entities in the namespace before importing � : remove all + entities from above namespace before running import from database process ;
  • +
  • Field � Import tables/columns comment to entities/properties description � : + import tables and columns description defined in database ;
  • +
  • Field � Add boost::optional<T> decoration if a column definition allows NULL + value � : add automatically boost::optional + decoration to manage NULL value ;
  • +
  • Field � Import columns default value � : import default values defined in database + columns ;
  • +
  • Field � Organize diagram layout after import process � : run automatically the organize entities diagram feature after executing + import process.
  • +
+
+ -- Section Relationship import settings : +
    +
  • Field � Decoration � : default relationship C++ type decoration (for + relationships, QxOrm library recommends smart-pointer : boost::shared_ptr, + std::shared_ptr or QSharedPointer) ; +
  • +
  • Field � Collection � : if relationship is a list of (1-n and n-n), + then define C++ list type ;
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor provides a + default mapping SQL type / C++ type. + You can use this list to override default behaviour : +
    +
  • Column � SQL type � : SQL type to map. SQL type search is case insensitive, and is + applied on first characters (STARTS WITH behaviour) : for example, varchar + matches VARCHAR(255) ;
  • +
  • Column � C++ type � : C++ type to use when SQL type is found ;
  • +
  • Button � Delete � : remove SQL type / C++ type mapping.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : when + QxEntityEditor is connected to database, all items (tables, columns, primary keys, + relationships, views, etc...) are displayed in this section. + By default, there is no item selected. + You can select all items to import with 1 click on the treeview root item. + It is also possible to select quickly items from a specific schema. + Once items to import are selected, the � Ok � button becomes enabled to run import + process. +


+ Note : all import parameters (database connection, import settings and relationships, SQL + type / C++ type mapping, etc...) are automatically saved when closing the import screen. + All import parameters are automatically re-loaded when opening the import screen. +

+ Other note : a QxEntityEditor video is available to show how + to import the MySQL database sample named sakila. +

+
+

Import from database + using ODBC driver (Oracle, MS SQL Server, etc.)

+
+ QxEntityEditor application provides a generic database import using ODBC drivers : main menu + Import >> Import from database using ODBC driver. + This kind of import process requires a DSN (Data Source Name) defined on the environment. + Import by ODBC process is able to manage following databases : Oracle, Microsoft SQL Server, + SQLite, MySQL/MariaDB, PostgreSQL, etc... +

+ Import ODBC +

+ This import parameters screen is divided in several sections : +

+ -- Section Database connection : +
    +
  • Field � DSN or connection string � : DSN (Data Source + Name) defined on the environment to be able to connect to database using an ODBC + driver ;
  • +
  • Field � Login � : user name to connect to database (optional depending on DSN) ; +
  • +
  • Field � Password � : password to connect to database (optional depending on DSN) ; +
  • +
  • Field � Database type � : Generic type is able to connect to all databases + but with some limitations (no relationship, no composite key). + So you should select the real database type before connecting to database (Oracle, + Microsoft SQL Server, SQLite, MySQL/MariaDB, PostgreSQL) ;
  • +
  • Button � Connect to database � : if an error occurred, a warning message is + displayed, otherwise all database tables and columns are displayed in � Database items + to import to QxEntityEditor project � section (treeview).
  • +
+
+ -- Section Import settings : +
    +
  • Field � Namespace � : namespace used to group all imported + items in current project ;
  • +
  • Field � Delete all entities in the namespace before importing � : remove all + entities from above namespace before running import from database process ;
  • +
  • Field � Import tables/columns comment to entities/properties description � : + import tables and columns description defined in database ;
  • +
  • Field � Add boost::optional<T> decoration if a column definition allows NULL + value � : add automatically boost::optional + decoration to manage NULL value ;
  • +
  • Field � Import columns default value � : import default values defined in database + columns ;
  • +
  • Field � Organize diagram layout after import process � : run automatically the organize entities diagram feature after executing + import process.
  • +
+
+ -- Section Relationship import settings : +
    +
  • Field � Decoration � : default relationship C++ type decoration (for + relationships, QxOrm library recommends smart-pointer : boost::shared_ptr, + std::shared_ptr or QSharedPointer) ; +
  • +
  • Field � Collection � : if relationship is a list of (1-n and n-n), + then define C++ list type ;
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor provides a + default mapping SQL type / C++ type. + You can use this list to override default behaviour : +
    +
  • Column � SQL type � : SQL type to map. SQL type search is case insensitive, and is + applied on first characters (STARTS WITH behaviour) : for example, varchar + matches VARCHAR(255) ;
  • +
  • Column � C++ type � : C++ type to use when SQL type is found ;
  • +
  • Button � Delete � : remove SQL type / C++ type mapping.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : when + QxEntityEditor is connected to database, all items (tables, columns, primary keys, + relationships, views, etc...) are displayed in this section. + By default, there is no item selected. + You can select all items to import with 1 click on the treeview root item. + It is also possible to select quickly items from a specific schema. + Once items to import are selected, the � Ok � button becomes enabled to run import + process. +


+ Note : all import parameters (database connection, import settings and relationships, SQL + type / C++ type mapping, etc...) are automatically saved when closing the import screen. + All import parameters are automatically re-loaded when opening the import screen. +

+ Other note : a QxEntityEditor video is available to show how + to import the MySQL database sample named sakila. +

+
+
+ +

Export plugins

+
+ All export process in QxEntityEditor application are accessible via main menu Export : +

+ Export plugins +

+

Export to C++ + project

+
+ C++ export generates a full C++ project ready to be built (using qmake and/or + cmake) which contains all entities/properties/relationships/enumerations registered in + QxOrm context. + All QxOrm library features (persistence, serialization, introspection, etc...) are available for all items inside + generated C++ project. +

+

C++ export settings

+
+ C++ export parameters are accessible via main menu : Tools >> Export to C++ project + (settings). + Export parameters screen is displayed automatically when the first export is launched if no + setting is saved in *.qxee project. + When a C++ export process has already been executed, then export parameters screen is only + accessible via : Tools >> Export to C++ project (settings) : +

+ Export C++ +

+ This export parameters screen is divided in several sections : +

+ -- Section C++ export settings : +
    +
  • Field � C++ project location � : define where generated C++ project is located (output + directory). + You can define in this field a relative path to your *.qxee project file ;
  • +
  • Field � Relative path to QxOrm library � : if enabled, QxOrm library dependency + is managed using a relative path, otherwise it is managed using an absolute path. + You should define an environment variable in QxEntityEditor + application settings (for example : $$(QXORM_DIR)) instead of using this + option ;
  • +
  • Field � Generate a custom directory with custom files for each entity � : if + enabled, generated C++ project contains a custom file per entity. + By default, these custom files are empty and will never be removed or erased by another + export. + These custom files can be used for example to implement validation methods, or trigger functions.
  • +
  • Field � Generate all persistent classes using the PIMPL (Private Implementation) + idiom � : if enabled, all generated C++ persistent classes registered into QxOrm + context will use the C++ PIMPL pattern (or + d-pointer).
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : settings for export custom engine. +
    +
  • Field � Custom script file � : Javascript file location to customize C++ export process. + If empty, no customization is applied (default behaviour of export process). + You can define in this field a relative path to *.qxee project file, for example + ./my_script.js if my_script.js file is in the same directory as + *.qxee file ; +
  • +
  • Button � Debug custom Javascript file � : if a Javascript file is defined, a + click on this button will enable Javascript debugging + mode for the next C++ export process. + Instead of using this button, you can also enable Javascript + debugging mode pressing SHIFT keyboard shortcut when starting an export + process.
  • +
+
+ -- Section C++ template files : this section defines entities C++ source code + for Header *.h and Source *.cpp files. + Export engine is based on placeholders (@@ACTION@@ format) to replace code by + calculated value. + Placeholder is the most important part to understand how Javascript customization engine works. + Please note that you can define your own custom placeholder + with @@CUSTOM_ prefix, for example : @@CUSTOM_MY_ACTION@@. +
    +
  • Option � No inheritance � : if enabled (default option), C++ class doesn't have + any inheritance (no base class) ;
  • +
  • Option � qx::IxPersistable � : if enabled, each generated C++ class inherit + from qx::IxPersistable interface (which provides a + common interface for persistence actions to database). + Please note that this option increases compilation times to build your C++ project ; +
  • +
  • Option � qx::IxPersistable + QObject � : if enabled, each generated C++ class + inherit from qx::IxPersistable interface and from + QObject Qt class. + Please note that this option increases compilation times to build your C++ project ; +
  • +
  • Option � Custom � : if enabled, you can provide your own C++ template files + (you should begin to copy/past Header *.h and Source *.cpp + from another option to get a list of placeholders to use).
  • +
+
+
+

Overview of generated C++ project

+
+ Output directory of generated C++ project looks like : +

+ Export C++ output +

+
    +
  • bin � folder is empty by default, and will contain output binary (shared + library *.dll on Windows, *.so on Linux, etc...) ;
  • +
  • build � folder is empty by default, it can be used to manage CMake configuration files ;
  • +
  • custom � folder is filled if the � Generate a custom directory with custom + files for each entity � option is enabled. + These custom files can be used for example to implement validation methods, or trigger functions ;
  • +
  • include � folder contains all classes definitions for entities and + enumerations ;
  • +
  • src � folder contains all classes implementations for entities and + enumerations ;
  • +
  • CMakeLists.txt � file can be used to build project with CMake ;
  • +
  • *.gen.pri � and � *.gen.pro � files can be used to build project with + qmake ; +
  • +
+
+
+

Build generated C++ project (using qmake or + cmake)

+
+ Generated C++ project can be built using CMake or qmake.
+ QxOrm library provides some documented compilation options + in QxOrm.pri (and QxOrm.cmake) configuration files (you can keep default compilation + options).
+ QxOrm library user manual has a topic about how to build a + QxOrm project.
+ A tutorial is also available to explain how to setup an + development environment on Windows with MSVC.
+ Once C++ project is built, then output binary is available in the � bin � directory of + exported project (*.dll on Windows, *.so on Linux, etc...). +

+
+

Example : how to use generated C++ project

+
+ The ./samples/ directory of QxEntityEditor package provides a sample project : + qxBlog.qxee. + This qxBlog.qxee project can be opened in QxEntityEditor application without any valid + license key. + Once C++ project is exported by QxEntityEditor, you can build the project to get a + qxBlog.dll shared library (or qxBlog.so on Linux). + This shared library registers all entities, properties and enumerations in QxOrm context : so all QxOrm library features are available. +

+ The ./samples/ directory of QxEntityEditor package also provides a C++ sample project + which depends on qxBlog.qxee exported project : qxBlogExec.zip. + Once qxBlogExec.zip is unzipped, the readme.txt file in the root folder + contains instructions to build this sample project : +

+
+
+--------------------------------------------
+-- To build qxBlogExec project with qmake --
+--------------------------------------------
+
+1- Export the 'qxBlog.qxee' project as a C++ project with QxEntityEditor and build it
+2- Open the 'qxBlogExec.pro' file
+3- Replace '$$(QXORM_DIR)' by your QxOrm library installation path
+4- Replace 'C:/Temp/qxee/cpp/' by the path where you have exported the 'qxBlog.qxee' project as a C++ project
+5- run command line : qmake
+6- run command line : make debug (or make release)
+
+
+--------------------------------------------
+-- To build qxBlogExec project with CMake --
+--------------------------------------------
+
+1- Export the 'qxBlog.qxee' project as a C++ project with QxEntityEditor and build it
+2- Open the 'CMakeLists.txt' file
+3- Replace '$ENV{QXORM_DIR}' by your QxOrm library installation path
+4- Replace 'C:/Temp/qxee/cpp/' by the path where you have exported the 'qxBlog.qxee' project as a C++ project
+5- run cmake or cmake-gui to configure and generate your make files
+
+
+

+ Here is the commented content of main() function (close to qxBlog tutorial) : +

+
+
+int main(int argc, char * argv[])
+{
+   // Qt application
+   QCoreApplication app(argc, argv);
+   QFile::remove("./qxBlog.sqlite");
+
+   // Parameters to connect to database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+   // Only for debug purpose : assert if invalid offset detected fetching a relation
+   qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true);
+
+   // !!! TO CREATE TABLES, PLEASE USE THE C++ DDL SQL EXPORT PLUGIN OF QXENTITYEDITOR !!!
+   // Create all tables in database (you should not use 'qx::dao::create_table<T>()' function in a production software, use it just for prototypes or samples)
+   QSqlError daoError = qx::dao::create_table<author>();
+   daoError = qx::dao::create_table<comment>();
+   daoError = qx::dao::create_table<category>();
+   daoError = qx::dao::create_table<blog>();
+
+   // Create a list of 3 author
+   author_ptr author_1; author_1.reset(new author());
+   author_ptr author_2; author_2.reset(new author());
+   author_ptr author_3; author_3.reset(new author());
+
+   author_1->setlastname("author_1");
+   author_1->setsex(sex::male);
+   author_1->setbirthdate(QDateTime::currentDateTime());
+   author_2->setlastname("author_2");
+   author_2->setsex(sex::female);
+   author_2->setbirthdate(QDateTime::currentDateTime());
+   author_3->setlastname("author_3");
+   author_3->setsex(sex::female);
+   author_3->setbirthdate(QDateTime::currentDateTime());
+
+   list_of_author authorX;
+   authorX.insert(1, author_1);
+   authorX.insert(2, author_2);
+   authorX.insert(3, author_3);
+
+   // Insert list of 3 author into database
+   daoError = qx::dao::insert(authorX);
+   qAssert(qx::dao::count<author>() == 3);
+
+   // Clone author n�2 : 'author_id_2'
+   author_ptr author_clone = qx::clone(* author_2);
+   qAssert(author_clone->getauthor_id() == author_2->getauthor_id());
+   qAssert(author_clone->getsex() == sex::female);
+
+   // Create a query to fetch only female author : 'author_id_2' and 'author_id_3'
+   qx::QxSqlQuery query("WHERE t_author.sex = :sex");
+   query.bind(":sex", sex::female);
+
+   list_of_author list_of_female_author;
+   daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+   qAssert(list_of_female_author.count() == 2);
+
+   // Dump list of female author (xml serialization)
+   qx::dump(list_of_female_author);
+
+   // Create 3 categories
+   category_ptr category_1 = category_ptr(new category("cat_1"));
+   category_ptr category_2 = category_ptr(new category("cat_2"));
+   category_ptr category_3 = category_ptr(new category("cat_3"));
+
+   category_1->setname("category_1"); category_1->setdescription("desc_1");
+   category_2->setname("category_2"); category_2->setdescription("desc_2");
+   category_3->setname("category_3"); category_3->setdescription("desc_3");
+
+   { // Create a scope to destroy temporary connexion to database
+
+   // Open a transaction to database
+   QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
+   bool bCommit = db.transaction();
+
+   // Insert 3 categories into database, use 'db' parameter for the transaction
+   daoError = qx::dao::insert(category_1, (& db));    bCommit = (bCommit && ! daoError.isValid());
+   daoError = qx::dao::insert(category_2, (& db));    bCommit = (bCommit && ! daoError.isValid());
+   daoError = qx::dao::insert(category_3, (& db));    bCommit = (bCommit && ! daoError.isValid());
+
+   qAssert(bCommit);
+   qAssert(category_1->getcategory_id() != "");
+   qAssert(category_2->getcategory_id() != "");
+   qAssert(category_3->getcategory_id() != "");
+
+   // Terminate transaction => commit or rollback if there is error
+   if (bCommit) { db.commit(); }
+   else { db.rollback(); }
+
+   } // End of scope : 'db' is destroyed
+
+   // Create a blog with the class name (factory)
+   boost::any blog_any = qx::create("blog");
+   blog_ptr blog_1;
+   try { blog_1 = boost::any_cast<blog_ptr>(blog_any); }
+   catch (...) { blog_1.reset(new blog()); }
+   blog_1->settext("blog_text_1");
+   blog_1->settitle("blog_title_1");
+   blog_1->setauthor(author_1);
+
+   // Insert 'blog_1' into database with 'save()' method
+   daoError = qx::dao::save(blog_1);
+
+   // Modify 'blog_1' properties and save into database
+   blog_1->settext("update blog_text_1");
+   blog_1->setauthor(author_2);
+   daoError = qx::dao::save(blog_1);
+
+   // Add 2 comments to 'blog_1'
+   comment_ptr comment_1; comment_1.reset(new comment());
+   comment_ptr comment_2; comment_2.reset(new comment());
+
+   comment_1->settext("comment_1 text");
+   comment_1->setblog_id(blog_1);
+   comment_2->settext("comment_2 text");
+   comment_2->setblog_id(blog_1);
+
+   daoError = qx::dao::insert(comment_1);
+   daoError = qx::dao::insert(comment_2);
+   qAssert(qx::dao::count<comment>() == 2);
+
+   // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog'
+   blog::type_list_of_category lst_category;
+   lst_category.insert(category_1->getcategory_id(), category_1);
+   lst_category.insert(category_3->getcategory_id(), category_3);
+   blog_1->setlist_of_category(lst_category);
+   daoError = qx::dao::save_with_relation("list_of_category", blog_1);
+
+   // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category'
+   blog_ptr blog_tmp; blog_tmp.reset(new blog());
+   blog_tmp->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp);
+
+   qAssert(blog_tmp->list_of_comment().count() == 2);
+   qAssert(blog_tmp->list_of_category().count() == 2);
+   qAssert(blog_tmp->gettext() == "update blog_text_1");
+   qAssert(blog_tmp->getauthor() && blog_tmp->getauthor()->getauthor_id() == author_2->getauthor_id());
+
+   // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships)
+   blog_tmp.reset(new blog());
+   blog_tmp->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp);
+
+   qAssert(blog_tmp->list_of_comment().count() == 2);
+   qAssert(blog_tmp->list_of_category().count() == 2);
+   qAssert(blog_tmp->gettext() == "update blog_text_1");
+   qAssert(blog_tmp->getauthor() && blog_tmp->getauthor()->getauthor_id() == author_2->getauthor_id());
+
+   // Dump 'blog_tmp' result from database (xml serialization)
+   qx::dump(blog_tmp);
+
+   // Check qx::dao::save_with_relation_recursive() function
+   daoError = qx::dao::save_with_relation_recursive(blog_tmp);
+   qAssert(! daoError.isValid());
+   daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only);
+   qAssert(! daoError.isValid());
+
+   // Call 'age()' method with class name and method name (reflexion)
+   //qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1);
+   //qAssert(bInvokeOk);
+
+   // Test 'isDirty()' method
+   qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(new blog());
+   blog_isdirty->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id(blog_isdirty);
+   qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());
+
+   blog_isdirty->settext("blog property 'text' modified => blog is dirty !!!");
+   QStringList lstDiff; bool bDirty = blog_isdirty.isDirty(lstDiff);
+   qAssert(bDirty && (lstDiff.count() == 1) && (lstDiff.at(0) == "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<author_ptr> > type_lst_author_test_is_dirty;
+   type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+   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->setlastname("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->setfirstname("firstname changed");
+   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_text' of blog
+   QStringList lstColumns = QStringList() << "text";
+   QList<blog_ptr> lst_blog_with_only_text;
+   daoError = qx::dao::fetch_all(lst_blog_with_only_text, NULL, lstColumns);
+   qAssert(! daoError.isValid() && (lst_blog_with_only_text.size() > 0));
+   if ((lst_blog_with_only_text.size() > 0) && (lst_blog_with_only_text[0].get() != NULL))
+   { qAssert(lst_blog_with_only_text[0]->gettitle().isEmpty()); }
+   qx::dump(lst_blog_with_only_text);
+
+   // Dump all registered classes into QxOrm context (introspection engine)
+   qx::QxClassX::dumpAllClasses();
+
+   // Call a custom SQL query or a stored procedure
+   qx_query testStoredProc("SELECT * FROM t_author");
+   daoError = qx::dao::call_query(testStoredProc);
+   qAssert(! daoError.isValid());
+   testStoredProc.dumpSqlResult();
+
+   // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+   qx_query testStoredProcBis("SELECT * FROM t_author");
+   authorX.clear();
+   daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+   qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+   qx::dump(authorX);
+
+   // Call a custom SQL query or a stored procedure and fetch automatically properties
+   qx_query testStoredProcThird("SELECT name, category_id FROM t_category");
+   category_ptr category_tmp = category_ptr(new category());
+   daoError = qx::dao::execute_query(testStoredProcThird, category_tmp);
+   qAssert(! daoError.isValid()); qAssert(category_tmp->getcategory_id() != "");
+   qx::dump(category_tmp);
+
+   return 0;
+}
+
+
+

+
+
+

Export to C++ model/view project

+
+ QxOrm library provides QxModelView module. + A documentation about QxModelView module is available in the QxOrm library user manual. + QxModelView module + provides a way to work with Qt + model/view engine with all classes registered in QxOrm context : +
    +
  • QML : each property defined in QxOrm context is + exposed to QML engine : QxModelView module makes easier integration between QML and + databases ;
  • +
  • Qt widgets : QTableView or QListView + for example to display/modify a database table content.
  • +
+
+ QxEntityEditor application is able to generate a full C++ model/view project ready to be built : + so all entities and their relationships are accessible in QML views. +

+

Export settings

+
+ C++ model/view export parameters are accessible via main menu : Tools >> Export to + C++ model/view project (settings). + Export parameters screen is displayed automatically when the first export is launched if no + setting is saved in *.qxee project. + When a C++ model/view export process has already been executed, then export parameters screen + is only accessible via : Tools >> Export to C++ model/view project (settings) : +

+ Export C++ model/view +

+ This export parameters screen is divided in several sections : +

+ -- Section C++ model/view export settings : +
    +
  • Field � C++ model/view project location � : output directory which contains C++ model/view project files. + You can define in this field a relative path to your *.qxee project file ;
  • +
  • Field � C++ entities project location � : read-only, displays the C++ project location (entities registered in QxOrm + context) whose depends C++ model/view project ;
  • +
  • Field � Namespace for model/view � : namespace used to group all C++ model/view + classes (these classes implement qx::IxModel interface) ;
  • +
  • Field � Generate custom files � : if enabled, generated C++ project contains a + custom file per entity. + By default, these custom files are empty and will never be removed or erased by another + export.
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : settings for export custom engine. +
    +
  • Field � Custom script file � : Javascript file location to customize C++ export process. + If empty, no customization is applied (default behaviour of export process). + You can define in this field a relative path to *.qxee project file, for example + ./my_script.js if my_script.js file is in the same directory as + *.qxee file ; +
  • +
  • Button � Debug custom Javascript file � : if a Javascript file is defined, a + click on this button will enable Javascript debugging + mode for the next C++ export process. + Instead of using this button, you can also enable Javascript + debugging mode pressing SHIFT keyboard shortcut when starting an export + process.
  • +
+
+ -- Section C++ model/view template files : this section defines model/view C++ + source code for Header *.h and Source *.cpp files. + Export engine is based on placeholders (@@ACTION@@ format) to replace code by + calculated value. + Placeholder is the most important part to understand how Javascript customization engine works. + Please note that you can define your own custom placeholder + with @@CUSTOM_ prefix, for example : @@CUSTOM_MY_ACTION@@. + +
+
+

Overview of generated project

+
+ Output directory of generated C++ model/view project looks like : +

+ Export C++ model/view output +

+
    +
  • bin � folder is empty by default, and will contain output binary (shared + library *.dll on Windows, *.so on Linux, etc...) ;
  • +
  • build � folder is empty by default, it can be used to manage CMake configuration files ;
  • +
  • custom � folder is filled if the � Generate custom files � + option is enabled ;
  • +
  • include � folder contains all models definitions for entities and their + relationships ;
  • +
  • src � folder contains all models implementations for entities and their + relationships ;
  • +
  • CMakeLists.txt � file can be used to build model/view project with CMake ;
  • +
  • *.gen.pri � and � *.gen.pro � files can be used to build model/view + project with qmake ;
  • +
+
+
+
+

Export + to C++ services project

+
+ QxOrm library provides QxService module. + A documentation about QxService module is available in QxOrm + library user manual. + QxService module of QxOrm + library provides a way to create quickly a powerful C++ applications server (based on + services with request from client and response from server). + A tutorial is available on QxOrm website to explain how to work + with QxService module. +

+ QxEntityEditor application is able to generate a full C++ services project ready to be built (a + C++ project to manage client layer and a C++ project to publish services on server side) : so + all entities and their relationships can be transfered over network (client/server application). +

+

Export settings

+
+ C++ services export parameters are accessible via main menu : Tools >> Export to C++ + services project (settings). + Export parameters screen is displayed automatically when the first export is launched if no + setting is saved in *.qxee project. + When a C++ services export process has already been executed, then export parameters screen + is only accessible via : Tools >> Export to C++ services project (settings) : +

+ Export C++ services +

+ This export parameters screen is divided in several sections : +

+ -- Section C++ services export settings : +
    +
  • Field � C++ services project location � : output directory which contains all C++ services project files. + You can define in this field a relative path to your *.qxee project file ;
  • +
  • Field � C++ entities project location � : read-only, displays the C++ project location (entities registered in QxOrm + context) whose depends C++ services project ;
  • +
  • Field � Namespace for services � : namespace used to group all C++ services + classes (these classes provide a way to transfer + entities over network, client layer and server layer) ;
  • +
  • Field � Generate custom files � : if enabled, generated C++ project contains a + custom file per entity. + By default, these custom files are empty and will never be removed or erased by another + export. + These custom files can be used for example to implement and publish new services ;
  • +
  • Field � Generate server application � : if enabled, a sample C++ applications server + project is generated and is able to load and publish services on server side + based on plugins ;
  • +
  • Field � Server application location � : if � Generate server application + � option is enabled, then define output directory of sample C++ applications server + project.
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : settings for export custom engine. +
    +
  • Field � Custom script file � : Javascript file location to customize C++ export process. + If empty, no customization is applied (default behaviour of export process). + You can define in this field a relative path to *.qxee project file, for example + ./my_script.js if my_script.js file is in the same directory as + *.qxee file ; +
  • +
  • Button � Debug custom Javascript file � : if a Javascript file is defined, a + click on this button will enable Javascript debugging + mode for the next C++ export process. + Instead of using this button, you can also enable Javascript + debugging mode pressing SHIFT keyboard shortcut when starting an export + process.
  • +
+
+ -- Section C++ services template files : this section defines services C++ + source code for Header *.h and Source *.cpp files (client and + server). + Export engine is based on placeholders (@@ACTION@@ format) to replace code by + calculated value. + Placeholder is the most important part to understand how Javascript customization engine works. + Please note that you can define your own custom placeholder + with @@CUSTOM_ prefix, for example : @@CUSTOM_MY_ACTION@@. +
    +
  • Option � Default � : if enabled (default option), generate default services + (client layer and server layer) : entities and their relationships can be transfered + over network and CRUD operations on database are supported ;
  • +
  • Option � Custom � : if enabled, you can provide your own C++ services template + files (you should begin to copy/past Header *.h and Source + *.cpp from another option to get a list of placeholders to use). +
  • +
+
+
+

Overview of generated project

+
+ Output directory of generated C++ services project (client and server) looks like : +

+ Export C++ services output +

+
    +
  • bin � folder is empty by default, and will contain output client and server + binaries (shared library *.dll on Windows, *.so on Linux, etc...) ;
  • +
  • build � folder is empty by default, it can be used to manage CMake configuration files ;
  • +
  • client � folder contains qmake and CMake + files to build project (client layer) ;
  • +
  • custom � folder is filled if the � Generate custom files � + option is enabled ;
  • +
  • include � folder contains all services definitions for entities and their + relationships ;
  • +
  • server � folder contains qmake and CMake + files to build project (server layer) ;
  • +
  • src � folder contains all services implementations for entities and their + relationships ;
  • +
  • CMakeLists.txt � file can be used to build services project (client and + server) with CMake ;
  • +
  • *.gen.pri � and � *.gen.pro � files can be used to build services + project (client and server) with qmake ;
  • +
  • *.gen.json � file is used by the server project to build a plugin which can + be loaded by the applications + server to publish services.
  • +
+
+
+

Generic application server to provide + services

+
+ If � Generate server + application � option is enabled, then C++ services export process generates + also a generic applications server. + This sample applications server is able to publish services loading plugins. + Like all other C++ projects generated by QxEntityEditor, the generic applications server can + be built with qmake and + CMake. + Output directory of the generic applications server project looks like : +

+ Export C++ services server app output +

+ Once project is built, an executable is available in the � bin � directory. + Open the executable will launch following window : +

+ Export C++ services server app +

+ This screen is divided in several sections : +

+ -- Section Plugins services : +
    +
  • Field � Plugins path � : required to define where to find services plugins. + These plugins are built using C++ + services server project. + Once loaded, all plugins publish their services which can be called by clients + applications. + If no plugin loaded after selecting the plugins path, then it is possible to define QT_DEBUG_PLUGINS environment variable to log some loading + errors and help you to understand why plugins are not loaded (generally, a plugin + dependency not found).
  • +
+
+ -- Section Database connection parameters : +
    +
  • This section contains all required parameters to initialize a database connection used + by services (see qx::QxSqlDatabase class for + more details).
  • +
+
+ -- Section Server parameters : +
    +
  • Field � Port number � : define port number opened by the applications server to + publish services. + Clients applications have to connect to this port number to send requests to server ; +
  • +
  • Field � Thread count � : number of threads used by server to manage client + requests ;
  • +
  • Field � Serialization type � : serialization type used to send responses from + server to client ;
  • +
  • Field � Compress data � : if enabled, all responses from server to client are + compressed ;
  • +
  • Field � Encrypt data � : if enabled, all responses from server to client are + encrypted (possibility to define your own encryption key) ;
  • +
  • Button � Start server � : button to start and stop server.
  • +
+
+ -- Section Log last client-server reply-request transaction : +
    +
  • Display in XML or JSON format all details about the last client-server transaction + managed by the applications server.
  • +
+
+ -- Section Log last server error : +
    +
  • If an error occurred on applications server, it is automatically logged in this + section.
  • +
+
+
+
+

Export SQL DDL + database schema

+
+ QxEntityEditor application is able to generate a database schema (structure) in a DDL SQL + format. + QxEntityEditor application support most commonly used databases : SQLite, MySQL, MariaDB, + PostgreSQL, Oracle and Microsoft SQL Server. + Generated DDL SQL script can be imported in database to create automatically all tables, + columns, primary keys, relationships, index, etc... + DDL SQL parameters are accessible via main menu : Tools >> Export to DDL SQL script + file (settings) : +

+ Export SQL DDL +

+ This export parameters screen is divided in several sections : +

+ -- Section DDL export settings : +
    +
  • Field � File location � : output directory which will contain the generated DDL + SQL script ;
  • +
  • Field � Database type � : select DDL SQL script format (SQLite, MySQL, MariaDB, + PostgreSQL, Oracle or Microsoft SQL Server) ;
  • +
  • Field � Relationships � : if enabled, then foreign keys are created to manage + relationships between entities ;
  • +
  • Field � Schema � : define DDL export type : 1 script which contains all + *.qxee items, or 1 script per *.qxee project + version (database schema evolution). +
  • +
+
+ -- Section Mapping C++ type to database SQL type : +
    +
  • List to map C++ type (defined in all *.qxee project properties) to SQL type.
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the export + process : settings for export custom engine. +
    +
  • Field � Custom script file � : Javascript file location to customize export process. + If empty, no customization is applied (default behaviour of export process). + You can define in this field a relative path to *.qxee project file, for example + ./my_script.js if my_script.js file is in the same directory as + *.qxee file ; +
  • +
  • Button � Debug custom Javascript file � : if a Javascript file is defined, a click + on this button will enable Javascript debugging mode for + the next export process. + Instead of using this button, you can also enable Javascript + debugging mode pressing SHIFT keyboard shortcut when starting an export + process.
  • +
+
+
+

Print entities + diagram

+
+ QxEntityEditor application is able to print entities diagram to PNG and/or PDF format. + Print parameters are accessible via main menu : Tools >> Print the entities diagram + (settings) : +

+ Export print PNG/PDF +

+
+

Export to a directory linked to a Source Control + manager (Git, Perforce, CVS, etc.)

+
+ A QxEntityEditor project (*.qxee file) can be managed by a developers team : the source + code of a QxEntityEditor project can be exported/imported (manually or using command line) with + QxEESourceControlExport and QxEESourceControlImport plugins.
+
+ Associated with a Source Control manager (Git, Perforce, CVS, etc.), these 2 plugins provide : +
    +
  • several people can work simultaneously on the same project ;
  • +
  • a project can easily be versioned in the source code manager ;
  • +
  • each element of a project can be compared (difference between 2 versions of the same + entity for example).
  • +
+ Here is a use case of QxEESourceControlExport and QxEESourceControlImport plugins, with 2 + developers named 'dev A' and 'dev B' (this example can be extended to X developers) : +
    +
  • dev A and dev B work on a same QxEntityEditor project (*.qxee file) ;
  • +
  • dev A creates/changes/deletes some entities in QxEntityEditor application ;
  • +
  • dev B creates/changes/deletes other entities in QxEntityEditor application ;
  • +
  • dev A and dev B export the *.qxee project file with the QxEESourceControlExport plugin + (manually or using command line) ;
  • +
  • once the project is exported to a directory, dev A and dev B check-in (or submit) + all generated JSON files to the Source Control manager (Git, Perforce, CVS, etc.) on their + own branch ;
  • +
  • from the Source Control manager, dev A and dev B merge (or integrate) their own + branch to the development branch DEV (or MAIN or MASTER or LATEST); Note : even if + there are conflicts to resolve, they will be easy to correct because the JSON format is + easily readable ;
  • +
  • dev A and dev B can now get latest files from Source Control manager from DEV branch (or + MAIN or MASTER or LATEST) : these JSON files contain both modifications from dev A and + dev B ;
  • +
  • dev A and dev B can import these JSON files into the QxEntityEditor application using the + import plugin QxEESourceControlImport + (manually or using command line).
  • +
+ The export plugin settings are accessible from the main menu Tools >> Export to Source + Control repository (Git, Perforce, CVS, etc.) as JSON files (settings) : +

+ Source Control export plugin settings +

+ The parameter to enter corresponds to the directory in which the JSON files will be + generated.
+ Each *.qxee project item (entities, properties, relationships, comments, etc.) is + exported to a specific JSON file.
+ The directory where the JSON files are exported has the following structure : +

+ Source Control output directory +

+ Note : it is possible to export a project from command line without starting the + QxEntityEditor application UI.
+ Command line example :
+
+ +
QxEntityEditor --no_gui --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlExport --QxEESourceControlExport_path="<path_to_your_export_output_directory>"
+
+
+

+
+

Export project + to XML or JSON format

+
+ + Note : + to work with a source code manager (Git, Perforce, CVS, etc.), it is recommended to use QxEESourceControlExport and QxEESourceControlImport plugins (instead of + creating a single file).
+
+ QxEntityEditor application can export a *.qxee project to XML or JSON format. + XML/JSON export parameters are accessible via main menu : Tools >> Export to XML or + JSON file (settings) : +

+ Export XML/JSON +

+ Note : a XML file cannot be used to import items in a *.qxee project. + On the other hand, a JSON file can be used to import items in a *.qxee project using the + import plugin : Import project based on JSON file. +

+
+
+ +

Javascript engine to + customize export

+
+ QxEntityEditor application provides a powerful export customization engine. + This engine is based on Javascript language to write scripts to customize QxEntityEditor exports. + These Javascript scripts can + access to all parameters and items of a *.qxee project, and a QxEntityEditor native debugger can be enabled to help you to develop + and fix your scripts. + It is also possible to write your own files during export + process. +

+ Note : the ./samples/ directory of QxEntityEditor package provides 2 documented + samples scripts : custom_script.js and q_property.js. +

+

Architecture + and workflow of Javascript engine

+
+ All QxEntityEditor export plugins provide following settings : Custom script (Javascript file) to change the + default behaviour of the export process. + This is where you can define a Javascript file to use to customize your exports. + Export engine is based on placeholders (@@ACTION@@ format) to replace code by + calculated value. + Placeholder is the most important part to understand how Javascript + customization engine works. + Please note that you can define your own custom placeholder + with @@CUSTOM_ prefix, for example : @@CUSTOM_MY_ACTION@@. + During an export process, QxEntityEditor application iterates over all entities and enumerations + defined in *.qxee project. + Each time a placeholder is read by export engine (@@ACTION@@ format), the Javascript script is + called with all input parameters required to customize output files. +

+ Here is a minimal Javascript file example. + This script does nothing, it just shows what is a valid QxEntityEditor Javascript file : + +
+
+
({
+
+// Here is the entry point of the QxEntityEditor javascript engine
+// This function is called for each placeholder defined in the C++ template section
+customProcess : function(params)
+{
+   try
+   {
+      // quit with 'params[0]' means : doesn't change the default export behaviour
+      return params[0];
+   }
+   catch (err)
+   { return ("[CustomScriptError] an unexpected error occurred : " + err); }
+}
+
+});
+
+

+

Input + parameters of Javascript engine

+
+ customProcess() function input parameter (named params) is an array which + contain a list of values (this is the call context of the script). + Here is a sample function which can be used in your own scripts to list and to give meaning + to all input values : +

+
+
function printParams(params)
+{
+   var log = "";
+   log = log + "\n - default_value = " + params[0];
+   log = log + "\n - project_name = " + params[1];
+   log = log + "\n - project_file = " + params[2];
+   log = log + "\n - plugin_name = " + params[3];
+   log = log + "\n - current_file = " + params[4];
+   log = log + "\n - action (or placeholder) = " + params[5];
+   log = log + "\n - entity_name = " + params[6];
+   log = log + "\n - entity_table_name = " + params[7];
+   log = log + "\n - property_name = " + params[8];
+   log = log + "\n - property_type = " + params[9];
+   log = log + "\n - property_column_name = " + params[10];
+   log = log + "\n - property_is_primary_key = " + params[11];
+   log = log + "\n - enumeration_name = " + params[12];
+   log = log + "\n - entity_id = " + params[13];
+   log = log + "\n - property_id = " + params[14];
+   log = log + "\n - enumeration_id = " + params[15];
+   log = log + "\n - output_location = " + params[16];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return log;
+}
+
+

+
+
+

Available + functions in Javascript

+
+ QxEntityEditor export customization engine support all Javascript language + features (ECMAScript 5). + QxEntityEditor application provides also a global instance of object named helper + which can be used in your own scripts to access to more features. + We will list in this chapter the most commonly used features to customize output files. +

+

Get + entity details

+
+ Here is an example to get all current entity parameters, + helper.getEntityDetails(entity_id) : +

+
+
var entity_id = params[13];
+printEntityDetails(entity_id);
+
+//...
+
+function printEntityDetails(entity_id)
+{
+   var details = helper.getEntityDetails(entity_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - entity_id = " + details[0];
+   log = log + "\n - entity_key = " + details[1];
+   log = log + "\n - entity_name = " + details[2];
+   log = log + "\n - entity_namespace = " + details[3];
+   log = log + "\n - entity_tablename = " + details[4];
+   log = log + "\n - entity_description = " + details[5];
+   log = log + "\n - entity_is_read_only = " + details[6];
+   log = log + "\n - entity_is_abstract = " + details[7];
+   log = log + "\n - entity_version = " + details[8];
+   log = log + "\n - entity_primary_key_property_id = " + details[9];
+   log = log + "\n - entity_list_of_properties_id = " + details[10];
+   log = log + "\n - entity_has_triggers = " + details[11];
+   log = log + "\n - entity_trigger_on_before_fetch = " + details[12];
+   log = log + "\n - entity_trigger_on_after_fetch = " + details[13];
+   log = log + "\n - entity_trigger_on_before_insert = " + details[14];
+   log = log + "\n - entity_trigger_on_after_insert = " + details[15];
+   log = log + "\n - entity_trigger_on_before_update = " + details[16];
+   log = log + "\n - entity_trigger_on_after_update = " + details[17];
+   log = log + "\n - entity_trigger_on_before_delete = " + details[18];
+   log = log + "\n - entity_trigger_on_after_delete = " + details[19];
+   log = log + "\n - entity_parent_id = " + details[20];
+   log = log + "\n - entity_soft_delete_column = " + details[21];
+   log = log + "\n - entity_validator_method = " + details[22];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Iterate over list of properties of an + entity

+
+ Here is an example to iterate over all properties defined in current entity : +

+
+
var entity_id = params[13];
+var entity_details = helper.getEntityDetails(entity_id);
+var entity_list_of_properties_id = ((entity_details.length > 0) ? entity_details[10] : "");
+var entity_list_of_properties_array = entity_list_of_properties_id.split("|");
+for (var idx = 0; idx < entity_list_of_properties_array.length; idx++)
+{
+   var property_id = entity_list_of_properties_array[idx];
+   var property_details = helper.getPropertyDetails(property_id);
+   // ...
+}
+
+

+
+

Get + property details

+
+ Here is an example to get all property parameters, + helper.getPropertyDetails(property_id) : +

+
+
function printPropertyDetails(property_id)
+{
+   var details = helper.getPropertyDetails(property_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - property_id = " + details[0];
+   log = log + "\n - property_key = " + details[1];
+   log = log + "\n - property_name = " + details[2];
+   log = log + "\n - property_column_name = " + details[3];
+   log = log + "\n - property_description = " + details[4];
+   log = log + "\n - property_type = " + details[5];
+   log = log + "\n - property_version = " + details[6];
+   log = log + "\n - property_entity_id = " + details[7];
+   log = log + "\n - property_is_read_only = " + details[8];
+   log = log + "\n - property_is_primary_key = " + details[9];
+   log = log + "\n - property_is_serializable = " + details[10];
+   log = log + "\n - property_is_transient = " + details[11];
+   log = log + "\n - property_is_obsolete = " + details[12];
+   log = log + "\n - property_is_index = " + details[13];
+   log = log + "\n - property_is_unique = " + details[14];
+   log = log + "\n - property_allow_null = " + details[15];
+   log = log + "\n - property_order_level = " + details[16];
+   log = log + "\n - property_default_value = " + details[17];
+   log = log + "\n - property_format = " + details[18];
+   log = log + "\n - property_force_sql_type = " + details[19];
+   log = log + "\n - property_force_sql_alias = " + details[20];
+   log = log + "\n - property_min_value = " + details[21];
+   log = log + "\n - property_max_value = " + details[22];
+   log = log + "\n - property_min_length = " + details[23];
+   log = log + "\n - property_max_length = " + details[24];
+   log = log + "\n - property_reg_exp = " + details[25];
+   log = log + "\n - property_accessibility = " + details[26];
+   log = log + "\n - property_is_relationship = " + details[27];
+   log = log + "\n - property_relation_type = " + details[28];
+   log = log + "\n - property_relation_entity_target_id = " + details[29];
+   log = log + "\n - property_relation_inverse_property_id = " + details[30];
+   log = log + "\n - property_relation_foreign_key = " + details[31];
+   log = log + "\n - property_relation_foreign_key_owner = " + details[32];
+   log = log + "\n - property_relation_extra_table = " + details[33];
+   log = log + "\n - property_relation_type_desc = " + details[34];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Get + enumeration details

+
+ Here is an example to get all current enumeration parameters, + helper.getEnumerationDetails(enumeration_id) : +

+
+
var enumeration_id = params[15];
+printEnumerationDetails(enumeration_id);
+
+//...
+
+function printEnumerationDetails(enumeration_id)
+{
+   var details = helper.getEnumerationDetails(enumeration_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - enumeration_id = " + details[0];
+   log = log + "\n - enumeration_key = " + details[1];
+   log = log + "\n - enumeration_name = " + details[2];
+   log = log + "\n - enumeration_namespace = " + details[3];
+   log = log + "\n - enumeration_description = " + details[4];
+   log = log + "\n - enumeration_version = " + details[5];
+   log = log + "\n - enumeration_use_qt_enum_macro = " + details[6];
+   log = log + "\n - enumeration_list_of_keys = " + details[7];
+   log = log + "\n - enumeration_list_of_values = " + details[8];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Get + meta-data of entity/property/enumeration

+
+ QxEntityEditor application provides a feature to define some meta-data linked to entity, property or enumeration. + These meta-data can be used for example to define extra-parameters not provided by default by + QxEntityEditor application. + These meta-data are available in generated C++ code (introspection engine of QxOrm library), and are also + available in QxEntityEditor Javascript engine. + Here is an example to get meta-data values in Javascript : +

+
+
var entity_id = params[13];
+var entity_meta_data = helper.getEntityMetaData(entity_id, "MY_ENTITY_META_DATA_KEY");
+
+// ...
+
+var property_meta_data = helper.getPropertyMetaData(property_id, "MY_PROPERTY_META_DATA_KEY");
+
+// ...
+
+var enumeration_id = params[15];
+var enumeration_meta_data = helper.getEnumerationMetaData(enumeration_id, "MY_ENUM_META_DATA_KEY");
+
+

+
+

Get + environment variable

+
+ Here is an example to get/set environment variables in Javascript, + helper.getEnvironmentVariable() and + helper.setEnvironmentVariable() : +

+
+
var env_var = helper.getEnvironmentVariable("QT_DIR");
+var set_env_var_ok = helper.setEnvironmentVariable("MY_ENV_VAR", "my_value");
+
+

+
+

Read + and write to files

+
+ Javascript engine of QxEntityEditor application is able to read and write to files (whatever + files on your system, not only exported files). + Javascript classes file and dir are available to instantiate + Javascript objects and to provide functions to manage files and directories. +

+ The Javascript file class provides the same definition as QFile Qt class : +

+
+
/*
+   --- 'file' class methods available by script (QFile wrapper : http://doc.qt.io/qt-5/qfile.html) ---
+
+   bool copy(string fileName, string newName);
+   bool exists(string fileName);
+   bool link(string fileName, string linkName);
+   bool remove(string fileName);
+   bool rename(string oldName, string newName);
+   string readAll(string fileName);
+
+   void setFileName(string name);
+   string fileName();
+   bool open(int mode); // enum QIODevice::OpenMode, for example : 26 = (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) = (2 + 8 + 16)
+   int error(); // enum QFile::FileError
+   void close();
+   bool atEnd();
+   string readLine();
+   void write(string text);
+*/
+
+

+ The Javascript dir class provides the same definition as QDir Qt class : +

+
+
/*
+   --- 'dir' class methods available by script (QDir wrapper : http://doc.qt.io/qt-5/qdir.html) ---
+
+   void setPath(string path);
+   string path();
+   string appPath();
+   string homePath();
+   string rootPath();
+   string tempPath();
+
+   string fromNativeSeparators(string pathName);
+   string toNativeSeparators(string pathName);
+
+   string cleanPath(string path);
+   bool isAbsolutePath(string path);
+   bool isRelativePath(string path);
+   bool match(string filter, string fileName);
+
+   bool mkdir(string dirName);
+   bool mkpath(string dirPath);
+   bool rmdir(string dirName);
+   bool rmpath(string dirPath);
+   bool exists(string name);
+
+   bool cdUp();
+   bool cd(string dirName);
+   string absoluteFilePath(string fileName);
+   string absolutePath();
+   string canonicalPath();
+   string dirName();
+   string filePath(string fileName);
+   void refresh();
+   string relativeFilePath(string fileName);
+
+   bool isAbsolute();
+   bool isReadable();
+   bool isRelative();
+   bool isRoot();
+*/
+
+

+ Example : read a file content : +

+
+
var f1 = new file();
+var f1_content = f1.readAll("C:\\Temp\\my_file.txt");
+
+

+ Other example : write to a file : +

+
+
var f2 = new file();
+f2.setFileName("C:\\Temp\\file_generated_by_script.txt");
+f2.open(26); // (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) = (2 + 8 + 16)
+f2.write("aaa");
+f2.write("bbb");
+f2.close();
+
+

+
+

Get list + of entities/enumerations of a project

+
+ Here is how to get all entities and enumerations of a *.qxee project : +

+
+
var listOfAllEntities = helper.getListOfAllEntities(); // 'listOfAllEntities' variable is an array, each item of this array contains : <entity_id>|<entity_name>
+var listOfAllEnums = helper.getListOfAllEnums(); // 'listOfAllEnums' variable is an array, each item of this array contains : <enum_id>|<enum_name>
+
+

+
+

Fetch all + application settings (at global level, project level and plugin level)

+
+ Here is how to fetch all application settings (JSON format) : +
    +
  • at global level calling function : + helper.getQxEEGlobalSettingsJson() ; +
  • +
  • at project level calling function : + helper.getQxEEProjectSettingsJson() ; +
  • +
  • at plugin level calling function : + helper.getQxEEPluginSetingsJson(). +
  • +
+
+
+
var globalSettings = helper.getQxEEGlobalSettingsJson();    // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+var projectSettings = helper.getQxEEProjectSettingsJson();  // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+var pluginSettings = helper.getQxEEPluginSetingsJson();     // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+
+print(globalSettings); helper.print(globalSettings);
+print(projectSettings); helper.print(projectSettings);
+print(pluginSettings); helper.print(pluginSettings);
+
+globalSettings = JSON.parse(globalSettings);    // Now 'globalSettings' is a javascript object instance
+projectSettings = JSON.parse(projectSettings);  // Now 'projectSettings' is a javascript object instance
+pluginSettings = JSON.parse(pluginSettings);    // Now 'pluginSettings' is a javascript object instance
+
+

+
+
+

Add a custom + action (placeholder) in C++ export template

+
+ C++ export plugins provide a setting to define template files to + use during export : Header *.h and Source *.cpp. + QxEntityEditor application provides several C++ templates by default, and it is possible to + define your own C++ template (option � Custom + �). + Header *.h and Source *.cpp C++ templates contain some + placeholders (@@ACTION@@ format) to replace code by calculated value. + Placeholder is the most important part to understand how Javascript + customization engine works. + Please note that you can define your own custom placeholder + with @@CUSTOM_ prefix, for example : @@CUSTOM_MY_ACTION@@. +

+ Here is an example to test current action code (so current placeholder inside call context) with + the Javascript engine : +

+
+ /* you can define your own placeholder in the template, it must start + with @@CUSTOM_, for example : @@CUSTOM_MY_ACTION@@ + ==> then, in the custom script, check if you are processing your custom action with this + code : */ +
var action = params[5];
+if (action == "CUSTOM_MY_ACTION")
+{
+   return "quit with my custom code here";
+}
+
+

+
+

Script + example : add automatically Q_PROPERTY definition on all generated C++ properties

+
+ Here is a documented script (deployed with QxEntityEditor package in + ./samples/q_property.js file) to add automatically Q_PROPERTY macro definition + to all properties of a *.qxee project : +

+
+
({
+
+/* ----------------------------------------------------------------------------------------
+   ----------------------------------------------------------------------------------------
+   'q_property.js' : custom javascript file to customize QxEntityEditor C++ export process.
+   This script is an example to show how to use QxEntityEditor javascript engine to add a Q_PROPERTY definition for each property generated by QxEntityEditor.
+   More details about Q_PROPERTY macro on Qt web site : http://doc.qt.io/qt-5/properties.html
+
+   To use this javascript file :
+      1- go to the main menu of QxEntityEditor 'Tools >> Export to C++ project (settings)' ;
+      2- select the C++ template 'qx::IxPersistable + QObject' : now generated entities will inherit from QObject, which is required to use the Qt Q_PROPERTY macro ;
+      3- in the field 'Custom script file' : put the location of this 'q_property.js' custom javascript file ;
+      4- save the settings and start the C++ export process ;
+      5- check generated files : Q_PROPERTY should be added automatically by the export process.
+   ----------------------------------------------------------------------------------------
+   ---------------------------------------------------------------------------------------- */
+
+// Here is the entry point of the QxEntityEditor javascript engine
+// This function is called for each placeholder defined in the C++ template section
+customProcess : function(params)
+{
+   try
+   {
+      // We use here the @@MACRO_QX_PERSISTABLE_HPP@@ placeholder which is present in the default C++ template 'qx::IxPersistable + QObject'
+      // You could also create your own custom C++ template (based on 'qx::IxPersistable + QObject' template), and create your own placeholder (which must be prefixed by @@CUSTOM_), for example : @@CUSTOM_Q_PROPERTY@@
+      var action = params[5];
+      if (action != "MACRO_QX_PERSISTABLE_HPP") { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Check if we have an entity
+      var entity_id = params[13];
+      if ((entity_id == "") || (entity_id == "0")) { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Get the list of properties
+      var entity_details = helper.getEntityDetails(entity_id);
+      var entity_list_of_properties_id = ((entity_details.length > 0) ? entity_details[10] : "");
+      var entity_list_of_properties_array = entity_list_of_properties_id.split("|");
+      if (entity_list_of_properties_array.length <= 0) { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Prepare output string
+      var output = params[0] + "\n";
+
+      // Iterate over each property
+      for (var idx = 0; idx < entity_list_of_properties_array.length; idx++)
+      {
+         // Get property details
+         var property_id = entity_list_of_properties_array[idx];
+         var property_details = helper.getPropertyDetails(property_id);
+
+         // Here you could also get property meta-data that you can define in QxEntityEditor, property parameters screen, section 'List of meta-data'
+         // This is a way to manage your own property parameters which are not a part of QxEntityEditor
+         // It could be useful for example to manage some Q_PROPERTY settings like : RESET, NOTIFY, REVISION, DESIGNABLE, SCRIPTABLE, FINAL, etc...
+         // To get a property meta-data value, just write this code : var my_meta_data = helper.getPropertyMetaData(property_id, "MY_META_DATA_KEY");
+
+         // Get property type and name
+         var property_type = property_details[5];
+         var property_name = property_details[2];
+
+         // Check if property type can be used with Q_PROPERTY macro
+         if (list_of_compatible_property_type.indexOf(property_type) == -1) { continue; }
+
+         // Create Q_PROPERTY definition
+         output += "\n   Q_PROPERTY(" + property_type + " " + property_name + " READ get" + property_name + " WRITE set" + property_name + ")";
+      }
+
+      return output;
+   }
+   catch (err)
+   { return ("[CustomScriptError] an unexpected error occurred : " + err); }
+}
+
+});
+
+// Here is a list of C++ types compatible with Qt Q_PROPERTY macro (C++ type can be converted to/from QVariant)
+// You can of course register your own C++ types to be able to use them with Q_PROPERTY macro (using Qt Q_DECLARE_METATYPE() macro)
+// So the following array is not fixed : you can add all C++ types you want...
+var list_of_compatible_property_type = [ "QBitArray", "QBitmap", "bool", "QBrush", "QByteArray", "QChar", "QColor", "QDate", "QDateTime", "double", 
+                                         "QUuid", "QFont", "QVariantHash", "QIcon", "QImage", "int", "QLine", "QLineF", "QVariantList", "qlonglong", 
+                                         "QVariantMap", "QMatrix", "QMatrix4x4", "QPixmap", "QPoint", "QPointF", "QPolygon", "QPolygonF", "QRect", "QRectF", 
+                                         "QRegExp", "QRegion", "QSize", "QSizeF", "QString", "QStringList", "QTime", "uint", "qulonglong", "QUrl", 
+                                         "QVector2D", "QVector3D", "QVector4D" ];
+
+

+
+

Enable Javascript + debugger editor

+
+ Javascript engine of QxEntityEditor application provides a native Javascript debugger. + This debug environment provides all required features to help you to develop and fix your custom + scripts : +
    +
  • define breakpoints ;
  • +
  • step-by-step mode to go from a code line to another code line during export execution ; +
  • +
  • display all variables and their values during export execution ;
  • +
  • display logs window.
  • +
+
+ By default, QxEntityEditor Javascript debugger is disabled during an export. + To enable it and show the debug editor, you can : +
    +
  • go to export settings, define a script to + use, then click on � Debug custom Javascript file � button ;
  • +
  • or press the SHIFT keyboard shortcut before starting an export process.
  • +
+
+ JS debug +

+
+
+ +

Execute custom scripts + (shell/bat) before/after plugin execution

+
+ QxEntityEditor application provides a way to define some custom scripts *.bat (Windows), + *.sh (Linux) or even executables to run before and/or after a QxEntityEditor plugin + execution. + Each script (or process) is called with 1 input parameter : the current *.qxee project + location. + This feature can be used for example to : +
    +
  • put generated files to a source control (Git, Perforce, CVS, etc...) ;
  • +
  • run compilation process for a generated C++ project ;
  • +
  • execute unitary tests or start an automation server like Jenkins for example ;
  • +
  • modify some values in the *.qxee SQLite database project + file after importing from a database structure.
  • +
+
+ To define these scripts or executables to run before and/or after a QxEntityEditor plugin + execution, just go to the main menu : Tools >> Plugins scripts. +

+ Plugin scripts +

+ Note : you can put in this list an absolute path to your script, or a relative path to + *.qxee project file. + For example, ./my_script.sh means that my_script.sh file must be located in the same + directory as *.qxee project file. +

+
+ +

QxEntityEditor + command-line interface

+
+ QxEntityEditor provides a command-line interface to run the application with some parameters. + We will detail in this chapter some QxEntityEditor calling examples : +


+ -- Example n�1 : run QxEntityEditor defining a *.qxee project to load at startup + (--project parameter) : +
+
+ +
QxEntityEditor --project="c:\test\qxBlog.qxee"
+
+
+

+ -- Example n�2 : run QxEntityEditor without displaying the user interface (--no_gui + parameter), defining a *.qxee project to load (--project parameter) and executing + automatically a C++ export process (--plugin parameter) : +
+
+ +
QxEntityEditor --no_gui --project="c:\test\qxBlog.qxee" --plugin=QxEECppExport
+
+
+

+ -- Example n�3 : run QxEntityEditor in read-only mode (--viewer_mode parameter), this + parameter can be used to open large *.qxee projects without any registered license key : +
+
+ +
QxEntityEditor --viewer_mode
+
+
+

+ -- Example n�4 : run QxEntityEditor tracing all SQL logs (--log_sql parameter), this + parameter logs all SQL queries executed to *.qxee SQLite + database : +
+
+ +
QxEntityEditor --log_sql
+
+
+

+ -- Example n�5 : run QxEntityEditor loading a *.qxee project from a JSON file : +
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEEJsonImport --QxEEJsonImport_file="<path_to_your_json_file>"
+
+
+

+ -- Example n�6 : display documentation about all QxEntityEditor command line parameters : +
+
+ +
QxEntityEditor --?
+
+
+
+ Note : --?, --help or --h will log following output to console : +
+
+ +
*** QxEntityEditor 1.2.5 application global command line parameters ***
+
+  --project="<full path to *.qxee project file>" : run QxEntityEditor defining a *.qxee project to load at startup
+  --no_gui : run QxEntityEditor without displaying the user interface
+  --viewer_mode : run QxEntityEditor in read-only mode, this parameter can be used to open large *.qxee projects without any registered license key
+  --log_sql : run QxEntityEditor tracing all SQL logs, this parameter logs all SQL queries executed to *.qxee SQLite database
+  --font : define application font (due to issues since macOS Catalina 10.15) with syntax <family>||<pointSize>||<weight>||<italic> (only <family> is required), for example : Courier New||14
+  --style_sheet : define application style sheet (more details here : https://doc.qt.io/qt-5/stylesheet-reference.html), for example : QWidget { background-color: black }
+  --plugin=<plugin name> : run QxEntityEditor and execute automatically a plugin process (see below for specific parameters per plugin)
+
+*** Import plugin QxEEJsonImport ***
+
+  --QxEEJsonImport_file="<full path to your json file>" : [Required] run QxEntityEditor loading a *.qxee project from a JSON file
+
+*** Import plugin QxEEMySQLImport ***
+
+  --QxEEMySQLImport_db_ip="<DB IP>" : [Required] Database server address (IP)
+  --QxEEMySQLImport_db_port="<DB port>" : [Required] Port number to connect to database
+  --QxEEMySQLImport_db_name="<DB name>" : [Required] Database name
+  --QxEEMySQLImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEMySQLImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEMySQLImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEMySQLImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEMySQLImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEMySQLImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEMySQLImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEMySQLImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEMySQLImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEMySQLImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEMySQLImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEMySQLImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEMySQLImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEEOdbcImport ***
+
+  --QxEEOdbcImport_dsn="<ODBC DSN>" : [Required] ODBC DSN to connect to database
+  --QxEEOdbcImport_db_type=<numeric value> : [Required] Database engine type (0=generic, 1=postgresql, 2=mysql, 3=oracle, 4=mssqlserver, 5=sqlite)
+  --QxEEOdbcImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEOdbcImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEOdbcImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEOdbcImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEOdbcImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEOdbcImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEOdbcImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEOdbcImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEOdbcImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEOdbcImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEOdbcImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEOdbcImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEOdbcImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEEPostgreSQLImport ***
+
+  --QxEEPostgreSQLImport_db_ip="<DB IP>" : [Required] Database server address (IP)
+  --QxEEPostgreSQLImport_db_port="<DB port>" : [Required] Port number to connect to database
+  --QxEEPostgreSQLImport_db_name="<DB name>" : [Required] Database name
+  --QxEEPostgreSQLImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEPostgreSQLImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEPostgreSQLImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEPostgreSQLImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEPostgreSQLImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEPostgreSQLImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEPostgreSQLImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEPostgreSQLImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEPostgreSQLImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEPostgreSQLImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEPostgreSQLImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEPostgreSQLImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEPostgreSQLImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEESQLiteImport ***
+
+  --QxEESQLiteImport_db_path="<DB File Path>" : [Required] SQLite database file path
+  --QxEESQLiteImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEESQLiteImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEESQLiteImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEESQLiteImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEESQLiteImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEESQLiteImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEESQLiteImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEESQLiteImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEESQLiteImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEESQLiteImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEESQLiteImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Export plugin QxEECppExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppExport_path="<Export Path>" : [Optional] C++ export path parameter
+  --QxEECppExport_template_type=<numeric value> : [Optional] C++ template type selected to build C++ files (0=no_inheritance, 1=ix_persistable, 2=qx_persistable, 3=ix_persistable_and_q_object, 4=custom)
+  --QxEECppExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppExport_template_type parameter must be equal to 4, which means custom)
+  --QxEECppExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppExport_template_type parameter must be equal to 4, which means custom)
+  --QxEECppExport_qxorm_relative_path=0/1 : [Optional] Relative path to QxOrm library
+  --QxEECppExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEECppModelViewExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppModelViewExport_path="<Export Path>" : [Optional] C++ model/view export path parameter
+  --QxEECppModelViewExport_namespace="<Namespace>" : [Optional] Namespace where to put all model/view classes
+  --QxEECppModelViewExport_template_type=<numeric value> : [Optional] C++ model/view template type selected to build C++ files (0=default, 1=custom, 2=qx_model_service)
+  --QxEECppModelViewExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppModelViewExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppModelViewExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppModelViewExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppModelViewExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppModelViewExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEECppServicesExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppServicesExport_path="<Export Path>" : [Optional] C++ services export path parameter
+  --QxEECppServicesExport_namespace="<Namespace>" : [Optional] Namespace where to put all services classes
+  --QxEECppServicesExport_template_type=<numeric value> : [Optional] C++ services template type selected to build C++ files (0=default, 1=custom)
+  --QxEECppServicesExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppServicesExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppServicesExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppServicesExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppServicesExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppServicesExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+  --QxEECppServicesExport_generate_server_app=0/1 : [Optional] Generate a sample server application
+  --QxEECppServicesExport_server_app_path="<Server App Path>" : [Optional] Server application location
+
+*** Export plugin QxEEGenericDDLExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEEGenericDDLExport_path="<Export Path>" : [Optional] DDL export path parameter
+  --QxEEGenericDDLExport_db_type=<numeric value> : [Optional] Database type (0=default, 1=sqlite, 2=mysql, 3=postgresql, 4=oracle, 5=mssqlserver)
+  --QxEEGenericDDLExport_relation_as_fk=0/1 : [Optional] Export relationships as foreign keys in database
+  --QxEEGenericDDLExport_schema_type=<numeric value> : [Optional] Way to export database schema (0=full, 1=evolution, 2=full_and_evolution)
+  --QxEEGenericDDLExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEEPrinter ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process !!!
+
+*** Export plugin QxEEXmlExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEEXmlExport_path="<Export Path>" : [Optional] XML or JSON export path parameter
+  --QxEEXmlExport_as_json=0/1 : [Optional] Export project as JSON format
+
+
+
+
+ Other note : to see logs generated by QxEntityEditor application : +
    +
  • Windows : use an external tool, for example DebugView ;
  • +
  • Linux : execute QxEntityEditor from a terminal ;
  • +
  • Mac OS X : execute QxEntityEditor from a terminal inside QxEntityEditor.app + sub-directory, for example : cd QxEntityEditor.app/Content/MacOS/, then : + ./QxEntityEditor +
  • +
+

+ -- Example n�7 : import by ODBC (plugin QxEEOdbcImport) a database schema : +
+
+ +
QxEntityEditor --no_gui --project="<project_path>" --plugin=QxEEOdbcImport --QxEEOdbcImport_db_type=1 --QxEEOdbcImport_dsn="<your_dsn>" --QxEEOdbcImport_login="<your_login>" --QxEEOdbcImport_pwd="<your_password>" --QxEEOdbcImport_delete_namespace=1
+
+
+

+ -- Example n�8 : import a PostgreSQL database schema (plugin QxEEPostgreSQLImport) : +
+
+ +
QxEntityEditor --no_gui --project="<project_path>" --plugin=QxEEPostgreSQLImport --QxEEPostgreSQLImport_db_ip="<ip>" --QxEEPostgreSQLImport_db_port=5432 --QxEEPostgreSQLImport_db_name="<dbname>" --QxEEPostgreSQLImport_login="<your_login>" --QxEEPostgreSQLImport_pwd="<your_password>" --QxEEPostgreSQLImport_delete_namespace=1
+
+
+

+ -- Example n�9 : export a QxEntityEditor project to a Source Control manager/directory Git, + Perforce, CVS, etc. (QxEESourceControlExport plugin) : +
+
+ +
QxEntityEditor --no_gui --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlExport --QxEESourceControlExport_path="<path_to_your_export_output_directory>"
+
+
+

+ -- Example n�10 : import from a Source Control manager/directory Git, Perforce, CVS, etc. + (QxEESourceControlImport plugin) : +
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlImport --QxEESourceControlImport_path="<path_to_the_root_source_control_json_file>"
+
+
+

+
+ +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/model.html b/doc/qxorm_en/model.html new file mode 100644 index 0000000..9d1602b --- /dev/null +++ b/doc/qxorm_en/model.html @@ -0,0 +1,177 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> [model] + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/quick_sample.html b/doc/qxorm_en/quick_sample.html new file mode 100644 index 0000000..094df39 --- /dev/null +++ b/doc/qxorm_en/quick_sample.html @@ -0,0 +1,449 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
HomeDownloadQuick sample + Tutorial (4) + + + + + + +
+ +
+
+ Manual (2) + + + + + + +
+ +
+
ForumOur customers
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Quick sample + + + + + + + + + + + + + + +
+ Current version :  + + QxOrm 1.5.0 - QxOrm library online class documentation - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
In this chapter, we will see a quick sample with basic functionalities of QxOrm + library.
+
+ Note : QxOrm library uses the following syntax and naming convention for C++ + source code : +
    +
  • all classes, functions, properties, etc... are defined under namespace qx ; +
  • +
  • all macros of QxOrm library are prefixed by QX_... ; +
  • +
  • all abstracts classes (or interfaces) start with prefix Ix (for example + IxFactory is an interface to create an instance of object) ; +
  • +
  • other classes start with prefix Qx (for example QxDataMember) ; +
  • +
  • containers of objects end with suffix X (for example QxDataMemberX is a + list of QxDataMember) ; +
  • +
  • functions to interact with databases are under namespace qx::dao (for + example qx::dao::fetch_by_id()) ; +
  • +
  • functions to serialize are under namespace + qx::serialization (for example qx::serialization::xml::to_file()) + ; +
  • +
  • the reflection (or introspection) engine can be used with + qx::QxClassX (for example qx::QxClassX::invoke() to call a class + method) ; +
  • +
  • all traits classes are under namespace qx::trait (for + example qx::trait::is_smart_ptr<T>). +
  • +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt + Ambassador Program + +
+ Additional note : you can find a more complex sample (with inheritance, polymorphism, + relationships, collections, shared libraries, + memory leak, etc...) in the folder ./test/qxDllSample/ of your QxOrm package. + The ./test/qxDllSample/ folder contains 2 projects of + DLL type (shared libraries) and 1 project of executable type : ./dll1/, + ./dll2/ and ./exe/.
+ This solution can be built with Visual C++ 2008, 2010 or 2012 on Windows (open the file + ./test/qxDllSample/test.sln).
+ This solution can also be compiled with GCC on Linux, Clang on Mac OS X and MinGW on + Windows with qmake command line.
+
+ Quick sample step by step : + +
+ * + -----------------------------------------------------------------------------------------------------
+ * 1- drug.h file : drug class definition with 3 properties : id, name + and description
* + -----------------------------------------------------------------------------------------------------
+

+ + + + + + + +
+
#ifndef _CLASS_DRUG_H_
+#define _CLASS_DRUG_H_
+
+class drug
+{
+public:
+   long id;
+   QString name;
+   QString description;
+
+   drug() : id(0) { ; }
+   virtual ~drug() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(drug, qx::trait::no_base_class_defined, 1)
+
+/* This macro is necessary to register 'drug' class in QxOrm context */
+/* param 1 : the current class to register => 'drug' */
+/* param 2 : the base class, if no base class, use the qx trait => 'qx::trait::no_base_class_defined' */
+/* param 3 : the class version used by serialization to provide 'ascendant compatibility' */
+
+#endif // _CLASS_DRUG_H_
+
+

+ * + ----------------------------------------------------------------------------------------------------
+ * 2- drug.cpp file : 'setting function' implementation : void + qx::register_class()
* + ---------------------------------------------------------------------------------------------------- +


+ + + + + + + +
+
#include "precompiled.h"   // Precompiled-header with '#include <QxOrm.h>' and '#include "export.h"'
+#include "drug.h"          // Class definition 'drug'
+#include <QxOrm_Impl.h>     // Automatic memory leak detection and boost serialization export macro
+
+QX_REGISTER_CPP_MY_TEST_EXE(drug)   // This macro is necessary to register 'drug' class in QxOrm context
+
+namespace qx {
+template <> void register_class(QxClass<drug> & t)
+{
+  t.id(& drug::id, "id");               // Register 'drug::id' <=> primary key in your database
+  t.data(& drug::name, "name", 1);      // Register 'drug::name' property with key 'name' and version '1'
+  t.data(& drug::description, "desc");  // Register 'drug::description' property with key 'desc'
+}}
+
+
+
+ * + -----------------------------------------------------------------------------------------------
+ * 3- main.cpp file : basic functionalities of QxOrm library with drug class
* + ----------------------------------------------------------------------------------------------- +


+ + + + + + + +
+
#include "precompiled.h"
+#include "drug.h"
+#include <QxOrm_Impl.h>
+
+int main(int argc, char * argv[])
+{
+   QApplication app(argc, argv); // Qt application
+
+   // Create 3 new drugs
+   // It is possible to use 'std' and 'Qt' smart pointer : 'std::shared_ptr', 'QSharedPointer', etc...
+   typedef std::shared_ptr<drug> drug_ptr;
+   drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1";
+   drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2";
+   drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3";
+
+   // Insert drugs into container
+   // It is possible to use many containers from 'std', 'boost', 'Qt' and 'qx::QxCollection<Key, Value>'
+   typedef std::vector<drug_ptr> type_lst_drug;
+   type_lst_drug lst_drug;
+   lst_drug.push_back(d1);
+   lst_drug.push_back(d2);
+   lst_drug.push_back(d3);
+
+   // Init parameters to communicate with a database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+   // Create table 'drug' into database to store drugs
+   QSqlError daoError = qx::dao::create_table<drug>();
+
+   // Insert drugs from container to database
+   // 'id' property of 'd1', 'd2' and 'd3' are auto-updated
+   daoError = qx::dao::insert(lst_drug);
+
+   // Modify and update the second drug into database
+   d2->name = "name2 modified";
+   d2->description = "desc2 modified";
+   daoError = qx::dao::update(d2);
+
+   // Delete the first drug from database
+   daoError = qx::dao::delete_by_id(d1);
+
+   // Count drugs into database
+   long lDrugCount = qx::dao::count<drug>();
+
+   // Fetch drug with id '3' into a new variable
+   drug_ptr d_tmp; d_tmp.reset(new drug());
+   d_tmp->id = 3;
+   daoError = qx::dao::fetch_by_id(d_tmp);
+
+   // Export drugs from container to a file under xml format (serialization)
+   qx::serialization::xml::to_file(lst_drug, "./export_drugs.xml");
+
+   // Import drugs from xml file into a new container
+   type_lst_drug lst_drug_tmp;
+   qx::serialization::xml::from_file(lst_drug_tmp, "./export_drugs.xml");
+
+   // Clone a drug
+   drug_ptr d_clone = qx::clone(* d1);
+
+   // Create a new drug by class name (factory)
+   qx::any d_any = qx::create("drug");
+
+   // Insert drugs container into 'qx::cache'
+   qx::cache::set("drugs", lst_drug);
+
+   // Remove all elements from 'qx::cache'
+   qx::cache::clear();
+
+   // Create a dummy memory leak
+   drug * pDummy = new drug();
+
+   return 0;
+}
+
+
+

+ * + -------------------------------------------------------------------------
+ * 4- execute program and trace output debug
* + ------------------------------------------------------------------------- +

+

+

+ [QxOrm] qx::QxSqlDatabase : create new database + connection in thread '3616' with key + '{d315250c-b5c9-46e0-9402-f800368a6673}'
+ [QxOrm] sql query (78 ms) : CREATE TABLE drug (id INTEGER NOT NULL + PRIMARY KEY AUTOINCREMENT, name TEXT, desc TEXT)
+ [QxOrm] sql query (63 ms) : INSERT INTO drug (name, desc) VALUES + (:name, :desc)
+ [QxOrm] sql query (62 ms) : UPDATE drug SET id = :id, name = :name, + desc = :desc WHERE id = :id_bis
+ [QxOrm] sql query (63 ms) : DELETE FROM drug WHERE id = :id
+ [QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM drug
+ [QxOrm] sql query (0 ms) : SELECT drug.id AS drug_id_0, drug.name AS + drug_name_0, drug.desc AS drug_desc_0 FROM drug WHERE drug_id_0 = + :id
+ [QxOrm] Leaked object at 0xf52ad8 (size 16, src\main.cpp:74)
+ [QxOrm] **** 1 memory leaks found ****

+
+

+ * + ------------------------------------------------------------------------------
+ * 5- ./export_drugs.xml file created by the program
* + ------------------------------------------------------------------------------
+

+
+ quick_sample.export_drugs.xml +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_en/resource/ES.png b/doc/qxorm_en/resource/ES.png new file mode 100644 index 0000000..805a1b6 Binary files /dev/null and b/doc/qxorm_en/resource/ES.png differ diff --git a/doc/qxorm_en/resource/FR.png b/doc/qxorm_en/resource/FR.png new file mode 100644 index 0000000..35e3aaa Binary files /dev/null and b/doc/qxorm_en/resource/FR.png differ diff --git a/doc/qxorm_en/resource/GB.png b/doc/qxorm_en/resource/GB.png new file mode 100644 index 0000000..3a18908 Binary files /dev/null and b/doc/qxorm_en/resource/GB.png differ diff --git a/doc/qxorm_en/resource/background.jpg b/doc/qxorm_en/resource/background.jpg new file mode 100644 index 0000000..d9f012a Binary files /dev/null and b/doc/qxorm_en/resource/background.jpg differ diff --git a/doc/qxorm_en/resource/download.jpg b/doc/qxorm_en/resource/download.jpg new file mode 100644 index 0000000..252f63c Binary files /dev/null and b/doc/qxorm_en/resource/download.jpg differ diff --git a/doc/qxorm_en/resource/gui_qxClientServer.jpg b/doc/qxorm_en/resource/gui_qxClientServer.jpg new file mode 100644 index 0000000..5f10aa1 Binary files /dev/null and b/doc/qxorm_en/resource/gui_qxClientServer.jpg differ diff --git a/doc/qxorm_en/resource/gui_qxClient_01.jpg b/doc/qxorm_en/resource/gui_qxClient_01.jpg new file mode 100644 index 0000000..c505283 Binary files /dev/null and b/doc/qxorm_en/resource/gui_qxClient_01.jpg differ diff --git a/doc/qxorm_en/resource/gui_qxClient_02.jpg b/doc/qxorm_en/resource/gui_qxClient_02.jpg new file mode 100644 index 0000000..90e964b Binary files /dev/null and b/doc/qxorm_en/resource/gui_qxClient_02.jpg differ diff --git a/doc/qxorm_en/resource/gui_qxServer.jpg b/doc/qxorm_en/resource/gui_qxServer.jpg new file mode 100644 index 0000000..e8a0549 Binary files /dev/null and b/doc/qxorm_en/resource/gui_qxServer.jpg differ diff --git a/doc/qxorm_en/resource/jquery.min.js b/doc/qxorm_en/resource/jquery.min.js new file mode 100644 index 0000000..0f60b7b --- /dev/null +++ b/doc/qxorm_en/resource/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; + +return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("
+
+ Video presentation step by step : +
    +
  • Download and install QxOrm library (10s) ;
  • +
  • Download and install QxEntityEditor (56s) ;
  • +
  • Create a QxEntityEditor project (1m 46s) ;
  • +
  • Export entities to a C++/Qt project (8m 26s) ;
  • +
  • Export entities to a DDL SQL database script (10m 22s) ;
  • +
  • Create a client/server application to transfer entities over network (12m 31s) ;
  • +
  • Export QxEntityEditor project to a XML or JSON file (17m 13s) ;
  • +
  • Execute QxEntityEditor with command line (no GUI) (18m 07s).
  • +
+
+
+
+ Here is another video of QxEntityEditor + application to show how to import an existing database structure (MySQL Workbench project) :
+
+
+
+ Video step by step : +
    +
  • MySQL Workbench project - Sakila sample database (10s) ;
  • +
  • Create a DSN to connect to MySQL by ODBC (46s) ;
  • +
  • Import database structure in a QxEntityEditor project (1m 15s) ;
  • +
  • Export QxEntityEditor project to a C++ Qt project (3m 10s) ;
  • +
  • Build the generated C++ Qt project (4m 22s).
  • +
+
+ + + +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/customer.html b/doc/qxorm_fr/customer.html new file mode 100644 index 0000000..59e3fe7 --- /dev/null +++ b/doc/qxorm_fr/customer.html @@ -0,0 +1,493 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Nos clients + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+
+ Remarque : la biblioth�que QxOrm est un produit open-source t�l�charg� chaque jour : il est donc + impossible de donner une liste de tous les utilisateurs et de toutes les applications bas�es sur la + biblioth�que QxOrm.
+ Voici une liste d'entreprises utilisant la biblioth�que QxOrm et l'application QxEntityEditor dans leurs + produits commerciaux :
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ AGCO + + AGCO :
+ AGCO Corporation is an American agricultural equipment manufacturer based in Duluth, Georgia, + United States. As a leading global manufacturer of agricultural equipment, AGCO offers a full + line of tractors, combines, hay tools, sprayers, forage and tillage equipment, which are + distributed through more than 3,100 independent dealers and distributors in more than 140 + countries worldwide. +
+ [Description based on Wikipedia webpage] + +

+
+ ENSCO + + ENSCO :
+ ENSCO, Inc. is a provider of engineering services, products, and advanced technologies for + national security, transportation safety and asset management, information sciences, data + management including information management systems for weather monitoring, aerospace and + avionics, and R and D for private corporations and local, state, and federal agencies and + governments, including the United States Department of Defense. +
+ [Description based on Wikipedia webpage] + +

+
+ Smiths Detection + + Smiths Detection :
+ Smiths Group plc is a British multinational diversified engineering company headquartered in + London, United Kingdom. It has operations in over 50 countries and employs around 23,550 + staff.
+ Smiths Group has five divisions : Smiths Detection is the world's largest manufacturer of + sensors for the detection of explosives, weapons, chemical agents, biohazards, narcotics and + contraband. +
+ [Description based on Wikipedia webpage] + +

+
+ Veran Medical + + Veran Medical :
+ Veran Medical Technologies is focused on comprehensive oncology program. + Veran's technology is defining the new standard in early definitive diagnosis of cancer, + providing your hospital with a comprehensive navigation solution. + Established in 2005, Veran Medical Technologies is a privately held soft tissue navigation + company focused on the early diagnosis of cancer. +
+ Veran's mission is to extend life through earlier diagnosis and the delivery of minimally + invasive therapies for interventional oncology procedures with unique navigation + technologies. +
+ Veran is dedicated to increasing patient survival while providing cost effective healthcare + solutions that defined the next standard of care. +

+
+ Altran AIS + + Altran AIS :
+ Altran Technologies, SA is a global consulting firm founded in 1982 in France. Altran + operates primarily in high technology and innovation consultancy, which account for nearly + 75% of its turnover. Administrative and information consultancy accounts for 20% of its + turnover with strategy and management consulting making up the rest. +
+ [Description based on Wikipedia webpage] + +

+
+ Intermountain Healthcare + + Intermountain Healthcare + :
+ Intermountain Health Care, Inc., officially doing business as Intermountain Healthcare, is a + non-profit healthcare system and is the largest healthcare provider in the Intermountain + West. Until 2005 it was known as Intermountain Health Care or more commonly IHC; it is now + often referred to as simply Intermountain for short. Intermountain Healthcare provides + hospital and other medical services in Utah and Idaho and also offers integrated managed care + under the insurance brand SelectHealth. Intermountain Healthcare is headquartered in Salt + Lake City, Utah, and (as of 2014) employed over 33,000 people. +
+ [Description based on Wikipedia webpage] + +

+
+ GSI Electronics Inc. + + GSI Electronics Inc. + :
+ GSI Electronics Inc. develops, manufactures and distributes innovative technological products + for the agricultural industry. GSI Electronics Inc. unique expertise allows them to offer + accurate, simple and diverse electronic, data processing and mechanical solutions for + improving agricultural production. +

+
+ Sagemcom + + Sagemcom :
+ A French high-tech group of international dimensions, Sagemcom operates on the broadband + (digital home, set-top boxes, Internet routers, telephony and multimedia terminals), telecoms + and energy (smartgrid and energy management) and retail. +

+
+ Motius + + Motius :
+ Motius is a unique German R&D company. It solves technical problems and develops products for + international customers through a pool of elite senior students, academic researchers and + young engineers. +

+
+ GSVitec + + GSVitec :
+ Production of high-speed video and measurement data acquisition devices and software.
+ Production of High Power LED light solutions especially for high speed video. Production and + design of High Power custom LED solutions (crash test, military, r&d).
+ Software solutions for synchronous high speed data and video acquisition and recording.
+

+
+ Promenade Software + + Promenade Software :
+ Promenade Software is a company comprised of highly skilled, experienced software engineers. + Whether it is for a medical device, avionics test system, or other sensitive system, + Promenade Software knows that their work is critical. + Critical to your company, your customer, and everyone involved. Promenade Software has the + skills and ready-made tools to deliver your product reliably and efficiently. +
+ Unlike other software service providers, Promenade Software took the time to create the + ready-made libraries and test tools that increase your system's quality, while saving you + money and development time. +

+
+ IVE mbH + + IVE mbH :
+ Since founding IVE mbH, Consulting Company for Traffic and Railway Engineering Ltd., in 1998 + IVE proficiently supports clients from the development of first ideas to the final + realisation and the practical use of projects. + Based on transport and railway expertise, IVE mbH derives concepts and future-oriented + sustainable solutions responding to the problems of clients, strengthening their position and + preparing them for the global competition. +

+
+ NauchPribor + + NauchPribor :
+ NauchPribor is a high-tech company aimed on developing and producing low dose x-ray devices + for medical and security fields.
+ Founded more than 40 years ago, now this company is one of the most advanced in + business.
+ It has customers from all over the world. Headquartered resides in Orel, Russia.
+

+
+ Tang + + Tang :
+ Tang A/S develops a PMS system for the veterinary business.
+ Their products are selling in Denmark, Norway and Sweden.
+

+
+
+ All organization names, logos and trademarks used in this web page are for identification purposes only. + All trademarks and logos are the property of their respective owners. +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/download.html b/doc/qxorm_fr/download.html new file mode 100644 index 0000000..e5c0972 --- /dev/null +++ b/doc/qxorm_fr/download.html @@ -0,0 +1,1271 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> T�l�chargement + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
QxOrm est une biblioth�que C++ disponible sous une double licence : +
    +
  • licence GNU/GPLv3 : open-source et + gratuite (id�ale pour d�velopper un projet open-source ou pour une �valuation de la biblioth�que + QxOrm) ;
  • +
  • licence propri�taire permettant de distribuer une + application bas�e sur la biblioth�que QxOrm sans les restrictions de la licence GNU/GPLv3. +
  • +
+ + + + + + + + + +
Download QxOrm + + T�l�charger QxOrm version 1.5.0 (source + test + + documentation)
+ Cette version est compatible avec Visual Studio (Windows), GCC (Linux et Mac OS + X), MinGW (Windows) et Clang (Mac OS X) : support de la norme C++11 n�cessaire. +
+
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+

QxEntityEditor est un �diteur graphique pour la biblioth�que QxOrm : + QxEntityEditor permet de g�rer graphiquement le mod�le d'entit�s.
+ QxEntityEditor est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et g�n�re du code + natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu� et mobile (Android, iOS, + Windows Phone, Raspberry Pi, etc.). +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QxEntityEditorQxEntityEditor 1.2.8 - Windows 32 bitsQxEntityEditorQxEntityEditor 1.2.8 - Windows 64 bits
QxEntityEditorQxEntityEditor 1.2.8 - Windows 32 bits (portable)QxEntityEditorQxEntityEditor 1.2.8 - Windows 64 bits (portable)
QxEntityEditorQxEntityEditor 1.2.8 - Linux 32 bitsQxEntityEditorQxEntityEditor 1.2.8 - Linux 64 bits
QxEntityEditorQxEntityEditor 1.2.8 - Mac OS X
+

+

Remarque : par d�faut, l'application QxEntityEditor est limit�e � 5 entit�s + par projet. + Pour obtenir une cl� de licence et ainsi cr�er un nombre illimit� d'entit�s par projet, vous pouvez nous + contacter � l'adresse suivante : ic-east.com. + Prix d'une cl� de licence QxEntityEditor : 500€ (par d�veloppeur, mise � jour gratuite + pendant 12 mois).
+
+ Un manuel utilisateur (documentation) d�di� � l'application + QxEntityEditor est disponible. +

+ QxEntityEditor +

+
+

QxOrm est bas� sur la biblioth�que Qt. + Vous devez donc t�l�charger et installer le framework Qt avant de pouvoir utiliser QxOrm.

+ + + + + + + + + +
QtQt : biblioth�que compl�te : IHM + (QtGui), r�seau (QtNetwork), XML (QtXml), base de donn�es + (QtSql), etc...
+ La documentation est excellente et le code C++ �crit � partir + de cette biblioth�que est � la fois performant et simple de + compr�hension.
+ Depuis le rachat par Nokia puis Digia et sa nouvelle licence LGPL, Qt est + sans contexte la biblioth�que phare du moment.
+ QxOrm est compatible avec les principaux objets d�finis par Qt + : QObject, QString, QDate, QTime, QDateTime, QList, QHash, + QSharedPointer, QScopedPointer, etc...
+ Il est conseill� d'installer et d'utiliser la derni�re version + de Qt disponible � l'adresse suivante : http://www.qt.io/
+ +

+ Voici l'historique des modifications apport�es � la biblioth�que QxOrm ainsi que l'application + QxEntityEditor : + +
+ Historique des modifications de la biblioth�que QxOrm : + + + + + + + +
+ +

Changes in version 1.5.0:

+
+ - Fix qx::dao::fetch_by_id_with_relation() when a table alias is used (table alias is now used in + the WHERE part instead of table name)
+ - Fix qx::IxDataMember::getType() method when used in a multi-thread environment
+ - New method qx::IxSqlRelation::linkRelationKeyTo() for MongoDB database to simulate lazy loading + for relationships (GitHub #107)
+ - Fix qx::QxSqlDatabase and multi-thread issue when the OS assigns an old and destroyed thread + identifier to a new one (GitHub #42) + add method qx::QxSqlDatabase::removeDatabaseByThread() to + call at the end of a thread execution
+ - Fix qx::QxSimpleCrypt class with Qt version >= 5.10 and error "Attempted to overwrite a + QRandomGenerator to system() or global()"
+ - Fix database not opened using async queries (GitHub #109)
+
+ +

Changes in version 1.4.9:

+
+ - Fix compilation issue with Qt 6.2+ (due to Qt JIRA : https://bugreports.qt.io/browse/QTBUG-92910), + more details in GitHub issue #54
+ - Support QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of + C++ instances in database (new optional parameter 'bUseExecBatch' available for functions : + qx::dao::insert, qx::dao::update, qx::dao::delete_by_id)
+ - New method in qx::QxSqlQuery class named setFctOnBeforeSqlPrepare() to define a custom callback + function to modify SQL query before preparing in database
+ - New callbacks functions available in qx::IxDataMember interface to customize SQL generated per + data member (see an example in ./test/qxBlogCompositeKey/src/blog.cpp file)
+ - Fix an issue in qx::QxSqlRelationLinked::hierarchyResolveOutput() which could call + getIdFromQuery() for nothing, which could generate some warnings in Qt SQL driver (for example : + QPSQLResult::data: column XX out of range)
+ - Fix a compilation issue of QxRestApi and QxHttpTransaction modules with Qt QStringBuilder option + enabled (GitHub issues #50, #83)
+ - Improve SQL DISTINCT to support relationships (unit test available in qxBlog sample project)
+ - New feature to fetch relationships only in LEFT OUTER/INNER JOIN and WHERE clauses (so no columns + in SELECT part) : use {NULL} syntax to define no relation columns in SELECT part (unit test + available in qxBlog sample project)
+ - Fix a crash which could occur using qx::QxSession and multi-threaded environment
+ - Add a new parameter caseSensitive (default value : false) to the method + qx::QxSqlQuery::getSqlResultAt()
+ - Fix an issue with JSON REST API (QxRestApi module) and MongoDB database (more details in GitHub + issue #70)
+ - Improve qx::QxClassX::registerAllClasses() : init all validator instances (can fix some issues in + a multi-thread environment)
+ - New settings available in the qx::QxSqlDatabase singleton class + (setSqlDelimiterForTableNameAlias() and setSqlDelimiterForColumnNameAlias()) to add delimiters to + SQL aliases (more details in GitHub issue #57)
+ - Fix linking error which could occur with Qt6 and MSVC2019 (should fix GitHub issues #98, #91, #89, + #90, #62, #65)
+ - Fix all checks with QT_VERSION (using macro QT_VERSION_CHECK), should fix checks from Qt 5.10 to + Qt 5.15 (GitHub issue #81)
+
+ +

Changes in version 1.4.8:

+
+ - Support Qt6 (tested with MSVC 2019 + CMake 3.19 on Windows) ==> QxOrm library is compatible + with Qt4, Qt5 and Qt6
+ - Support PIMPL idiom for persistent classes (useful to reduce compilation times, to provide a + stable ABI, ascendant compatibility for shared libraries, to reduce binaries size)
+ - Documentation about PIMPL idiom for persistent classes : + https://www.qxorm.com/qxorm_en/manual.html#manual_455
+ - New sample project named qxBlogPImpl in ./test/ directory of QxOrm package to show how to + implement persistent classes using the PIMPL idiom
+ - Possibility to ignore soft delete behavior during a session execution (useful to fetch logical + deleted instances for example) : qx::QxSession::ignoreSoftDelete()
+ - Fix SQL DISTINCT keyword in qx::QxSqlQuery class (when DISTINCT is used, then the primary key is + not fetched)
+ - Fix an issue which could happen after enabling _QX_ENABLE_QT_NETWORK compilation option (due to + QT_NO_SSL/QT_NO_OPENSSL used in QxThread.cpp file)
+ - Fix an issue in qx::QxSqlDatabase and multi-thread context when a thread identifier is reused + (GitHub issue #42)
+ - Add new behavior to qx::QxSession class with setAutoRollbackWhenDestroyed() option : if true, then + database rollback is called when session instance destructor (or close() method) is invoked (instead + of commit by default, GitHub issue #43)
+
+ +

Changes in version 1.4.7:

+
+ - Fix a MongoDB issue with qx::dao::fetch_by_id_with_relation() (wrong id fetched)
+ - Fix an issue with qx::dao::fetch_all when a custom list of columns with the primary key is + used
+ - Fix identifier JSON serialization for MongoDB with properties registered as Q_PROPERTY (Qt + property meta system)
+ - Fix a crash (seg fault) using qx::IxPersistable with multiple inheritance (for example QObject + + qx::IxPersistable) due to some static_cast to void * in QxFactory module (fix also for QxService + module and multiple inheritance)
+ - Remove automatic relationship lazy fetch when not requested in query
+ - Fix an issue with QJson and QDataStream serialization when class doesn't contain any identifier + (so not a database class) and is a wrapper of another registered class (can have same address + pointer as parent)
+ - Improve qx::QxSqlQuery::freeText() method to add custom text to build SQL query : support + placeholders (add second parameter const QVariantList & values)
+ - Improve performance in a multi-threads environment (mutex in qx::IxSqlQueryBuilder)
+ - New setting to display more details (execution times) in qx::dao functions logs (to enable this + new feature : qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true))
+ - Improve MongoDB integration to fetch a list of items : build C++ instances as soon as possible + without putting data in a buffer (better performance + less memory usage)
+ - Improve MongoDB integration : support qx::dao::delete_by_query() function with MongoDB aggregation + framework
+ - Improve qx::QxSqlQuery class (or its qx_query alias) : new addJoinQuery() method to insert SQL + sub-queries inside LEFT OUT JOIN / INNER JOIN (more details in documentation here : + https://www.qxorm.com/qxorm_en/manual.html#manual_3855)
+ - Improve qx::QxSqlQuery class : new constructors with placeholders support + new methods to embed + SQL sub-queries (in_Select, notIn_Select, isEqualTo_Select, isNotEqualTo_Select)
+ - Improve qx::QxCollection class : qx::QxCollection is now a thread-safe container (fix for example + QxModelView module when model is fetched in a different thread than the view)
+
+ +

Changes in version 1.4.6:

+
+ - New QxHttpServer module : C++/Qt standalone multi-threaded HTTP 1.1 web server (support SSL/TLS, + persistent connections, cookies, sessions, chunked responses, URL dispatcher/routing, no other + dependency except QtNetwork) : https://www.qxorm.com/qxorm_en/manual.html#manual_96
+ - New QxRestApi module : provide a REST API to send requests in JSON format from external + application (web services), from web-site (written in Angular for example), from QML or from + scripting langage (like Python) : https://www.qxorm.com/qxorm_en/manual.html#manual_97
+ - With QxHttpServer and QxRestApi modules, QxOrm library can now be used to create web applications, + especially single-page applications (SPA) with famous Javascript frameworks like AngularJS, React, + Meteor.js, etc...
+ - New project example named qxBlogRestApi : QML application with a list of REST requests to show how + to send JSON queries from Javascript to QxRestApi module + HTTP web server application to show how + to create web applications using QxHttpServer module
+ - QxRestApi module supports : all CRUD operations, complex queries, several levels of relationships, + custom JSON output format, call dynamically native C++ functions registered in QxOrm context, + instance validation, call custom database queries
+ - Improve JSON serialization engine : possibility to define a custom filter to not export all + properties (https://www.qxorm.com/qxorm_en/manual.html#manual_606)
+ - Possibility to define a custom SQL table alias for complex queries with relationships using syntax + <my_table_alias> (https://www.qxorm.com/qxorm_en/manual.html#manual_3850)
+ - Improve SQL generator for Oracle database : manage last insert id using RETURNING INTO syntax (thx + to Romain Macureau and Abdennour Boutrig)
+ - Fix an issue with stored procedure and output parameters
+ - New function available : qx::dao::count_with_relation<T>()
+ - Fix JSON serialization in multi-thread environment
+ - Change JSON QDateTime and QTime serialization format : use Qt::ISODateWithMs instead of + Qt::ISODate (Qt 5.8 or +)
+ - Improve QxService module : support SSL/TLS secure connections + keep-alive connections
+ - Remove *.suo files (MSVC++ temporary project files) from QxOrm package
+
+ +

Changes in version 1.4.5:

+
+ - Support MongoDB database : QxOrm library becomes a C++/Qt Object Document Mapper ODM library !
+ - For more details about MongoDB integration, see QxOrm manual + (https://www.qxorm.com/qxorm_en/manual.html#manual_95) and new sample project available in + ./test/qxBlogMongoDB/ directory
+ - QxOrm library is now available on GitHub (official repository) : + https://github.com/QxOrm/QxOrm
+ - Fix an issue in qx::IxSqlQueryBuilder class when QxOrm library is used in a multi-thread + environment
+ - Support latest version of boost (1.66)
+ - Update boost portable binary serialization classes to version 5.1 (provided by + https://archive.codeplex.com/?p=epa)
+ - Fix an issue building SQL query for Oracle database (doesn't support AS keyword for table + alias)
+ - Improve qx::QxClassX::registerAllClasses() function : possibility to initialize all relations + (useful to work with introspection engine)
+ - Improve qx::IxPersistable interface : provide new methods toJson() / fromJson()
+ - Improve documentation/website : change http://www.qxorm.com by https://www.qxorm.com + everywhere
+ - Fix fetching relations with soft delete putting SQL condition in the JOIN part instead of WHERE + part
+ - Fix SQL generator for Oracle database : use new limit/pagination syntax (version Oracle > + 12.1)
+ - Improve SQL generator interface : add 'onBeforeSqlPrepare()' method to modify/log SQL queries in + custom classes
+ - Add an option in qx::QxSqlDatabase class to format SQL query (pretty-printing) before logging it + (can be customized creating a qx::dao::detail::IxSqlGenerator sub-class)
+ - Fix an issue with boost/std::optional (to manage NULL database values) and some databases : if + optional is empty, then create a NULL QVariant based on QVariant::Type
+ - Add an option in qx::QxSqlDatabase class to insert square brackets (or any other delimiters) in + SQL queries for table name and/or column name (to support specific database keywords)
+ - Improve introspection engine : add getType() method in qx::IxDataMember interface to get C++ type + of a property dynamically
+ - Improve qx::QxSqlDatabase singleton settings class to make easier working with several databases : + now there are 3 levels of settings : global >> per thread >> per database (see + 'bJustForCurrentThread' and 'pJustForThisDatabase' optional parameters in all setXXXX() methods)
+ - Fix QxOrm.pri for MinGW compiler on Windows : an issue could occurred to export some symbols from + shared library (some Qt signals for example)
+ - Add an option in qx::QxSqlDatabase singleton class to display only slow SQL queries (see + setTraceSqlOnlySlowQueriesDatabase() and setTraceSqlOnlySlowQueriesTotal() methods)
+
+ +

Changes in version 1.4.4:

+
+ QxOrm library doesn't depend on boost framework anymore (the boost dependency has been fully + removed, replaced by some C++11 features).
+ So QxOrm library is now a pure Qt library which depends only on QtCore and QtSql by default.
+ For backward compatibility, QxOrm library still supports some boost classes (boost smart-pointers, + unordered containers, boost::optional, etc...) : you have to define _QX_ENABLE_BOOST compilation + option to enable these features.
+
+ Main advantages are :
+ - QxOrm becomes a much lighter library
+ - easier to install (because you don't have to deal with boost anymore)
+ - reduce compilation times
+ - reduce output binary size
+
+ Thx also to Jimmy Taker for several improvments and new features in QxModelView module !
+
+ - QxOrm library now requires a C++11 compiler (please note that QxOrm doesn't require a full + compliant C++11 compiler : for example, QxOrm can be built and used with MSVC 2012, GCC 4.5 or Clang + 3.2)
+ - Implement PIMPL idiom for some QxOrm classes to reduce compilation times and output binary + size
+ - New class named qx::any to replace boost::any (basic implementation of boost::any written by + Kevlin Henney)
+ - qx_shared_ptr alias doesn't exist anymore : it is replaced everywhere by std::shared_ptr
+ - QxModelView module : all models based on qx::IxModel class can now be sorted (on all columns), + please note that you can also use QSortFilterProxyModel Qt class to sort your model
+ - QxModelView module - qx::QxModel<T> : fix setData() with e_auto_update_on_field_change + option when an error occurred saving data in database, now previous value is restored if an error + occurred
+ - QxModelView module - qx::IxModel : fix setHeaderData() using it with default role (Qt::EditRole) + changes the header in a header view (role Qt::DisplayRole)
+ - QxModelView module - qx::IxModel : if a description is registered in QxOrm context, then it is + displayed in header for each property
+ - QxModelView module : new feature available to add automatically an empty row at the end of the + table to insert quickly new items (setShowEmptyLine() method)
+ - QxModelView module : possibility to define an intermediate base class between qx::IxModel and + qx::QxModel<T> to provide your own model features, for example imagine you develop a drag&drop + feature in a class named IxModelDragDrop, you can now create a QxOrm model like this (see the second + template parameter) : qx::IxModel * pModel = new qx::QxModel<MyPersistantClass, + IxModelDragDrop>();
+ - QxOrm.pro : fix DESTDIR parameter on Windows
+ - QxOrm.pri and QxOrm.cmake : add a section to enable QT_USE_QSTRINGBUILDER to optimize QString + operations
+ - QxOrm library is now tested with MSVC 2015 compiler (support all MSVC versions from 2012)
+ - Fix a bug in QxSqlError.h file with a qPrintable() call on a temporary object
+ - Provide more details in logs after executing a SQL query : time to execute query in database + + time to fetch C++ instances
+ - Support std::optional<T> (if your compiler supports C++17 features) to manage NULL database + value : new header available named <QxExtras/QxStdOptional.h> to include just after + <QxOrm.h> header file (ideally in a precompiled header)
+
+ +

Changes in version 1.4.3:

+
+ - Support CMake : new CMakeLists.txt file added to build QxOrm library with CMake
+ - Improve SQL error messages when qx::dao functions return a database error
+ - New parameter in singleton class qx::QxSqlDatabase to log SQL bound values + (setTraceSqlBoundValues) : by default, bound values are logged when an error occurred
+ - New syntax to select columns to not fetch : -{ col_1, col_2, etc... }
+ - New function qx::dao::call_query_without_prepare() to execute specific SQL queries without + prepared statement
+ - Improve QxModelView module : all QxOrm models (based on qx::IxModel interface) can be serialized + to JSON format (including all relationships levels) : this is now another way to work with + relationships and QML (thanks to JSON.parse() and JSON.stringify() javascript functions) without + using nested models concept (so without using QxEntityEditor model/view generated classes)
+ - Improve qxBlogModelView sample project and QxOrm manual to show how to access to relationships + data in QML (nested models or JSON)
+ - Fix a memory leak in qx::QxSqlRelation class
+ - Reduce output binary size (~20%) and compilation times (~20%) to build persistent classes based on + QxOrm library
+ - Support unity build concept to reduce compilation times to build QxOrm library and C++ persistent + classes generated by QxEntityEditor application : for more details, see _QX_UNITY_BUILD compilation + option in QxOrm.pri or QxOrm.cmake configuration file
+ - Improve QxConvert module : possibility to store in database complex QVariant properties which + contain QVariantMap, QVariantHash or QVariantList types (JSON format)
+ - Fix an issue with some databases when a foreign key is also a part of the primary key
+ - Fix an issue with QSharedPointer and boost::serialization when a same raw pointer is shared by + several QSharedPointer during deserialization process
+
+ +

Changes in version 1.4.2:

+
+ - Support JSON serialization : each C++ class registered in QxOrm context can be + serialized/deserialized in JSON format (JSON feature requires Qt5)
+ - For more details about JSON serialization, read QxOrm manual here : + https://www.qxorm.com/qxorm_en/manual.html#manual_606
+ - With JSON serialization and QxService module : it is now possible to create REST Web Services to + send data to a javascript engine (web pages for example)
+ - Fix some compilation errors with recent (and less permissive) compilers and latest versions of + boost and Qt
+ - Fix relationship initialization assertion with complex, deep and circular relationships in large + database schema
+ - Improve QDataStream serialization : should be faster now and fix an issue with circular instances + dependencies
+ - Fix a bug fetching 1-n and n-n relationships when root is a container of stack objects (it worked + only with pointers or smart-pointers, for example : QList<blog> vs + QList<std::shared_ptr<blog>>)
+ - Improve qx::dump() function : possibility to display a C++ instance state in XML or JSON + format
+
+ +

Changes in version 1.4.1:

+
+ !!! IMPORTANT NOTE ABOUT THIS VERSION !!! : it is strongly recommended to read the QxOrm.pri + configuration file of this new version (compilation options have changed compared to previous + versions).
+ Now, by default, QxOrm library is a much lighter library : QxOrm depends only on QtCore and + QtSql (boost serialization is now optional and not required by default).
+ By default, serialization engine is now based on Qt QDataStream class (but you can still enable + boost serialization defining _QX_ENABLE_BOOST_SERIALIZATION compilation option in QxOrm.pri + configuration file).
+ So now, with default options :
+ - QxOrm 1.4.1 is much easier to install because you don't have to deal with boost serialization + extra dependency ;
+ - QxOrm 1.4.1 shared library is 3X smaller than 1.3.2 version ;
+ - Generated binaries which depends on QxOrm library are 25% smaller ;
+ - If you are not using serialization functions in current projects based on QxOrm library, then you + can define or not _QX_ENABLE_BOOST_SERIALIZATION compilation option without changing any line of + your source code.
+
+ Here are all other changes of version 1.4.1:
+ - Improve relationships engine : possibility to select columns to fetch using syntax : my_relation { + col_1, col_2, etc... }
+ - Improve QxTraits module to reduce compilation times and build smaller binaries
+ - Improve QxOrm website adding possibility to search and replacing the old FAQ by a more organized + manual (user guide)
+ - New compilation option _QX_ENABLE_BOOST_SERIALIZATION to enable boost serialization dependency + (read QxOrm.pri configuration file for more details)
+ - New compilation option _QX_ENABLE_QT_NETWORK to enable QxService module (transfer persistent layer + over network) : read QxOrm.pri configuration file for more details
+ - New compilation option _QX_NO_RTTI to build QxOrm library without C++ RTTI type information
+ - Support QDataStream Qt serialization engine (used by default when _QX_ENABLE_BOOST_SERIALIZATION + compilation option is not defined)
+ - Improve qx_query class (SQL queries) : new method (named customOperator()) which gives the + possibility to define a custom operator (for example <@ for PostgreSQL ltree type)
+ - Fix a program startup issue due to 'static initialization order fiasco' creating singletons (it + was an issue with some compilers during the shared library link process)
+ - New namespace qx::dao::throwable : same functions as qx::dao namespace, but they throw a + qx::dao::sql_error exception when a SQL error occurred (instead of returning a QSqlError + instance)
+ - Add a qAssertMsg() macro to put a more explicit error message when throwing an assertion
+ - Include all *.inl files (template implementation) in QxOrm.pro project file : QtCreator can now + index these *.inl files in its project treeview
+ - Rename QxStringCvt to QxConvert : so if you persist custom types to database, you have to rename + from QxStringCvt_FromVariant, QxStringCvt_ToVariant to QxConvert_FromVariant, + QxConvert_ToVariant
+
+ +

Changes in version 1.3.2:

+
+ - Support C++11 types (need to set compilation options in QxOrm.pri config file to enable these + features)
+ - With _QX_CPP_11_SMART_PTR compilation option : std::unique_ptr, std::shared_ptr, std::weak_ptr
+ - With _QX_CPP_11_CONTAINER compilation option : std::unordered_map, std::unordered_set, + std::unordered_multimap, std::unordered_multiset
+ - With _QX_CPP_11_TUPLE compilation option : std::tuple
+
+ +

Changes in version 1.3.1:

+
+ - New class qx::QxModelService<T, S> in QxModelView module to connect a Qt model to services + to execute client-server requests (can be used with QML and QtWidgets views)
+ - Add some useful methods to qx::IxModel class and fix several issues with the QxModelView + module
+ - Support last version of MinGW with large precompiled header bug : new compilation option + _QX_NO_PRECOMPILED_HEADER (to enable in QxOrm.pri file)
+ - Fix issue when loading several shared libraries on Windows with services registered in QxService + module
+ - Fix the qx::QxSqlQuery serialization process used by QxService module to send requests over + network
+ - Fix an issue with qx::QxCollection<Key, Value> class when inserting an item at last + position
+
+ +

Changes in version 1.2.9:

+
+ - Improve nested models in QxModelView module to be able to use several relationships levels in + QML
+
+ +

Changes in version 1.2.8:

+
+ - New function qx::model_view::create_nested_model (QxModelView module) used by QxEntityEditor to + manage complex data structure to work with relationships in QML views and Qt model/view + architecture
+ - New section in the QxOrm.pri file with some tips to reduce output binaries size
+ - Fix the call of triggers to have the inserted ID inside the trigger function with PostgreSQL
+
+ +

Changes in version 1.2.7:

+
+ - New module QxModelView : now, all classes registered into QxOrm context can be used with Qt + model/view architecture (Qt widgets and/or QML views)
+ - qx::IxModel interface provides an easy way to work on QML with QxOrm library and interact with + databases
+ - For more details about the new module QxModelView, goto the FAQ : 'How to use QxModelView module + to interact with Qt model/view architecture (Qt widgets and/or QML views) ?'
+ - New function qx::dao::save_with_relation_recursive(), useful to save a full tree structure for + example
+ - Remove the dependency on the STL compatibility functions in Qt (QT_NO_STL), which may not be + available (thanks to KDE Plasma Media Center team for the patch)
+ - Support database table defined into a schema (using qx::IxDataMember::setName() function)
+
+ +

Changes in version 1.2.6:

+
+ - First version full compatible with QxEntityEditor application : the graphic editor for QxOrm + library !
+ - For more details about QxEntityEditor, go to QxOrm website : https://www.qxorm.com/
+ - Thanks to the recent release of Qt 5.2, QxOrm library can now be used on Android and iOS
+ - Improve relationships and triggers engine
+ - Triggers onBeforeFetch() and onAfterFetch() called when fetching relationships
+ - Fix release mode detection during compilation : should improve performance on some + environments
+ - Add serialization for QSqlError, qx::QxSqlQuery, qx::QxInvalidValue and qx::QxInvalidValueX + classes
+
+ +

Changes in version 1.2.5:

+
+ - New license : go to download page of QxOrm website for more details
+ - Support Qt5
+ - New compiler supported : Clang (tested on Mac OS X)
+ - Now each QxOrm version will be tested in 32-bit and 64-bit mode
+ - Improve QxOrm introspection engine : possibility to register static class methods
+ - Improve QxService module : now it's easy to add an authentication process on server side
+ - New class qx::exception to get error code + error description with services methods throwing an + exception
+ - New settings available in QxOrm.pri config file (whithout changing QxConfig.h file)
+ - Possibility to implement specifics database SQL functions overriding qx_query class
+ - Fix an issue when fetching multiple levels of relationship and NULL pointers
+ - Fix a bug with MS SQL Server database and update queries using auto-increment id
+
+ +

Changes in version 1.2.4:

+
+ - New relationship engine to fetch easily many levels of relationships per query
+ - For more details about this new engine, goto the FAQ : 'How to use relationship engine to fetch + datas from many tables ?'
+ - Add 2 functions : qx::dao::execute_query and qx::dao::call_query to call a stored procedure or a + custom SQL query
+ - For more details about this new feature, goto the FAQ : 'How to execute a stored procedure or a + custom SQL query ?'
+ - Add support for boost::optional type to manage NULL database value without using QVariant type
+ - New class : qx::QxDaoAsync to make easier to execute queries in asynchronous way + (multi-thread)
+ - For more details about this new class, goto the FAQ : 'How to use qx::QxDaoAsync class to execute + queries in asynchronous way (multi-thread) ?'
+
+ +

Changes in version 1.2.3:

+
+ - New interface 'qx::IxPersistable' (abstract class) to simplify polymorphism using QxOrm + library
+ - For more details about this new interface, goto the FAQ : 'How to use qx::IxPersistable interface + ?'
+ - New methods into 'qx::IxCollection' interface to iterate over each items without knowing its + type
+ - New option into 'QxOrm.pri' file to build QxOrm library statically (see '_QX_STATIC_BUILD' + option)
+ - New triggers : 'qx::dao::on_before_fetch' and 'qx::dao::on_after_fetch' (for more details, goto + the FAQ : 'How to define a Trigger with QxOrm ?')
+ - Add 'std::type_info' class information to introspection engine
+ - Some minor bugs fixed ('qx::dao::sql_error' exception message, SQL query column alias, mutex, + etc.)
+
+ +

Changes in version 1.2.2:

+
+ - New module to provide a validation engine : QxValidator module
+ - For more details about QxValidator module, goto the FAQ of QxOrm library : 'How to use QxValidator + module to validate automatically an instance ?'
+ - Fix last insert ID with PostgreSQL using 'RETURNING' keyword : fetch inserted ID instead of + OID
+ - Improve SQL generator providing the good SQL type for all databases
+ - Add support for special database keywords using '[', ']' and '"' characters
+
+ +

Changes in version 1.2.1:

+
+ - Improve 'qx::QxSqlQuery' class : new engine to build queries without writing SQL, for more + details, see the FAQ 'How to build a query without writing SQL with the class qx::QxSqlQuery ?'
+ - Improve 'qx::QxSession' class : provide persistent methods (CRUD) without using 'qx::dao::xxx' + functions, for more details, see the FAQ 'How to use a session (qx::QxSession class) to manage + automatically database transactions (using C++ RAII) ?'
+ - Implement 'repository' pattern to provide a common interface for persistent methods (CRUD) with 3 + new classes : 'qx::IxRepository', 'qx::QxRepository<T>' and 'qx::QxRepositoryX'
+ - Possibility to serialize a QVariant 'UserType' with serialization engine of QxOrm library
+ - Improve thread-safe 'qx::cache' : add insertion date-time into the cache to verify that an element + must be updated or not, for more details, see the FAQ 'How to use the cache (functions into + namespace qx::cache) of QxOrm library ?'
+ - FAQ updated on QxOrm website with now 28 questions and answers
+
+ +

Changes in version 1.1.9:

+
+ - Possibility to register automatically Qt meta-properties (using Q_PROPERTY macro) to QxOrm context + without writing mapping function per class (void qx::register_class<T>())
+ - Strong integration with Qt introspection/moc engine : for more details about this new feature, + goto the FAQ 'How to register automatically Qt meta-properties to QxOrm context ?'
+ - Improve introspection/reflection engine : see the FAQ (How to use introspection engine (or + reflection engine) of QxOrm library ?) for more details
+ - Possibility to add meta-data (using a property bag) to introspection engine : see 'IxClass', + 'IxDataMember' and 'IxFunction' classes for more details
+ - Add function 'qx::QxClassX::dumpSqlSchema()' to explain how to create your own SQL schema based on + C++ classes
+ - New class 'qx::QxSimpleCrypt' to provide encryption/decryption (thanks very much to Andre Somers) + : so it's now possible to store encrypted data into database without using an external library
+ - QxService module : new feature to encrypt/decrypt data before transfering it over network
+
+ +

Changes in version 1.1.8:

+
+ - QxOrm library can now be used on Mac (thanks very much to Dominique Billet) : see + 'osx_build_all_debug.sh' and 'osx_build_all_release.sh' scripts to build QxOrm library and all + samples in './test/' directory
+ - Add 'qx::QxSession' class : define a session to manage automatically database transactions (using + C++ RAII), see the FAQ for more details
+ - Add 'qx::QxDateNeutral', 'qx::QxTimeNeutral' and 'qx::QxDateTimeNeutral' classes : helper classes + to store date-time value into database under neutral format => cross database compatibility
+
+ +

Changes in version 1.1.7:

+
+ - Add soft delete behavior : see the FAQ (How to define a soft delete behavior ?) for more details + about this new feature
+ - Add functions into namespace 'qx::dao' to update an element with a SQL condition : + update_by_query, update_optimized_by_query, etc.
+ - Fix a bug when QVariant type is used for a property of a persistent class : so, it's now possible + to insert NULL value into database
+
+ +

Changes in version 1.1.6:

+
+ - QxOrm library online documentation available : 'https://www.qxorm.com/doxygen/index.html'
+ - Possibility to disable QtGui dependency using compilation option in 'QxConfig.h' file : + _QX_ENABLE_QT_GUI_DEPENDENCY
+ - Possibility to disable QtNetwork dependency (so QxService module too) using compilation option in + 'QxConfig.h' file : _QX_ENABLE_QT_NETWORK_DEPENDENCY
+ - Provide a new macro to register abstract class into QxOrm context : + QX_REGISTER_ABSTRACT_CLASS()
+
+ +

Changes in version 1.1.5:

+
+ - New feature available : 'QxService' module to create C++ application server
+ - 'QxService' provides an easy and powerful way to create services and to transfer data over + network
+ - New tutorial available to explain how 'QxService' module works
+ - New sample available at './test/qxClientServer' directory
+ - QxOrm can be built with 'CONFIG += no_keywords' flag in '*.pro' files
+ - Bug fix with 'qx::dao::create_table<>' function and relation 'many-to-many'
+ - QxOrm should now build fine with GCC <= 4.2
+
+ +

Changes in version 1.1.4:

+
+ - New parameter in functions 'qx::dao::fetch_by_id', 'qx::dao::fetch_all', 'qx::dao::fetch_by_query' + and 'qx::dao::update' to define a list of properties to fetch/update (by default, all properties are + fetched/updated)
+ - Support multi-columns primary key (composite key) : see sample './test/qxBlogCompositeKey/'
+ - Improve strategy of inheritance : QxOrm supports 'Concrete Table Inheritance' strategy ('Concrete + Table Inheritance' becomes default strategy)
+ - New smart-pointer 'qx::dao::ptr<T>' based on Qt 'QSharedPointer<T>' to provide 2 new + features : 'is dirty' and 'update optimized'
+ - 'qx::dao::ptr<T>' can be used with a simple object and with many containers (stl, boost, Qt + and 'qx::QxCollection' containers)
+ - 'qx::dao::ptr<T>' keeps original values from database and provides a 'isDirty()' method to + retrieve all properties changed
+ - 'qx::dao::update_optimized' must be used with 'qx::dao::ptr<T>' to save into database only + properties changed
+
+ +

Changes in version 1.1.3:

+
+ - This version works fine with MinGW on Windows
+
+ +

Changes in version 1.1.2:

+
+ - License LGPL
+ - Fix compilation problems on Linux and boost > 1.38
+ - Fix sql query with MySql database
+ - Disable assert when qx::dao functions return an error
+
+ +

Changes in version 1.1.1:

+
+ - This version supports Visual Studio 2010
+
+ +

Changes in version 1.1.0:

+
+ - First release
+
+

+
+ Historique des modifications de l'application QxEntityEditor : + + + + + + + +
+ +

Changes in version QxEntityEditor 1.2.8:

+
+ - New export plugin 'QxEESourceControlExport' : export a *.qxee QxEntityEditor project file to a + list of JSON files which can be easily check-in in a source control repository (Git, Perforce, CVS, + etc...)
+ - New import plugin 'QxEESourceControlImport' : import a list of JSON files (generated using + 'QxEESourceControlExport' export plugin) inside a *.qxee QxEntityEditor project file
+ - These 2 new plugins allow a team development to work simultaneously on a same *.qxee + QxEntityEditor project file
+ - A typical workflow could be (with 2 developers named dev A and dev B) :
+ * dev A and dev B work on a same *.qxee QxEntityEditor project file
+ * dev A create/modify/change some entities in QxEntityEditor application
+ * dev B create/modify/change other entities in QxEntityEditor application
+ * dev A and dev B export the *.qxee project file using the new 'QxEESourceControlExport' export + plugin
+ * Once exported, dev A and dev B check-in the JSON files inside the source control manager (Git, + Perforce, CVS, etc...) on their own branch
+ * dev A and dev B integrate from their own branch to the DEV (or MAIN or MASTER) branch (if there + are some conflicts to resolve, it should be easy because JSON files are easy to read and + understand)
+ * dev A and dev B can now get latest JSON files from the DEV (or MAIN or MASTER) branch : these JSON + files contain both modifications from dev A and dev B
+ * dev A and dev B can import these JSON files inside QxEntityEditor application using the new + 'QxEESourceControlImport' import plugin
+ - These 2 new plugins can be executed using command line (like all other QxEntityEditor plugins), + here are 2 examples :
+ * Export : QxEntityEditor --no_gui --project="C:\Temp\qxBlog.qxee" --plugin=QxEESourceControlExport + --QxEESourceControlExport_path="C:\Temp\source_control\"
+ * Import : QxEntityEditor --no_gui --project="C:\Temp\qxBlog.qxee" --plugin=QxEESourceControlImport + --QxEESourceControlImport_path="C:\Temp\source_control\qxBlog.qxee.export.json"
+
+ +

Changes in version QxEntityEditor 1.2.7:

+
+ - Fix an issue with MySQL database schema import process when MySQL server is configured to answer + with column names in UPPERCASE (may fix other imports depending on specific database + configuration)
+
+ +

Changes in version QxEntityEditor 1.2.6:

+
+ - Support PIMPL (private implementation or d-pointer) idiom in the C++ export plugin
+ - Documentation about PIMPL idiom for persistent classes : + https://www.qxorm.com/qxorm_en/manual_qxee.html#cpp_export_settings_parameters
+ - Fix import database schema for PostgreSQL version 12 and +
+ - Fix some assertions on macOS and linux versions due to libavoid library compiled without NDEBUG + compilation option (should improve performance too)
+ - Add CMake 'target_precompile_headers' command for generated CMakeLists.txt files to support + precompiled headers building with CMake (reduce compilation times)
+
+ +

Changes in version QxEntityEditor 1.2.5:

+
+ - Fix an issue with fonts on macOS Catalina 10.15
+ - Add command line parameter --font : define application font with syntax + <family>||<pointSize>||<weight>||<italic> (only <family> is required), + for example : Courier New||14
+ - Add command line parameter --style_sheet : define application style sheet (more details here : + https://doc.qt.io/qt-5/stylesheet-reference.html), for example : QWidget { background-color: black + }
+ - Fix meta-data (property bag) C++ export : keep same order between several C++ exports (this is now + easier to check differences between 2 C++ exports using WinMerge or any other comparison/diff + tool)
+
+ +

Changes in version QxEntityEditor 1.2.4:

+
+ - New feature in Javascript engine to customize exports : include QxRestApi module to query *.qxee + project file
+ - Fix a property/relation sorting issue in C++ export after importing a database schema (which could + be annoying to make some C++ files diffs between 2 exports)
+ - Fix a crash which could occurred sometimes importing a new table on an existing schema
+
+ +

Changes in version QxEntityEditor 1.2.3:

+
+ - Fix a crash which appears sometimes with complex database schema to draw relationships (orthogonal + way)
+ - Improve QxEntityEditor command line parameters : possibility to import/export without using GUI + (useful to manage a Jenkins server for example)
+ - For more details about command line parameters, go to QxEntityEditor documentation : + https://www.qxorm.com/qxorm_en/manual_qxee.html#qxee_command_line
+
+ +

Changes in version QxEntityEditor 1.2.2:

+
+ - Fix an issue after importing a project (from database or JSON file) which forced user to refresh + or reload current project
+ - Improve performance (fetching less data from database) when loading relationships from generated + persistent classes (bLoadFromDatabase parameter)
+ - Change model/view export plugin to take into account some improvments available in the new version + of QxOrm library
+ - Support changes of new QxOrm version : remove boost dependency by default and enable C++11 + features
+ - Improve Javascript engine to customize exports : add 3 functions available in js script to get all + QxEntityEditor settings (at global level, project level and plugin level)
+ - Check entities schema before exporting to C++ project : if a design error is detected, then + display a message to user
+ - Fix SQL type field in property settings : now you can put parenthesis (for example VARCHAR(255) is + now allowed)
+ - DDL export for MySQL (and MariaDB) : add ` character to escape column name and table name
+ - Add full path to project in recent projects list and main window title bar
+ - Now it is easier to select a relationship from entities diagram with a simple click on it
+
+ +

Changes in version QxEntityEditor 1.2.1:

+
+ - Support CMake : each C++ project generated by QxEntityEditor (persistent classes, services, + model/view) provide a CMakeLists.txt file to build with CMake
+ - New online QxEntityEditor manual (user guide) available at : + https://www.qxorm.com/qxorm_en/manual_qxee.html
+ - Improve Javascript engine to customize export generated files : add a parameter named + 'output_location' to know where generated files are located + add functions to get a list of all + entities/enums of a project (see ./samples/custom_script.js file for more details)
+ - Improve database import process (SQLite, MySQL/MariaDB, PostgreSQL, Oracle and MSSQLServer) : fix + an issue importing composite foreign keys + foreign keys embedded in primary key ==> so it is now + possible to import more complex database schema
+ - Improve DDL database schema export process : fix an issue with 1-1 relationship + manage composite + keys
+ - New menu "Naming convention" to provide a fast way to rename all entities/properties/enums + (without breaking mapping to database) : support snake_case, camelCase and PascalCase (or upper + camel case), this new menu can be useful after an import from database process for example
+ - Each screen of QxEntityEditor provides now a fast access to the online manual (user guide) in its + associated topic (new button "Documentation" + shortcut pressing F1 key everywhere)
+ - New buttons undo/redo in the main QxEntityEditor toolbar to undo or redo actions done on entities, + enumerations, comments, layout (undo/redo feature can be disabled to improve performance on large + projects)
+ - Support _QX_UNITY_BUILD compilation option to reduce compilation times of generated C++ projects + (recommended with CMake which doesn't support natively precompiled headers)
+ - Fix an issue importing a relationship where target entity doesn't have a primary key
+ - Fix an issue with C++ services export plugin and JSON serialization : "Unable to create nude + pointer for input parameter"
+ - Fix an issue with abstract entities and C++ model/view export plugin and C++ services export + plugin
+ - Possibility to put hexadecimal values to define an enumeration
+ - New Javascript sample file in directory ./samples/ named q_property.js to show how to add + automatically Q_PROPERTY definition for each property generated by QxEntityEditor
+
+ +

Changes in version QxEntityEditor 1.1.9:

+
+ - New import plugin to connect to MySQL or MariaDB database without having to deal with ODBC + settings
+ - New import plugin to connect to PostgreSQL database without having to deal with ODBC settings
+ - New import plugin to load a QxEntityEditor project from a JSON file
+ - Fix SQLite import process to manage composite keys
+ - Improve Javascript engine to customize export process : new types available by script to manage + files and directories + possibility to get/set environment variables (read custom_script.js file in + ./samples/ directory for script examples)
+ - Improve Javascript engine to customize export process : new events/actions available by script : + PLUGIN_EXPORT_START, PLUGIN_EXPORT_END, AFTER_CLOSING_FILE
+ - New message box displayed if directory doesn't exist when starting an export process (to create it + automatically)
+ - Fix an issue with the "Tag project state" function (project historic) : each tag double the size + of a *.qxee project file (now each tag is optimized)
+ - Fix C++ services export process when C++11 features are enabled in QxOrm.pri configuration + file
+ - Possibility to export a *.qxee project file to a JSON text file (can be useful to store a text + representation in a source control, like Perforce, VSS, CVS, Git, etc...)
+ - Possibility to use an environment variable to define QxOrm library location (using the same syntax + as qmake, for example $$(QXORM_DIR))
+
+ +

Changes in version QxEntityEditor 1.1.8:

+
+ - Improve import plugins : reduce import process time : now, you can import hundred of entities in + few seconds into a QxEntityEditor project
+ - Relationship n-1 : possibility to define a database column name different than the relationship + name
+ - New file qxBlogExec.zip in the ./samples/ directory of QxEntityEditor package : this is a C++/Qt + example project which depends on the qxBlog.qxee generated files
+ - Improve import by ODBC plugin screen : new schema/namespace level in the list of tables/views + treeview
+ - Fix a performance issue to load large diagram with new style to draw relationships : you can now + load quickly a project with hundred of entities
+ - Add new C++11 types to manage relationships, decoration, collection (std::shared_ptr, + std::unordered_map and std::unordered_set) : C++11 features must be enabled in QxOrm.pri config file + to use these classes
+ - Import process more permissive : possibility to import tables without primary key and tables + without column
+
+ +

Changes in version QxEntityEditor 1.1.7:

+
+ - New Navigator window (under project treeview) : useful to navigate over large diagram
+ - New way to draw relationships (orthogonal lines between 2 entities) + display the relationship + type on each side (there is an option to use the old drawing style from previous version)
+ - Possibility to define a background color by namespace : useful to group all entities in the + diagram associated to a same namespace
+ - New feature to customize entities/enumerations/notes colors at several levels
+ - Define items colors at project level (menu Tools >> Project settings >> Colors + tab)
+ - Define items colors at namespace level (right-click on the diagram >> Define colors by + namespace)
+ - Define colors at item level : right-click on an item (entity, enumeration or comment) >> + Define item colors
+ - New action to organize automatically the diagram layout, useful after an import process for + example (menu View >> Organize diagram layout)
+ - Improve the DDL SQL export plugin : new option to export relationships as foreign keys constraints + in database
+ - Support the new compilation option _QX_NO_PRECOMPILED_HEADER of QxOrm library (workaround for a + known bug of recent versions of MinGW on Windows and large precompiled header)
+ - Import database by ODBC plugin : fix the import from MS SQL Server database when tables are not + located in the default schema (dbo)
+ - QxEntityEditor Mac OS X version : fix an issue to load the QxEEPrinter plugin
+ - Export plugin to C++ model/view project : new option to generate models based on the new QxOrm + library class qx::QxModelService<T, S> (models based on services to execute client-server + requests)
+
+ +

Changes in version QxEntityEditor 1.1.6:

+
+ - New javascript engine to customize the C++ and DDL SQL export process writing your own custom + script
+ - Integrated debugger to debug your own custom javascript files (for example, putting a breakpoint + or logging some traces)
+ - New plugin to print the entities diagram as a PNG image file and PDF file
+ - New property parameter UNIQUE (in property params window) used by the DDL SQL generator to create + the database schema
+ - Improve nested models in QxModelView module to be able to use several relationships levels in + QML
+ - Possibility to change the order in the list of properties and list of relationships of an + entity
+ - Change encoding of generated files : now files are UTF-8
+ - Possibility to put a relative path to the QxEntityEditor project file (*.qxee file) in each plugin + location settings
+
+ +

Changes in version QxEntityEditor 1.1.5:

+
+ - New C++ model/view export plugin to manage complex data structure to work with relationships in + QML views and Qt model/view architecture (using QxModelView module of QxOrm library)
+ - Now, with this new export plugin, working on QML with C++ entities has never been so easy !
+ - New function, menu "Tools >> Plugins scripts", to define your own custom scripts + before/after a plugin execution
+ - New command line parameter --log_sql to trace all SQL queries executed by QxEntityEditor : a + QxEntityEditor project file (*.qxee) is just a SQLite database, so it's easy to write your own + script to customize some default behaviour
+ - New option in the C++ export plugin to generate or not the custom directory with all custom files + for each entity
+ - Scrollbar available in the entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.4:

+
+ - Improve import by ODBC plugin to manage relationship, schema and composite key for SQLite, MySQL, + PostgreSQL, Oracle and MS SQL Server databases
+ - New import from SQLite plugin to import SQLite database structure into QxEntityEditor project + without having to create an ODBC DSN connexion
+ - Improve C++ export plugin : add a set of useful methods in generated classes + option to manage + relative path to QxOrm library
+ - New menu to rename a namespace (move all entities to another namespace) and delete a list of + entities by namespace
+ - Fix a bug when executing QxEntityEditor in command line (no GUI)
+ - Add a viewer mode to open a QxEntityEditor project with unlimited entities count without having a + license key (read-only mode)
+
+ +

Changes in version QxEntityEditor 1.1.3 (first official release):

+
+ - New plugin to transfer your data model over network and create quickly client/server applications, + using QxService module
+ - New options to define entity, enum and comment width in entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.2 (BETA):

+
+ - New plugin to generate DDL SQL script (database schema) for SQLite, MySQL, PostgreSQL, Oracle and + MS SQL Server databases
+ - The new DDL SQL plugin manages automatically schema evolution for each project version (ALTER + TABLE, ADD COLUMN, DROP INDEX, etc.)
+ - Add post-it or comments in the entities viewer
+ - Option to display or not property type in the entities viewer
+
+ +

Changes in version QxEntityEditor 1.1.1 (BETA):

+
+ - First BETA version of QxEntityEditor application
+ - Provide a graphic way to manage the data model for QxOrm library
+ - Multi-platform (available for Windows, Linux and Mac OS X) and generate native code for all + environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android, iOS, Windows Phone, + Raspberry Pi, etc.)
+ - Based on plugins and provides many ways to import/export the data model
+ - Generate C++ persistent classes automatically (registered into QxOrm context)
+
+

+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/download_details.php b/doc/qxorm_fr/download_details.php new file mode 100644 index 0000000..de2c9f3 --- /dev/null +++ b/doc/qxorm_fr/download_details.php @@ -0,0 +1,165 @@ + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor (data model designer and source code generator) + + + + + + + + + + + + + + + + +
QxOrm + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) +
+ +
+
+ Manuel (2) +
+ +
+
ForumNos clients
+
+ + + + + + + + + + +
QxOrm >> Informations sur le t�l�chargement + + + + + + + + + +
Version courante : QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub
QxEntityEditor 1.2.8
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + +
La biblioth�que QxOrm est disponible avec son code source et peut �tre utilis�e gratuitement en respectant les termes de la licence GNU General Public License (GPL) version 3. +

+ En associant (link) une application avec la biblioth�que QxOrm (directement ou indirectement, statiquement ou dynamiquement, � la compilation ou � l'ex�cution), votre application est soumise aux termes de la licence GPLv3 + qui demande � ce que vous publiez le code source de votre application si et quand vous la distribuez. Distribuer une application signifie la donner ou vendre � des clients, + des soci�t�s, filiales, ou tous autres entit�s l�gales diff�rentes de la votre. D'un autre c�t�, lorsque vous utilisez votre application dans votre organistation uniquement, + alors vous n'avez pas besoin de rendre votre code source public. +

+ Si vous ne souhaitez pas �tre limit� par les termes de la licence GPLv3, vous pouvez acqu�rir la licence QxOrm Proprietary License (QXPL).
+ Les avantages de la licence QxOrm Proprietary License sont : +
    +
  • Le code source de votre application reste priv� ;
  • +
  • Compatible avec toutes les autres licences commerciales et open-source ;
  • +
  • Possibilit� d'utiliser QxOrm sans livrer le code source de la biblioth�que aux utilisateurs ;
  • +
  • Possibilit� de conserver vos propres modifications � la biblioth�que QxOrm sans les d�voiler ;
  • +
  • Possibilit� de cr�er des produits sans mentionner QxOrm aux utilisateurs ;
  • +
  • Protection contre le reverse engineering du produit.
  • +
+
qt_ambassador
+ QxOrm library has been accepted into the Qt Ambassador Program +
+ La licence QXPL de la biblioth�que QxOrm est une licence par projet (ou par application), peu importe le nombre de d�veloppeurs travaillant sur le projet, et peu importe le nombre d'instances d�ploy�es de votre logiciel (royalty-free). + Par exemple, si vous d�veloppez 3 applications diff�rentes bas�es sur la biblioth�que QxOrm, alors vous devez acqu�rir 3 licences QXPL (une par projet).
+
+ Prix d'une licence QxOrm Proprietary License : 400€.
+
+ Pour toutes questions ou pr�cisions sur les licences, ou bien pour acqu�rir la licence QXPL, vous pouvez nous contacter � l'adresse suivante : ic-east.com.
+
+ T�l�charger QxOrm 1.5.0 +
+ +
+
+

+ + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + diff --git a/doc/qxorm_fr/faq.html b/doc/qxorm_fr/faq.html new file mode 100644 index 0000000..44f1926 --- /dev/null +++ b/doc/qxorm_fr/faq.html @@ -0,0 +1,3768 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Faq + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+ + qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ Qu'est-ce que QxOrm ?

+ + + + + + + + + +
+ QxOrm est une biblioth�que C++ open source de gestion de donn�es (Object Relational Mapping, + ORM).
+ QxOrm est d�velopp� XDL Teamarty, Ing�nieur en d�veloppement logiciel depuis 2003.
+
+ � partir d'une simple fonction de param�trage (que l'on peut comparer avec un fichier de + mapping XML Hibernate), vous aurez acc�s aux fonctionnalit�s suivantes : +
    +
  • + persistance : communication avec de nombreuses + bases de donn�es (avec support des relations 1-1, 1-n, n-1 et n-n) ; +
  • +
  • + s�rialisation des donn�es (flux binaire, XML + et JSON) ; +
  • +
  • moteur de r�flexion (ou introspection) pour acc�der aux classes, attributs + et invoquer des m�thodes. +
  • +
+ QxOrm est d�pendant des excellentes biblioth�ques boost (compatible � partir de la version 1.38) et Qt (compatible � partir de la version + 4.5.0).
+ La biblioth�que QxOrm a �t� retenue pour faire partie du programme Qt + Ambassador. +

+
+
+ Qu'est-ce que QxEntityEditor ?

+ + + + + + + + + +
+ QxEntityEditor est un �diteur graphique pour la biblioth�que QxOrm : + QxEntityEditor permet de g�rer graphiquement le mod�le d'entit�s.
+ QxEntityEditor est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et g�n�re du + code natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu� et mobile + (Android, iOS, Windows Phone, Raspberry Pi, etc.).
+ Une vid�o de pr�sentation de l'application QxEntityEditor est + disponible.
+
+ QxEntityEditor est bas� sur un syst�me de plugins et propose diverses fonctionnalit�s pour + importer/exporter le mod�le de donn�es : +
    +
  • g�n�ration automatique du code C++ (classes persistantes enregistr�es dans le contexte QxOrm) ; +
  • +
  • g�n�ration automatique des scripts SQL DDL (sch�ma de base de donn�es) pour les bases SQLite, + MySQL, PostgreSQL, Oracle et MS SQL Server ;
  • +
  • supporte l'�volution du sch�ma de base de donn�es pour chaque version d'un projet (ALTER + TABLE, ADD COLUMN, DROP INDEX, etc.) ;
  • +
  • g�n�ration automatique des classes C++ de services pour transf�rer le mod�le de donn�es sur le + r�seau, en utilisant le module QxService, pour cr�er rapidement des applications client/serveur ;
  • +
  • importation automatique des structures de bases de donn�es existantes (par connexion ODBC) pour + les bases SQLite, MySQL, PostgreSQL, Oracle et MS SQL Server ;
  • +
  • parce que chaque projet est diff�rent, QxEntityEditor propose plusieurs outils pour + personnaliser les fichiers g�n�r�s (notamment un moteur javascript et un d�bogueur int�gr�).
  • +
+ QxEntityEditor +

+ QxEntityEditor est d�velopp� XDL Teamarty, Ing�nieur en d�veloppement logiciel depuis 2003.
+

+
+
+ Comment contacter QxOrm pour indiquer un bug ou poser une question + ?

+ + + + + + + + + +
+ Si vous trouvez un bug ou si vous avez une question concernant le fonctionnement de la biblioth�que + QxOrm, + vous pouvez envoyer un mail � : support@qxorm.com.
+ Un forum (en anglais) d�di� � QxOrm est disponible en cliquant ici.
+ Vous pouvez �galement retrouver la communaut� fran�aise de QxOrm sur le forum de Developpez.com. +
+

+ Comment installer et compiler QxOrm ?

+ + + + + + + + + +
+ Un tutoriel pour installer un environnement de d�veloppement avec QxOrm + sous Windows est disponible en cliquant ici.
+
+ QxOrm utilise le processus qmake de la biblioth�que Qt pour g�n�rer les + makefile et compiler le projet.
+ qmake est multiplateforme et fonctionne parfaitement sous Windows, Linux (Unix) et Mac.
+ Pour compiler QxOrm, il suffit d'ex�cuter les commandes suivantes :
+
+ qmake
+ make debug
+ make release
+
+ Sous Windows, des fichiers *.vcproj et *.sln sont disponibles pour les �diteurs + Visual C++ 2008, Visual C++ 2010 et Visual C++ 2012.
+ Les fichiers *.pro sont lisibles par l'�diteur Qt Creator, et des plugins existent + permettant de s'interfacer avec de nombreux �diteurs C++.
+ Les fichiers mingw_build_all_debug.bat et mingw_build_all_release.bat pr�sents dans le + dossier ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests avec le + compilateur MinGW sous Windows.
+ Les fichiers gcc_build_all_debug.sh et gcc_build_all_release.sh pr�sents dans le dossier + ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests avec GCC sous + Linux.
+ Enfin, les fichiers osx_build_all_debug.sh et osx_build_all_release.sh pr�sents dans le + dossier ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests sous + Mac (merci � Dominique Billet pour l'�criture des scripts).
+
+ Remarque : suivant l'environnement de d�veloppement, il peut �tre n�cessaire de modifier le + fichier QxOrm.pri pour param�trer la configuration de la biblioth�que boost :
+
+ QX_BOOST_INCLUDE_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/include)
+ QX_BOOST_LIB_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/lib_shared)
+ QX_BOOST_LIB_SERIALIZATION_DEBUG = "boost_serialization-vc90-mt-gd-1_42"
+ QX_BOOST_LIB_SERIALIZATION_RELEASE = "boost_serialization-vc90-mt-1_42"
+
+

+ Quelles sont les bases de donn�es prises en compte par QxOrm ?

+ + + + + + + + + +
+ QxOrm utilise le moteur QtSql de Qt bas� sur un syst�me de plugin.
+ Une liste d�taill�e des bases de donn�es support�es est disponible sur le site de Qt en cliquant ici.
+ Le plugin ODBC (QODBC) assure une compatibilit� avec de nombreuses bases de donn�es.
+ Pour des performances optimales, il est conseill� d'utiliser un plugin sp�cifique � une base de + donn�es : +
    +
  • QMYSQL : MySQL ; +
  • +
  • QPSQL : PostgreSQL (versions 7.3 and above) ; +
  • +
  • QOCI : Oracle Call Interface Driver ; +
  • +
  • QSQLITE : SQLite version 3 ; +
  • +
  • QDB2 : IBM DB2 (version 7.1 and above) ; +
  • +
  • QIBASE : Borland InterBase ; +
  • +
  • QTDS : Sybase Adaptive Server. +
  • +
+
+
+ Pourquoi QxOrm est d�pendant de deux biblioth�ques : boost et Qt ?

+ + + + + + + + + +
+ QxOrm utilise de nombreuses fonctionnalit�s disponibles dans les excellentes biblioth�ques + boost et Qt.
+ De plus, ces deux biblioth�ques sont utilis�es dans de nombreux projets � la fois professionnels et + open-source.
+ Il existe un grand nombre de forums, de tutoriaux, et toute une communaut� pour r�pondre � toutes les + probl�matiques que vous pourriez rencontrer.
+ L'objectif de QxOrm n'est pas de red�velopper des fonctionnalit�s qui existent d�j� mais de + fournir un outil performant d'acc�s aux bases de donn�es + comme il en existe dans d'autres langages (Java avec Hibernate, .Net avec + NHibernate, Ruby, Python, etc.).

+ + + + + + + + + +
QtQt : biblioth�que compl�te : IHM + (QtGui), r�seau (QtNetwork), XML (QtXml), base de donn�es + (QtSql), etc.
+ La documentation est excellente et le code C++ �crit � partir + de cette biblioth�que est � la fois performant et simple de + compr�hension.
+ Depuis le rachat par Nokia puis Digia et sa nouvelle licence LGPL, Qt est + sans contexte la biblioth�que phare du moment.
+ QxOrm est compatible avec les principaux objets d�finis par Qt + : QObject, QString, QDate, QTime, QDateTime, QList, QHash, + QSharedPointer, QScopedPointer, etc.
+ Il est conseill� d'installer et d'utiliser la derni�re version + de Qt disponible � l'adresse suivante : http://www.qt.io/
+

+ + + + + + + + + +
boostboost : de nombreux modules de la + biblioth�que boost font partie de la nouvelle norme C++.
+ C'est une biblioth�que reconnue pour sa qualit�, son code 'C++ + moderne', sa documentation, sa portabilit�, etc.
+ QxOrm utilise les fonctionnalit�s suivantes de boost : + smart_pointer, serialization, type_traits, + multi_index_container, unordered_container, any, tuple, + foreach, function.
+ Il est conseill� d'installer et d'utiliser la derni�re version + de boost disponible � l'adresse suivante : http://www.boost.org/ +
+
+

+ Pourquoi QxOrm n�cessite un en-t�te pr�compil� (precompiled header) pour pouvoir �tre + utilis� ?

+ + + + + + + + + +
+ QxOrm utilise les techniques de m�taprogrammation C++ pour fournir une grande partie de + ses fonctionnalit�s.
+ Vous n'avez pas besoin de savoir utiliser la m�taprogrammation pour travailler avec la biblioth�que + QxOrm.
+ En effet, QxOrm se veut simple d'utilisation et un code C++ �crit avec Qt et QxOrm est facile � lire, + donc facile � d�velopper et � maintenir.

+ Cependant, la m�taprogrammation est couteuse en temps de compilation.
+ En utilisant un fichier precompiled.h, un projet C++ se compilera beaucoup plus vite.
+ Un seul fichier d'en-t�te est n�cessaire pour disposer de l'ensemble des fonctionnalit�s de QxOrm : le + fichier QxOrm.h. +
+

+ Est-il possible d'acc�l�rer les temps de compilation d'un projet ?

+ + + + + + + + + +
+ Oui, si la serialization des donn�es au format XML n'est pas utilis�e dans le projet, vous + pouvez d�sactiver cette fonctionnalit�.
+ Les temps de compilation seront alors r�duits mais vous n'aurez plus acc�s au namespace + qx::serialization:xml.
+ Pour d�sactiver la serialization XML, il faut ouvrir le fichier de configuration + QxOrm.pri et supprimer (ou mettre en commentaire) l'option de compilation + _QX_ENABLE_BOOST_SERIALIZATION_XML.
+ Une recompilation de la biblioth�que QxOrm est n�cessaire pour prendre en compte cette + modification.
+
+ Une autre possibilit� est d'utiliser les classes polymorphiques de la biblioth�que boost::serialization (� la place des classes template).
+ Cette fonctionnalit� r�duit les temps de compilation ainsi que la taille de l'�xecutable g�n�r�.
+ En contre-partie, la vitesse d'ex�cution du programme sera r�duite puisqu'une partie du travail + effectu� lors de la compilation devra �tre r�alis� � l'ex�cution de l'application.
+ Pour utiliser cette fonctionnalit� dans QxOrm, vous devez activer l'option de compilation + _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC dans le fichier de configuration + QxOrm.pri.
+ Attention : les fonctions de serialization seront alors accessibles depuis les + namespace suivants : qx::serialization::polymorphic_binary, + qx::serialization::polymorphic_text et qx::serialization::polymorphic_xml.
+ Une recompilation de la biblioth�que QxOrm est n�cessaire pour prendre en compte cette + modification.
+
+ Enfin, il est �galement possible d'utiliser la macro Q_PROPERTY pour d�clarer les propri�t�s si + la classe h�rite du type QObject.
+ Dans ce cas, il existe deux mani�res diff�rentes pour enregistrer les propri�t�s dans le contexte + QxOrm, dont une qui r�duit sensiblement les temps de compilation du projet.
+ Pour plus d'informations sur cette fonctionnalit�, rendez-vous sur cette + Question-R�ponse de la FAQ.
+
+ Remarque : il est �galement n�cessaire de s'assurer que toutes les optimisations propos�es par + le compilateur sont activ�es, notamment au niveau de la compilation parall�le sur plusieurs + processeurs : +
    +
  • MSVC++ : utiliser la variable d'environnement SET CL=/MP
  • +
  • GCC et Clang : pr�ciser le nombre de processeurs utilis�s en param�tre du process + make, par exemple pour 8 coeurs : SET MAKE_COMMAND=make -j8 +
  • +
+
+

+ Quels sont les diff�rents types de serialization disponibles + ?

+ + + + + + + + + +
+ QxOrm utilise le framework de serialization propos� par la biblioth�que boost.
+ Il existe plusieurs types de serialization disponibles : binaire, XML, JSON, texte, etc.
+ Le fichier de configuration QxOrm.pri permet d'activer et/ou d�sactiver les diff�rents types de + serialization.
+
+ Chaque type de serialization poss�de ses propres caract�ristiques : +
    +
  • binary : smallest, fastest, non-portable ; +
  • +
  • text : larger, slower, portable ; +
  • +
  • XML : largest, slowest, portable. +
  • +
+ Remarque : le type binary n'est pas portable, ce qui signifie que des donn�es ne peuvent + pas s'�changer entre un syt�me Windows et un syst�me Unix par exemple.
+ Si vous devez faire transiter des donn�es sur un r�seau � travers plusieurs syst�mes d'exploitation, + il faut utiliser le type de serialization text ou XML.
+ QxOrm propose �galement une autre solution : le type de serialization portable_binary.
+ Le type portable_binary poss�de les m�mes caract�ristiques que le type binary et permet + d'�changer des donn�es de mani�re portable.
+ Cependant, ce type de serialization n'est pas propos� officiellement par la biblioth�que boost, + il est donc n�cessaire de tester avant de l'utiliser dans un logiciel en production. +
+

+ Pourquoi QxOrm fournit un nouveau type de container qx::QxCollection<Key, + Value> ?

+ + + + + + + + + +
+ Il existe de nombreux container dans les biblioth�ques stl, boost et + Qt.
+ Il est donc l�gitime de se poser cette question : � quoi sert qx::QxCollection<Key, + Value> ?
+ qx::QxCollection<Key, + Value> est un nouveau container (bas� sur l'excellente biblioth�que boost::multi_index_container) qui poss�de les fonctionnalit�s suivantes : +
    +
  • conserve l'ordre d'insertion des �l�ments dans la liste ; +
  • +
  • acc�s rapide � un �l�ment par son index : �quivaut � std::vector<T> ou + QList<T> par exemple ; +
  • +
  • acc�s rapide � un �l�ment par une cl� (hash-map) : �quivaut � QHash<Key, + Value> ou boost::unordered_map<Key, Value> par exemple ; +
  • +
  • fonctions de tri sur le type Key et sur le type Value. +
  • +
+ Remarque : + qx::QxCollection<Key, Value> est compatible avec la macro foreach fournie par la + biblioth�que Qt ainsi que par la macro BOOST_FOREACH fournie par la biblioth�que boost.
+ Cependant, chaque �l�ment renvoy� par ces deux macros correspond � un objet de type + std::pair<Key, Value>.
+ Pour obtenir un r�sultat 'plus naturel' et plus lisible, il est conseill� d'utiliser la macro + _foreach : cette macro utilise BOOST_FOREACH pour tous les container sauf pour + qx::QxCollection<Key, Value>.
+ Dans ce cas, l'�l�ment renvoy� correspond au type Value (voir par la suite l'exemple + d'utilisation).
+ La macro _foreach est donc compatible avec tous les container (stl, Qt, + boost, etc.) puisqu'elle utilise la macro BOOST_FOREACH.

+ Autre Remarque : + qx::QxCollection<Key, Value> est particuli�rement adapt� pour recevoir des donn�es issues + d'une base de donn�es.
+ En effet, ces donn�es peuvent �tre tri�es (en utilisant ORDER BY dans une requ�te SQL par + exemple), il est donc important de conserver l'ordre d'insertion des �l�ments dans la liste.
+ De plus, chaque donn�e issue d'une base de donn�es poss�de un identifiant unique. Il est donc + int�ressant de pouvoir acc�der � un �l�ment en fonction de cet identifiant unique de mani�re + extr�mement rapide (hash-map).

+ Exemple d'utilisation de la collection qx::QxCollection<Key, Value> :
+
+ + + + + + + +
+
/* d�finition d'une classe drug avec 3 propri�t�s : 'code', 'name', 'description' */
+class drug { public: QString code; QString name; QString desc; };
+
+/* pointeur intelligent associ� � la classe drug */
+typedef boost::shared_ptr<drug> drug_ptr;
+
+/* collection de drugs (acc�s rapide � un �l�ment de la collection par la propri�t� 'code') */
+qx::QxCollection<QString, drug_ptr> lstDrugs;
+
+/* cr�ation de 3 nouveaux drugs */
+drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1";
+drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2";
+drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3";
+
+/* insertion des 3 drugs dans la collection */
+lstDrugs.insert(d1->code, d1);
+lstDrugs.insert(d2->code, d2);
+lstDrugs.insert(d3->code, d3);
+
+/* parcours la collection en utilisant le mot-cl� '_foreach' */
+_foreach(drug_ptr p, lstDrugs)
+{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); }
+
+/* parcours la collection en utilisant une boucle 'for' */
+for (long l = 0; l < lstDrugs.count(); ++l)
+{
+   drug_ptr p = lstDrugs.getByIndex(l);
+   QString code = lstDrugs.getKeyByIndex(l);
+   qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc);
+}
+
+/* parcours la collection en utilisant le style Java avec 'QxCollectionIterator' */
+qx::QxCollectionIterator<QString, drug_ptr> itr(lstDrugs);
+while (itr.next())
+{
+   QString code = itr.key();
+   qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc);
+}
+
+/* effectue un tri croissant par cl� (propri�t� 'code') et d�croissant par valeur */
+lstDrugs.sortByKey(true);
+lstDrugs.sortByValue(false);
+
+/* acc�s rapide � un drug par son 'code' */
+drug_ptr p = lstDrugs.getByKey("code2");
+
+/* acc�s rapide � un drug par son index (position) dans la collection */
+drug_ptr p = lstDrugs.getByIndex(2);
+
+/* teste si un drug existe dans la collection et si la liste est vide */
+bool bExist = lstDrugs.exist("code3");
+bool bEmpty = lstDrugs.empty();
+
+/* supprime de la collection le 2�me �l�ment */
+lstDrugs.removeByIndex(2);
+
+/* supprime de la collection l'�l�ment avec le code 'code3' */
+lstDrugs.removeByKey("code3");
+
+/* efface tous les �l�ments de la collection */
+lstDrugs.clear();
+
+
+

+ Pourquoi QxOrm fournit un nouveau type de pointeur intelligent + qx::dao::ptr<T> ?

+ + + + + + + + + +
+ QxOrm est compatible avec les pointeurs intelligents des biblioth�ques boost et + Qt.
+ Le pointeur intelligent d�velopp� par QxOrm est bas� sur QSharedPointer et apporte de + nouvelles fonctionnalit�s s'il est utilis� avec les fonctions 'qx::dao::...'.
+ qx::dao::ptr<T> + conserve automatiquement les valeurs issues de la base de donn�es.
+ Il est ainsi possible de v�rifier � tout moment si une instance d'objet a subi des modifications gr�ce + � la m�thode 'isDirty()' : cette m�thode peut renvoyer la liste de toutes les propri�t�s ayant + �t� modifi�es.
+ qx::dao::ptr<T> peut �galement �tre utilis� par la fonction + 'qx::dao::update_optimized()' pour mettre � jour en base de donn�es uniquement les champs + modifi�s.
+ qx::dao::ptr<T> peut �tre utilis� avec un objet simple ou bien avec la plupart des + containers : stl, boost, Qt et qx::QxCollection<Key, Value>.
+
+ Exemple d'utilisation du pointeur intelligent qx::dao::ptr<T> :
+
+ + + + + + + +
+
// exemple d'utilisation de la m�thode 'isDirty()'
+qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(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("|"))); }
+
+// met � jour uniquement la propri�t� 'm_text' de l'instance 'blog_isdirty'
+daoError = qx::dao::update_optimized(blog_isdirty);
+qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());
+qx::dump(blog_isdirty);
+
+// exemple d'utilisation de la m�thode 'isDirty()' avec une liste d'objets
+typedef qx::dao::ptr< QList<author_ptr> > type_lst_author_test_is_dirty;
+
+type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+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("|"))); }
+
+// met � jour la propri�t� 'm_name' en position 1, la propri�t� 'm_birthdate' en position 2 et ne change rien en position 0
+daoError = qx::dao::update_optimized(container_isdirty);
+qAssert(! daoError.isValid() && ! container_isdirty.isDirty());
+qx::dump(container_isdirty);
+
+// r�cup�re uniquement la propri�t� 'm_dt_creation' du 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);
+
+
+

+ Faut-il utiliser QString ou std::string ?

+ + + + + + + + + +
+ QxOrm conseille d'utiliser la classe QString pour la gestion des cha�nes de caract�res.
+ M�me si boost fournit de nombreuses fonctionnalit�s avec son module boost::string_algo, + la classe QString est plus simple � utiliser et surtout prend en charge automatiquement les + diff�rents formats : Ascii, Utf8, Utf16, etc.
+ Cependant, QxOrm est compatible avec std::string et std::wstring si vous pr�f�rez + utiliser ce type de cha�ne de caract�res. +
+

+ Faut-il utiliser les pointeurs intelligents smart-pointer ?

+ + + + + + + + + +
+ QxOrm conseille fortement d'utiliser les pointeurs intelligents de boost ou + Qt.
+ Le langage C++ ne poss�de pas de Garbage Collector comme Java ou C# par + exemple.
+ L'utilisation des smart-pointer simplifie �norm�ment la gestion de la m�moire en C++.
+ L'id�al dans un programme C++ est de n'avoir aucun appel � delete ou delete[].
+ De plus, les smart-pointer font partie de la nouvelle norme C++ : C++1x.
+ Il est donc essentiel aujourd'hui de conna�tre les classes suivantes : + +
+

+ La cl� primaire est de type long par d�faut. Est-il possible d'utiliser une cl� + de type QString ou autre ?

+ + + + + + + + + +
+ Par d�faut, lorsqu'un mapping d'une classe C++ est �crit avec la m�thode void + qx::register_class<T>, l'identifiant associ� � la classe est de type long (cl� + primaire avec auto-incr�mentation dans la base de donn�es).
+
+ Il est possible de d�finir un identifiant d'un autre type en utilisant la macro + QX_REGISTER_PRIMARY_KEY.
+ Cette macro sp�cialise le template qx::trait::get_primary_key pour associer un type + d'identifiant � une classe C++.
+
+ Par exemple, pour d�finir un identifiant unique de type QString pour la classe C++ + myClass (mapp�e vers une table de la BDD avec une colonne de type VARCHAR pour cl� + primaire), il suffit d'�crire :
+ QX_REGISTER_PRIMARY_KEY(myClass, QString)
+
+ Voici un exemple d'utilisation de la macro QX_REGISTER_PRIMARY_KEY avec une classe + author poss�dant un identifiant de type QString :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+ 
+class author
+{
+public:
+// -- propri�t�s
+   QString  m_id;
+   QString  m_name;
+// -- constructeur, destructeur virtuel
+   author() { ; }
+   virtual ~author() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+

+ Comment d�finir une cl� primaire sur plusieurs colonnes (composite key) + ?

+ + + + + + + + + +
+ QxOrm supporte la notion de 'multi-columns primary key'.
+ L'identifiant de la classe doit �tre du type suivant : +
    +
  • QPair ou std::pair pour d�finir deux colonnes ; +
  • +
  • boost::tuple pour d�finir de deux � neuf colonnes. +
  • +
+ Il est n�cessaire d'utiliser la macro QX_REGISTER_PRIMARY_KEY() pour sp�cialiser le + template et ainsi d�finir le type d'identifiant sur plusieurs colonnes.
+ La liste des noms des colonnes doit �tre de la forme suivante : + 'column1|column2|column3|etc.'.
+
+ Exemple d'utilisation avec la classe 'author' du projet 'qxBlogCompositeKey', + cette classe poss�de un identifiant sur trois colonnes :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+
+   QX_REGISTER_FRIEND_CLASS(author)
+
+public:
+
+// -- cl� compos�e (cl� primaire d�finie sur plusieurs colonnes dans la base de donn�es)
+   typedef boost::tuple<QString, long, QString> type_composite_key;
+   static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; }
+
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+
+// -- enum
+   enum enum_sex { male, female, unknown };
+
+// -- propri�t�s
+   type_composite_key   m_id;
+   QString              m_name;
+   QDate                m_birthdate;
+   enum_sex             m_sex;
+   list_blog            m_blogX;
+
+// -- constructeur, destructeur virtuel
+   author() : m_id("", 0, ""), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+
+// -- m�thodes
+   int age() const;
+
+// -- m�thodes d'acc�s � la cl� compos�e
+   type_composite_key getId() const    { return m_id; }
+   QString getId_0() const             { return boost::tuples::get<0>(m_id); }
+   long getId_1() const                { return boost::tuples::get<1>(m_id); }
+   QString getId_2() const             { return boost::tuples::get<2>(m_id); }
+
+// -- m�thodes de modification de la cl� compos�e
+   void setId_0(const QString & s)     { boost::tuples::get<0>(m_id) = s; }
+   void setId_1(long l)                { boost::tuples::get<1>(m_id) = l; }
+   void setId_2(const QString & s)     { boost::tuples::get<2>(m_id) = s; }
+
+};
+
+QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<author::type_composite_key, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/author.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, author::str_composite_key());
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key());
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+

+ Comment enregistrer des membres private ou protected dans le contexte + QxOrm ?

+ + + + + + + + + +
+ Pour enregistrer des membres private ou protected dans le contexte QxOrm (fonction + qx::register_class<T>), il faut d�clarer les friend class n�cessaires.
+ Pour simplifier l'�criture avec les template C++, la biblioth�que QxOrm fournit la macro + suivante : QX_REGISTER_FRIEND_CLASS(myClass).
+ Un exemple d'utilisation se trouve dans le dossier ./test/qxDllSample/dll1/ du package QxOrm + avec la classe CPerson :
+
+ + + + + + + +
+
namespace qx {
+namespace test {
+
+class QX_DLL1_EXPORT CPerson : public QObject
+{
+
+   Q_OBJECT
+   QX_REGISTER_FRIEND_CLASS(qx::test::CPerson)
+
+   // etc...
+
+};
+
+} // namespace test
+} // namespace qx
+
+
+
+

+ Comment activer/d�sactiver le module QxMemLeak pour la d�tection automatique + des fuites m�moires ?

+ + + + + + + + + +
+ Le module QxMemLeak permet une d�tection rapide des fuites + m�moire en mode Debug une fois l'ex�cution du programme termin�e + (avec indication du fichier et de la ligne => style MFC de + Microsoft).
+ Ce module a �t� d�velopp� par Wu Yongwei + et a subi + quelques modifications pour �tre int�gr� dans QxOrm.
+ Si un autre outil est d�j� utilis� (Valgrind par exemple), + cette fonctionnalit� ne doit pas �tre activ�e.
+ Pour activer/d�sactiver le module QxMemLeak, il suffit de modifier la constante + _QX_USE_MEM_LEAK_DETECTION d�finie dans le fichier QxConfig.h.
+ Une recompilation de la biblioth�que QxOrm est n�cessaire pour prendre en compte cette modification. +
+

+ Comment g�rer la notion d'h�ritage avec la base de donn�es ?

+ + + + + + + + + +
+ On retrouve g�n�ralement dans les diff�rents outils de type ORM trois diff�rentes strat�gies + pour g�rer la notion d'h�ritage avec la base de donn�es : + + QxOrm utilise par d�faut la strat�gie Concrete Table Inheritance (les autres strat�gies + ne sont pas fonctionnelles � l'heure actuelle).
+ De nombreux tutoriaux et forums sont disponibles sur internet pour plus de d�tails sur cette notion + d'h�ritage.
+ Un exemple d'utilisation avec une classe de base se trouve dans le dossier + ./test/qxDllSample/dll2/ avec la classe BaseClassTrigger. +
+

+ Comment utiliser les Trigger ?

+ + + + + + + + + +
+ Les Trigger de QxOrm permettent d'effectuer divers traitements avant et/ou apr�s une + insertion, une mise � jour ou bien une suppression dans la base de donn�es.
+ Un exemple d'utilisation se trouve dans le dossier ./test/qxDllSample/dll2/ avec la classe + BaseClassTrigger.
+ Cette classe contient cinq propri�t�s : m_id, m_dateCreation, m_dateModification, + m_userCreation et m_userModification.
+ Ces propri�t�s se mettront � jour automatiquement pour chaque classe h�ritant de + BaseClassTrigger (cf. les classes Foo et Bar du m�me projet).
+ Il est n�cessaire de sp�cialiser le template 'QxDao_Trigger' pour profiter de cette + fonctionnalit�.
+
+ + + + + + + +
+
#ifndef _QX_BASE_CLASS_TRIGGER_H_
+#define _QX_BASE_CLASS_TRIGGER_H_
+
+class QX_DLL2_EXPORT BaseClassTrigger
+{
+
+   QX_REGISTER_FRIEND_CLASS(BaseClassTrigger)
+
+protected:
+
+   long        m_id;
+   QDateTime   m_dateCreation;
+   QDateTime   m_dateModification;
+   QString     m_userCreation;
+   QString     m_userModification;
+
+public:
+
+   BaseClassTrigger() : m_id(0)  { ; }
+   virtual ~BaseClassTrigger()   { ; }
+
+   long getId() const                     { return m_id; }
+   QDateTime getDateCreation() const      { return m_dateCreation; }
+   QDateTime getDateModification() const  { return m_dateModification; }
+   QString getUserCreation() const        { return m_userCreation; }
+   QString getUserModification() const    { return m_userModification; }
+
+   void setId(long l)                              { m_id = l; }
+   void setDateCreation(const QDateTime & dt)      { m_dateCreation = dt; }
+   void setDateModification(const QDateTime & dt)  { m_dateModification = dt; }
+   void setUserCreation(const QString & s)         { m_userCreation = s; }
+   void setUserModification(const QString & s)     { m_userModification = s; }
+
+   void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
+   void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
+
+};
+
+QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0)
+
+namespace qx {
+namespace dao {
+namespace detail {
+
+template <>
+struct QxDao_Trigger<BaseClassTrigger>
+{
+
+   static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeInsert(dao); } }
+   static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeUpdate(dao); } }
+   static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onBeforeFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+
+};
+
+} // namespace detail
+} // namespace dao
+} // namespace qx
+
+#endif // _QX_BASE_CLASS_TRIGGER_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/BaseClassTrigger.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger)
+
+namespace qx {
+template <> void register_class(QxClass<BaseClassTrigger> & t)
+{
+   IxDataMember * pData = NULL;
+
+   pData = t.id(& BaseClassTrigger::m_id, "id");
+
+   pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation");
+   pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification");
+   pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation");
+   pData = t.data(& BaseClassTrigger::m_userModification, "user_modification");
+}}
+
+void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateCreation = QDateTime::currentDateTime();
+   m_dateModification = QDateTime::currentDateTime();
+   m_userCreation = "current_user_1";
+   m_userModification = "current_user_1";
+}
+
+void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateModification = QDateTime::currentDateTime();
+   m_userModification = "current_user_2";
+}
+
+
+
+

+ Comment d�clarer une classe abstraite dans le contexte QxOrm ?

+ + + + + + + + + +
+ Une classe abstraite C++ (contenant au moins une m�thode virtuelle pure) ne peut pas �tre mapp�e avec + une table d'une base de donn�es (puisqu'elle ne peut pas �tre instanci�e).
+ Cependant, il peut �tre int�ressant de d�finir une classe abstraite contenant une liste de propri�t�s + utilis�es par plusieurs objets persistants.
+ Un exemple de classe abstraite se trouve dans le dossier ./test/qxDllSample/dll2/ de la + distribution de QxOrm avec la classe BaseClassTrigger.
+ QxOrm propose le m�canisme suivant pour d�finir une classe abstraite dans le contexte QxOrm : +
    +
  • d�clarer la classe avec la m�thode 'void register_class' comme n'importe qu'elle autre + classe ; +
  • +
  • utiliser la macro QX_REGISTER_ABSTRACT_CLASS(className) juste apr�s la d�finition de la + classe. +
  • +
+
+

+ Comment d�clarer une classe d�finie dans un espace de nom (namespace) dans le + contexte QxOrm ?

+ + + + + + + + + +
+ Si une classe est d�finie dans un espace de nom (namespace), alors une erreur de compilation se + produit avec l'utilisation des macros : QX_REGISTER_HPP et QX_REGISTER_CPP.
+ Pour �viter ces erreurs de compilation, il est n�cessaire d'utiliser les macros suivantes : + QX_REGISTER_COMPLEX_CLASS_NAME_HPP et QX_REGISTER_COMPLEX_CLASS_NAME_CPP.
+
+ Vous trouverez un exemple d'utilisation dans le dossier ./test/qxDllSample/dll1/ de la + distribution de QxOrm avec la classe CPerson d�finie dans l'espace de nom qx::test :
+ * QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0, + qx_test_CPerson)
+
+ Les macros QX_REGISTER_COMPLEX_CLASS_NAME... n�cessitent un param�tre suppl�mentaire (dans + l'exemple ci-dessus il s'agit du param�tre qx_test_CPerson) afin de cr�er une variable + globale.
+ Celle-ci est appel�e d�s le lancement de l'application.
+ La construction de cette instance globale d�clare la classe dans le module QxFactory (mod�le de + conception fabrique ou design pattern factory).
+ Un objet C++ ne pouvant pas se nommer avec des caract�res "::", le param�tre suppl�mentaire de + la macro permet de remplacer tous les "::" par des "_".
+
+

+ Comment utiliser le m�canisme de suppression logique (soft delete) + ?

+ + + + + + + + + +
+ Une suppression logique permet de ne pas effacer de ligne dans une table d'une base de donn�es + (contrairement � une suppression physique) : une colonne suppl�mentaire est ajout�e � la d�finition de + la table pour indiquer que la ligne est supprim�e ou non.
+ Cette colonne peut contenir soit un bool�en (1 signifie ligne supprim�e, 0 ou vide signifie ligne non + supprim�e), soit la date-heure de suppression de la ligne (si vide, la ligne est consid�r�e comme non + supprim�e).
+ Il est donc � tout moment possible de r�activer une ligne supprim�e en r�initialisant la valeur � vide + dans la table de la base de donn�es.
+
+ Pour activer le m�canisme de suppression logique avec la biblioth�que QxOrm, il faut utiliser la + classe qx::QxSoftDelete dans la fonction de mapping qx::register_class<T>.
+ Voici un exemple d'utilisation avec une classe Bar contenant deux propri�t�s m_id et + m_desc :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<Bar> & t)
+{
+   t.setSoftDelete(qx::QxSoftDelete("deleted_at"));
+
+   t.id(& Bar::m_id, "id");
+   t.data(& Bar::m_desc, "desc");
+}}
+
+
+ Les requ�tes SQL g�n�r�es automatiquement par la biblioth�que QxOrm vont prendre en compte ce + param�tre de suppression logique pour ajouter les conditions n�cessaires (ne pas r�cup�rer les + �l�ments supprim�s, ne pas supprimer physiquement une ligne, etc.).
+ Par exemple, si vous ex�cutez les lignes suivantes avec la classe Bar :
+
+ + + + + + + +
+
Bar_ptr pBar; pBar.reset(new Bar());
+pBar->setId(5);
+QSqlError daoError = qx::dao::delete_by_id(pBar);     qAssert(! daoError.isValid());
+qx_bool bDaoExist = qx::dao::exist(pBar);             qAssert(! bDaoExist);
+daoError = qx::dao::delete_all<Bar>();                qAssert(! daoError.isValid());
+long lBarCount = qx::dao::count<Bar>();               qAssert(lBarCount == 0);
+daoError = qx::dao::destroy_all<Bar>();               qAssert(! daoError.isValid());
+
+
+ Vous obtiendrez les traces suivantes :
+
+ + + + + + + +
+
[QxOrm] sql query (93 ms) : UPDATE Bar SET deleted_at = '20110617115148615' WHERE id = :id
+[QxOrm] sql query (0 ms) : SELECT Bar.id AS Bar_id_0, Bar.deleted_at FROM Bar WHERE Bar.id = :id AND (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (78 ms) : UPDATE Bar SET deleted_at = '20110617115148724'
+[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM Bar WHERE (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (110 ms) : DELETE FROM Bar
+
+
+ Remarque : pour supprimer physiquement une ligne de la base de donn�es, il faut utiliser les + fonctions : qx::dao::destroy_by_id() et qx::dao::destroy_all().
+
+ Autre remarque : il peut �tre int�ressant de d�finir au niveau du SGBD un index sur la colonne + deleted_at (ou peu importe le nom que vous donnez) afin d'acc�l�rer l'ex�cution des requ�tes + SQL.
+
+

+ Comment utiliser les sessions (classe qx::QxSession) pour simplifier la gestion + des transactions des bases de donn�es (C++ RAII) ?

+ + + + + + + + + +
+ Une transaction est une suite d'op�rations effectu�es comme une seule unit� + logique de travail.
+ Une fois termin�e, la transaction est :
+ * soit valid�e (commit), alors toutes les modifications sont faites dans la base de donn�es + ;
+ * soit annul�e (rollback), alors toutes les modifications ne sont pas enregistr�e.
+
+ La classe qx::QxSession de la biblioth�que QxOrm permet de g�rer automatiquement les + transactions (validation, annulation) en utilisant le m�canisme C++ RAII :
+
+ + + + + + + +
+
{ // Ouverture d'un scope o� une session sera instanci�e
+
+  // Cr�ation d'une session : une connection valide � la BDD est assign�e � la session et une transaction est d�marr�e
+  qx::QxSession session;
+
+  // Ex�cution d'une s�rie d'op�rations avec la BDD (en utilisant l'op�rateur += de la classe qx::QxSession et la connection de la session)
+  session += qx::dao::insert(my_object, session.database());
+  session += qx::dao::update(my_object, session.database());
+  session += qx::dao::fetch_by_id(my_object, session.database());
+  session += qx::dao::delete_by_id(my_object, session.database());
+
+  // Si la session n'est pas valide (donc une erreur s'est produite) => affichage de la 1�re erreur de la session
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // Fermeture du scope : la session est d�truite (transaction => commit ou rollback automatique)
+
+
+ Remarque : une session peut d�clencher une exception de type qx::dao::sql_error + lorsqu'une erreur se produit (par d�faut, aucune exception n'est d�clench�e). Il est possible de + param�trer ce comportement en utilisant :
+ * soit le constructeur de la classe qx::QxSession (pour une session en particulier) ;
+ * soit le param�tre du singleton qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b) + (pour toutes les sessions).
+
+ Autre remarque : il est important de ne pas oublier de passer la connection � la base de + donn�es de la session � chaque fonction qx::dao::xxx (en utilisant la m�thode + session.database()).
+ De plus, il est possible d'initialiser une session avec sa propre connection (provenant d'un pool de + connections par exemple) en utilisant le constructeur de la classe qx::QxSession.
+
+ La classe qx::QxSession propose �galement des m�thodes de persistance (CRUD), ce qui peut + simplifier l'�criture du code C++ suivant les habitudes de programmation.
+ Voici le m�me exemple en utilisant les m�thodes de la classe qx::QxSession � la place des + fonctions du namespace qx::dao :
+
+ + + + + + + +
+
{ // Ouverture d'un scope o� une session sera instanci�e
+
+  // Cr�ation d'une session : une connection valide � la BDD est assign�e � la session et une transaction est d�marr�e
+  qx::QxSession session;
+
+  // Ex�cution d'une s�rie d'op�rations avec la BDD
+  session.insert(my_object);
+  session.update(my_object);
+  session.fetchById(my_object);
+  session.deleteById(my_object);
+
+  // Si la session n'est pas valide (donc une erreur s'est produite) => affichage de la 1�re erreur de la session
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // Fermeture du scope : la session est d�truite (transaction => commit ou rollback automatique)
+
+
+
+

+ Comment persister un type dont on ne poss�de pas le code source (classe provenant + d'une biblioth�que tierce par exemple) ?

+ + + + + + + + + +
+ La biblioth�que QxOrm permet de persister n'importe quel type, m�me si ce dernier n'est pas enregistr� + dans le contexte QxOrm par la m�thode qx::register_class<T>().
+
+ Il est n�cessaire d'�crire les fonctions de s�rialisation de la biblioth�que boost, en utilisant la + m�thode non intrusive (puisque le code source n'est pas disponible ou ne peut pas �tre + modifi�). + Pour plus d'informations sur la s�rialisation des donn�es avec la biblioth�que boost, rendez-vous sur + le tutoriel + de developpez.com.
+
+ Par exemple, imaginons une classe 'ExtObject3D' provenant d'une biblioth�que tierce et dont le + code source n'est pas disponible ou ne peut pas �tre modifi�. + Voici le code n�cessaire pour pouvoir persister une instance de type 'ExtObject3D' en base de + donn�es :
+
+ + + + + + + +
+
#ifndef _PERSIST_EXTOBJECT3D_H_
+#define _PERSIST_EXTOBJECT3D_H_
+
+#include "ExtObject3D.h"
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/nvp.hpp>
+ 
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void save(Archive & ar, const ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(t.getX()), y(t.getY()), z(t.getZ()), angle(t.getAngle());
+
+   ar << boost::serialization::make_nvp("x", x);
+   ar << boost::serialization::make_nvp("y", y);
+   ar << boost::serialization::make_nvp("z", z);
+   ar << boost::serialization::make_nvp("angle", angle);
+}
+
+template <class Archive>
+void load(Archive & ar, ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(0.0), y(0.0), z(0.0), angle(0.0);
+
+   ar >> boost::serialization::make_nvp("x", x);
+   ar >> boost::serialization::make_nvp("y", y);
+   ar >> boost::serialization::make_nvp("z", z);
+   ar >> boost::serialization::make_nvp("angle", angle);
+
+   t.setX(x);
+   t.setY(y);
+   t.setZ(z);
+   t.setAngle(angle);
+}
+
+} // namespace serialization
+} // namespace boost
+ 
+BOOST_SERIALIZATION_SPLIT_FREE(ExtObject3D)
+
+#endif // _PERSIST_EXTOBJECT3D_H_
+
+
+ Le code ci-dessus est suffisant pour persister une instance de type 'ExtObject3D' en base de + donn�es : il est ainsi possible d'utiliser une propri�t� de type 'ExtObject3D' dans une classe + persistante enregistr�e dans le contexte QxOrm. + Cette propri�t� peut �tre mapp�e sur une colonne de type TEXT ou VARCHAR en base de + donn�es.
+
+ Le comportement par d�faut de la biblioth�que QxOrm est le suivant : l'instance est s�rialis�e au + format XML avant d'�tre ins�r�e ou mise � jour en base de donn�es. + Ce comportement par d�faut peut �tre utile par exemple si l'on souhaite enregistrer une collection + d'objets sans vouloir faire de relation (et donc g�rer une autre table dans la base de donn�es). + Par exemple, si l'on utilise une propri�t� de type std::vector<mon_objet> dans une classe + persistante sans relation associ�e, la liste d'�l�ments sera automatiquement enregistr�e au format XML + en base de donn�es.
+
+ Remarque : ce comportement par d�faut peut �tre facilement modifi� pour un type donn�. + Le moteur QtSql utilise le type QVariant pour faire le lien entre le code C++ et la base + de donn�es. + Le type QVariant peut contenir du texte, des valeurs num�riques, du binaire, etc. + Il peut donc �tre int�ressant de sp�cialiser le comportement par d�faut (s�rialisation XML) si l'on + souhaite stocker des donn�es au format binaire ou bien optimiser les performances (la s�rialisation + XML peut �tre couteuse en temps d'ex�cution). + Il suffit de proposer (en plus des fonctions de s�rialisation boost) les conversions n�cessaires en + QVariant, par exemple avec la classe 'ExtObject3D' :
+
+ + + + + + + +
+
namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< ExtObject3D > {
+static inline QVariant toVariant(const ExtObject3D & t, const QString & format, int index)
+{ /* Ici je convertis ExtObject3D en QVariant */ } };
+
+template <> struct QxConvert_FromVariant< ExtObject3D > {
+static inline qx_bool fromVariant(const QVariant & v, ExtObject3D & t, const QString & format, int index)
+{ /* Ici je convertis QVariant en ExtObject3D */; return qx_bool(true); } };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+
+
+

+ Comment utiliser le moteur d'introspection (ou r�flexion) de la biblioth�que QxOrm + ?

+ + + + + + + + + +
+ Toute classe enregistr�e dans le contexte QxOrm par la m�thode qx::register_class<T>() + peut �tre utilis�e par le moteur d'introspection (ou r�flexion) de la biblioth�que QxOrm. + Le moteur d'introspection permet d'obtenir de fa�on dynamique (donc pendant l'ex�cution du programme) + des informations propres � un type. + Ces informations correspondent � des m�ta-donn�es et d�crivent de fa�on exhaustive les + caract�ristiques d'une classe (propri�t�s, m�thodes, etc.). + De nombreux langages de programmation (par exemple Java ou C#) int�grent nativement ce m�canisme, ce + n'est pas le cas du C++, c'est pourquoi la biblioth�que QxOrm �mule un moteur d'introspection.
+
+ Voici la liste des classes disponibles pour acc�der aux m�ta-donn�es : +
    +
  • qx::QxClassX : + singleton permettant de parcourir l'ensemble des classes enregistr�es dans le contexte QxOrm par + la m�thode qx::register_class<T>() ;
  • +
  • qx::IxClass : interface + pour une classe enregistr�e dans le contexte QxOrm ;
  • +
  • qx::IxDataMemberX : liste des propri�t�s associ�es � une classe ;
  • +
  • qx::IxDataMember : + interface pour une propri�t� d'une classe ;
  • +
  • qx::IxFunctionX : + liste des m�thodes associ�es � une classe ;
  • +
  • qx::IxFunction : + interface pour une m�thode d'une classe.
  • +
+ Une instance de type qx::IxClass poss�de la liste des propri�t�s d'une classe + (qx::IxDataMemberX) ainsi que la liste des m�thodes d'une classe (qx::IxFunctionX).
+
+ Le moteur d'introspection de la biblioth�que QxOrm permet par exemple de : +
    +
  • cr�er dynamiquement une instance en fonction du nom d'une classe sous forme de cha�ne de + caract�res (qx::create()) ;
  • +
  • acc�der/modifier le contenu d'un champ d'un objet de fa�on dynamique en prenant pour param�tres + un objet et le nom du champ qu'on souhaite acc�der/modifier (qx::IxDataMember::getValue() + et qx::IxDataMember::setValue()) ;
  • +
  • invoquer une m�thode de classe de fa�on dynamique, en g�rant bien entendu le passage des + param�tres souhait�s � la m�thode (qx::IxFunction::invoke()) ;
  • +
  • acc�der � la hi�rarchie d'une classe (qx::IxClass::getBaseClass()).
  • +
+ Remarque : le module QxService de la biblioth�que QxOrm (cliquez ici pour acc�der au tutoriel) permettant de cr�er un serveur + d'applications C++ est bas� sur le moteur d'introspection pour appeler dynamiquement les m�thodes de + type service (demande du client) sur le serveur.
+
+ Voici un exemple d'utilisation du moteur d'introspection de la biblioth�que QxOrm : comment lister + toutes les classes, propri�t�s et m�thodes enregistr�es dans le contexte QxOrm ?
+
+ + + + + + + +
+
QString QxClassX::dumpAllClasses()
+{
+   QxClassX::registerAllClasses();
+   QxCollection<QString, IxClass *> * pAllClasses = QxClassX::getAllClasses();
+   if (! pAllClasses) { qAssert(false); return ""; }
+
+   QString sDump;
+   long lCount = pAllClasses->count();
+   qDebug("[QxOrm] start dump all registered classes (%ld)", lCount);
+   _foreach(IxClass * pClass, (* pAllClasses))
+   { if (pClass) { sDump += pClass->dumpClass(); } }
+   qDebug("[QxOrm] %s", "end dump all registered classes");
+
+   return sDump;
+}
+
+QString IxClass::dumpClass() const
+{
+   QString sDump;
+   sDump += "-- class '" + m_sKey + "' (name '" + m_sName + "', ";
+   sDump += "description '" + m_sDescription + "', version '" + QString::number(m_lVersion) + "', ";
+   sDump += "base class '" + (getBaseClass() ? getBaseClass()->getKey() : "") + "')\n";
+
+   long lCount = (m_pDataMemberX ? m_pDataMemberX->count() : 0);
+   sDump += "\t* list of registered properties (" + QString::number(lCount) + ")\n";
+   if (m_pDataMemberX)
+   {
+      IxDataMember * pId = this->getId();
+      for (long l = 0; l < lCount; l++)
+      {
+         IxDataMember * p = m_pDataMemberX->get(l); if (! p) { continue; }
+         IxSqlRelation * pRelation = p->getSqlRelation();
+         QString sInfos = p->getKey() + ((p == pId) ? QString(" (id)") : QString());
+         sInfos += (pRelation ? (QString(" (") + pRelation->getDescription() + QString(")")) : QString());
+         sDump += "\t\t" + sInfos + "\n";
+      }
+   }
+
+   lCount = (m_pFctMemberX ? m_pFctMemberX->count() : 0);
+   sDump += "\t* list of registered functions (" + QString::number(lCount) + ")\n";
+   if (m_pFctMemberX)
+   {
+      _foreach_if(IxFunction_ptr p, (* m_pFctMemberX), (p))
+      { QString sKey = p->getKey(); sDump += "\t\t" + sKey + "\n"; }
+   }
+
+   qDebug("%s", qPrintable(sDump));
+   return sDump;
+}
+
+
+ Si on utilise la m�thode qx::QxClassX::dumpAllClasses() avec le tutoriel qxBlog, voici le r�sultat obtenu :
+
+ + + + + + + +
+
[QxOrm] start dump all registered classes (4)
+-- class 'author' (name 'author', description '', version '0', base class '')
+	* list of registered properties (5)
+		author_id (id)
+		name
+		birthdate
+		sex
+		list_blog (relation one-to-many)
+	* list of registered functions (1)
+		age
+
+-- class 'blog' (name 'blog', description '', version '0', base class '')
+	* list of registered properties (6)
+		blog_id (id)
+		blog_text
+		date_creation
+		author_id (relation many-to-one)
+		list_comment (relation one-to-many)
+		list_category (relation many-to-many)
+	* list of registered functions (0)
+
+-- class 'comment' (name 'comment', description '', version '0', base class '')
+	* list of registered properties (4)
+		comment_id (id)
+		comment_text
+		date_creation
+		blog_id (relation many-to-one)
+	* list of registered functions (0)
+
+-- class 'category' (name 'category', description '', version '0', base class '')
+	* list of registered properties (4)
+		category_id (id)
+		name
+		description
+		list_blog (relation many-to-many)
+	* list of registered functions (0)
+
+[QxOrm] end dump all registered classes
+
+
+ Remarque : il est possible d'ajouter de nouvelles informations au moteur d'introspection en + utilisant la notion de property bag. + En effet, les classes qx::IxClass, qx::IxDataMember et qx::IxFunction poss�dent + chacune une liste d'�l�ments de type QVariant accessibles par cl� de type QString (voir + la classe qx::QxPropertyBag pour plus de d�tails sur cette notion).
+
+
+

+ Comment d�clarer automatiquement les m�ta-propri�t�s de Qt (d�finies par la macro + Q_PROPERTY) dans le contexte QxOrm ?

+ + + + + + + + + +
+ Toute classe h�ritant du type QObject peut d�clarer ses propri�t�s avec la macro Q_PROPERTY : les + propri�t�s deviennent alors des m�ta-propri�t�s. + Ce m�canisme permet au framework Qt de proposer un moteur d'introspection gr�ce au pr�-compilateur + moc. + Les m�ta-propri�t�s peuvent alors �tre utilis�es par exemple par le moteur QML, + QtScript, etc.
+
+ La biblioth�que QxOrm n�cessite une d�claration de chacune des propri�t�s d'une classe dans la + fonction de mapping void qx::register_class<T>() afin de proposer l'ensemble de ses + fonctionnalit�s (persistance des donn�es, s�rialisation XML, JSON et binaire, etc.). + Il est possible de d�clarer automatiquement dans le contexte QxOrm l'ensemble des m�ta-propri�t�s sans + maintenir une fonction de mapping void qx::register_class<T>() : la macro + QX_REGISTER_ALL_QT_PROPERTIES() utilise le moteur d'introspection de Qt pour parcourir la liste + des m�ta-propri�t�s.
+
+ Voici un exemple d'utilisation avec la classe TestQtProperty se trouvant dans le dossier + ./test/qxDllSample/dll1/include/ de la distribution QxOrm :
+
+ + + + + + + +
+
#ifndef _QX_TEST_QT_META_PROPERTY_H_
+#define _QX_TEST_QT_META_PROPERTY_H_
+ 
+class QX_DLL1_EXPORT TestQtProperty : public QObject
+{
+
+   Q_OBJECT
+   Q_PROPERTY(int id READ id WRITE setId)
+   Q_PROPERTY(long number READ number WRITE setNumber)
+   Q_PROPERTY(QString desc READ desc WRITE setDesc)
+   Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate)
+   Q_PROPERTY(QVariant photo READ photo WRITE setPhoto)
+
+protected:
+
+   int         m_id;
+   long        m_number;
+   QString     m_desc;
+   QDateTime   m_birthDate;
+   QVariant    m_photo;
+
+public:
+
+   TestQtProperty() : QObject(), m_id(0), m_number(0) { ; }
+   virtual ~TestQtProperty() { ; }
+
+   int id() const                { return m_id; }
+   long number() const           { return m_number; }
+   QString desc() const          { return m_desc; }
+   QDateTime birthDate() const   { return m_birthDate; }
+   QVariant photo() const        { return m_photo; }
+
+   void setId(int i)                         { m_id = i; }
+   void setNumber(long l)                    { m_number = l; }
+   void setDesc(const QString & s)           { m_desc = s; }
+   void setBirthDate(const QDateTime & dt)   { m_birthDate = dt; }
+   void setPhoto(const QVariant & v)         { m_photo = v; }
+ 
+};
+
+QX_REGISTER_HPP_QX_DLL1(TestQtProperty, QObject, 0)
+
+#endif // _QX_TEST_QT_META_PROPERTY_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/TestQtProperty.h"
+
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_QX_DLL1(TestQtProperty)
+QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id")
+
+
+ Pour ceux qui ne souhaitent pas utiliser la macro QX_REGISTER_ALL_QT_PROPERTIES, il est + possible d'�crire � la place les quatre lignes de code suivantes :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<TestQtProperty> & t)
+{ qx::register_all_qt_properties<TestQtProperty>(t, "id"); }
+} // namespace qx
+
+
+ Remarque : le deuxi�me param�tre de la macro QX_REGISTER_ALL_QT_PROPERTIES permet + d'indiquer la propri�t� qui servira de cl� primaire dans la base de donn�es. + Si ce param�tre est vide, cela signifie que la classe ne poss�de pas de cl� primaire ou bien que + celle-ci est d�finie dans une classe de base.
+
+ Toute propri�t� d�finie avec la macro Q_PROPERTY peut s'enregistrer dans le contexte QxOrm de + deux mani�res diff�rentes :
+ 1- par la m�thode classique : t.data(& MyQObject::my_property, "my_property", 0);
+ 2- ou bien sans mentionner le pointeur vers la donn�e membre de la classe : + t.data("my_property", 0);
+
+ Peu importe la m�thode d'enregistrement des propri�t�s dans le contexte QxOrm, elles seront + accessibles par la m�me interface qx::IxDataMember et proposent donc les m�mes fonctionnalit�s. + Il est possible d'utiliser les deux m�thodes dans une m�me fonction de mapping void + qx::register_class<T>(). + Chaque m�thode d'enregistrement pr�sente des avantages et inconv�nients.
+
+ Voici la liste des avantages de la deuxi�me m�thode d'enregistrement des propri�t�s dans le contexte + QxOrm : +
    +
  • temps de compilation du projet beaucoup plus rapide ;
  • +
  • taille de l'ex�cutable g�n�r� plus petite ;
  • +
  • forte int�gration avec le moteur d'introspection du framework Qt ;
  • +
  • pas besoin de maintenir la fonction de mapping en utilisant la macro + QX_REGISTER_ALL_QT_PROPERTIES. +
  • +
+ Voici les inconv�nients par rapport � la m�thode classique d'enregistrement des propri�t�s : +
    +
  • n�cessite un h�ritage de la classe QObject pour pouvoir utiliser la macro + Q_PROPERTY ; +
  • +
  • ex�cution du programme plus lente (utilisation du type QVariant � la place des + template C++) ; +
  • +
  • ne supporte pas la notion de relation entre tables de la base de donn�es (one-to-one, + one-to-many, many-to-one et many-to-many) ; +
  • +
  • pas d'acc�s au pointeur sur la donn�e membre de la classe (conversion n�cessaire au type + QVariant pour acc�der et modifier une valeur). +
  • +
+
+

+ Comment construire une requ�te pour interroger la base de donn�es sans �crire de SQL + avec la classe qx::QxSqlQuery ?

+ + + + + + + + + +
+ La classe qx::QxSqlQuery (ou bien son alias qx_query) permet d'interroger la + base de donn�es (trier, filtrer, etc.) de deux mani�res diff�rentes : + + Le principal avantage de la premi�re m�thode (�criture manuelle des requ�tes SQL) est de pouvoir + utiliser certaines optimisations sp�cifiques � chaque base de donn�es.
+ La deuxi�me m�thode (utilisation du code C++ pour g�n�rer la requ�te SQL) permet de mapper + automatiquement les param�tres SQL sans utiliser la fonction qx::QxSqlQuery::bind().
+
+ Voici un exemple d'utilisation de la classe qx::QxSqlQuery avec �criture manuelle d'une requ�te + SQL :
+
+ + + + + + + +
+
// Construit une requ�te pour r�cup�rer uniquement les 'author' de type 'female'
+qx::QxSqlQuery query("WHERE author.sex = :sex");
+query.bind(":sex", author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* traitement avec la collection issue de la base de donn�es */ }
+
+
+ La biblioth�que QxOrm supporte trois syntaxes pour l'�criture des param�tres SQL.
+ Le type de syntaxe peut �tre modifi� de fa�on globale � un projet en utilisant la m�thode suivante : + qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle().
+ Les trois param�tres possibles pour cette m�thode sont : +
    +
  • ph_style_2_point_name : "WHERE author.sex = :sex" (syntaxe par d�faut) ;
  • +
  • ph_style_at_name : "WHERE author.sex = @sex" ;
  • +
  • ph_style_question_mark : "WHERE author.sex = ?".
  • +
+ Voici le m�me exemple en utilisant les m�thodes C++ de la classe qx::QxSqlQuery (ou bien son + alias qx_query) pour g�n�rer la requ�te automatiquement :
+
+ + + + + + + +
+
// Construit une requ�te pour r�cup�rer uniquement les 'author' de type 'female'
+qx_query query;
+query.where("author.sex").isEqualTo(author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* traitement avec la collection issue de la base de donn�es */ }
+
+
+ Cette utilisation de la classe qx::QxSqlQuery pr�sente l'avantage de ne pas avoir � mapper les + param�tres de la requ�te, tout en restant tr�s proche de l'�criture manuelle d'une requ�te SQL.
+ Les param�tres seront automatiquement inject�s en utilisant la syntaxe d�finie de mani�re globale par + la m�thode : qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle().
+
+ Voici un exemple pr�sentant diff�rentes m�thodes disponibles avec la classe qx::QxSqlQuery (ou + bien son alias qx_query) :
+
+ + + + + + + +
+
qx_query query;
+query.where("sex").isEqualTo(author::female)
+     .and_("age").isGreaterThan(38)
+     .or_("last_name").isNotEqualTo("Dupont")
+     .or_("first_name").like("Alfred")
+     .and_OpenParenthesis("id").isLessThanOrEqualTo(999)
+     .and_("birth_date").isBetween(date1, date2)
+     .closeParenthesis()
+     .or_("id").in(50, 999, 11, 23, 78945)
+     .and_("is_deleted").isNotNull()
+     .orderAsc("last_name", "first_name", "sex")
+     .limit(50, 150);
+
+
+ Ce qui produira le code SQL suivant pour les bases de donn�es MySQL, PostgreSQL et + SQLite (pour Oracle et SQLServer, le traitement de la m�thode limit() est + diff�rent) :
+
+ + + + + + + +
+
WHERE sex = :sex_1_0 
+AND age > :age_3_0 
+OR last_name <> :last_name_5_0 
+OR first_name LIKE :first_name_7_0 
+AND ( id <= :id_10_0 AND birth_date BETWEEN :birth_date_12_0_1 AND :birth_date_12_0_2 ) 
+OR id IN (:id_15_0_0, :id_15_0_1, :id_15_0_2, :id_15_0_3, :id_15_0_4) 
+AND is_deleted IS NOT NULL 
+ORDER BY last_name ASC, first_name ASC, sex ASC 
+LIMIT :limit_rows_count_19_0 OFFSET :offset_start_row_19_0
+
+
+ Voici la liste des fonctions et m�thodes disponibles pour utiliser la classe qx::QxSqlQuery (ou + bien son alias qx_query) :
+
+ + + + + + + +
+
// avec les fonctions du namespace qx::dao
+qx::dao::count<T>()
+qx::dao::fetch_by_query<T>()
+qx::dao::update_by_query<T>()
+qx::dao::delete_by_query<T>()
+qx::dao::destroy_by_query<T>()
+qx::dao::fetch_by_query_with_relation<T>()
+qx::dao::fetch_by_query_with_all_relation<T>()
+qx::dao::update_by_query_with_relation<T>()
+qx::dao::update_by_query_with_all_relation<T>()
+qx::dao::update_optimized_by_query<T>()
+
+// avec la classe qx::QxSession
+qx::QxSession::count<T>()
+qx::QxSession::fetchByQuery<T>()
+qx::QxSession::update<T>()
+qx::QxSession::deleteByQuery<T>()
+qx::QxSession::destroyByQuery<T>()
+
+// avec la classe qx::QxRepository<T>
+qx::QxRepository<T>::count()
+qx::QxRepository<T>::fetchByQuery()
+qx::QxRepository<T>::update()
+qx::QxRepository<T>::deleteByQuery()
+qx::QxRepository<T>::destroyByQuery()
+
+
+ Remarque : certaines de ces fonctions ont �galement deux autres param�tres optionnels : +
    +
  • const QStringList & columns : pour indiquer la liste des colonnes � r�cup�rer (par + d�faut, toutes les colonnes sont r�cup�r�es) ;
  • +
  • const QStringList & relation : pour indiquer les jointures (one-to-one, + one-to-many, many-to-one et many-to-many d�finies dans la fonction de mapping + void qx::register_class<T>()) entre les tables de la base de donn�es (par d�faut, + aucune relation). +
  • +
+
+

+ Comment utiliser le cache (fonctions du namespace qx::cache) pour stocker tous + types de donn�es ?

+ + + + + + + + + +
+ Le cache propos� par la biblioth�que QxOrm (module QxCache) est thread-safe et permet de stocker facilement + n'importe quel type de donn�es.
+ Les fonctions pour acc�der au cache se trouvent dans le namespace + qx::cache.
+ Le cache permet une optimisation du programme : il est possible par exemple de stocker des �l�ments + issus d'une requ�te effectu�e en base de donn�es.
+
+ Chaque �l�ment stock� dans le cache est associ� � une cl� de type QString : cette cl� permet de + retrouver rapidement un �l�ment du cache.
+ Si un nouvel �l�ment est stock� dans le cache avec une cl� qui existe d�j�, alors l'ancien �l�ment + associ� � cette cl� est effac� automatiquement du cache.
+
+ Le cache de la biblioth�que QxOrm ne g�re pas la dur�e de vie des objets : il n'y a aucun + delete effectu� par le cache.
+ C'est pourquoi il est fortement recommand� (mais ce n'est pas une obligation) de privil�gier le + stockage de pointeurs intelligents : par exemple, boost::shared_ptr<T> pour la biblioth�que boost ou bien QSharedPointer<T> pour la biblioth�que Qt.
+
+ Le cache peut avoir un co�t relatif maximum pour �viter une utilisation de la m�moire trop importante + : chaque �l�ment ins�r� dans le cache peut indiquer un co�t repr�sentant une estimation de sa taille + m�moire (par exemple, le nombre d'�l�ments d'une collection).
+ Lorsque le co�t maximum du cache est atteint, les premiers �l�ments ins�r�s dans le cache sont + supprim�s (en respectant l'ordre d'insertion dans le cache) jusqu'� ce que la limite du cache ne soit + plus d�pass�e.
+
+ Il est possible d'associer � chaque �l�ment du cache une date-heure d'insertion.
+ Si aucune date-heure n'est renseign�e, alors la date-heure courante est prise en compte.
+ Ce m�canisme permet de v�rifier si un �l�ment stock� dans le cache n�cessite une mise � jour ou + non.
+
+ Voici un exemple d'utilisation du cache de la biblioth�que QxOrm (fonctions du namespace + qx::cache) :
+
+ + + + + + + +
+
// D�fini le co�t maximum du cache � 500
+qx::cache::max_cost(500);
+
+// R�cup�re une liste de 'author' de la base de donn�es
+boost::shared_ptr< QList<author> > list_author;
+QSqlError daoError = qx::dao::fetch_all(list_author);
+
+// Ins�re la liste de 'author' dans le cache
+qx::cache::set("list_author", list_author);
+
+// R�cup�re une liste de 'blog' de la base de donn�es
+QSharedPointer< std::vector<blog> > list_blog;
+daoError = qx::dao::fetch_all(list_blog);
+
+// Ins�re la liste de 'blog' dans le cache (co�t = nombre de 'blog')
+qx::cache::set("list_blog", list_blog, list_blog.count());
+
+// Pointeur vers un objet de type 'comment'
+comment_ptr my_comment;
+my_comment.reset(new comment(50));
+daoError = qx::dao::fetch_by_id(my_comment);
+
+// Ins�re le 'comment' dans le cache en pr�cisant une date-heure d'insertion
+qx::cache::set("comment", my_comment, 1, my_comment->dateModif());
+
+// R�cup�re la liste de 'blog' stock�e dans le cache
+list_blog = qx::cache::get< QSharedPointer< std::vector<blog> > >("list_blog");
+
+// R�cup�re la liste de 'blog' sans pr�ciser le type
+qx_bool bGetOk = qx::cache::get("list_blog", list_blog);
+
+// Supprime du cache la liste de 'author'
+bool bRemoveOk = qx::cache::remove("list_author");
+
+// Compte le nombre d'�l�ments du cache
+long lCount = qx::cache::count();
+
+// R�cup�re le co�t actuel des �l�ments stock�s dans le cache
+long lCurrentCost = qx::cache::current_cost();
+
+// V�rifie qu'un �l�ment associ� � la cl� "comment" existe dans le cache
+bool bExist = qx::cache::exist("comment");
+
+// R�cup�re le 'comment' stock� dans le cache avec sa date-heure d'insertion
+QDateTime dt;
+bGetOk = qx::cache::get("comment", my_comment, dt);
+
+// Vide le cache
+qx::cache::clear();
+
+
+
+

+ Comment g�n�rer le sch�ma SQL (cr�ation et mise � jour des tables) en fonction des + classes persistantes C++ d�finies dans le contexte QxOrm ?

+ + + + + + + + + +
+ Il est recommand� d'utiliser l'application QxEntityEditor pour g�rer cette + probl�matique.
+
+ La biblioth�que QxOrm ne fournit pas de m�canisme pour g�rer automatiquement la cr�ation et mise � + jour des tables dans la base de donn�es.
+ En effet, la fonction qx::dao::create_table<T> doit �tre utilis�e uniquement pour cr�er + des prototypes.
+ Il est fortement recommand� d'utiliser un outil sp�cifique � chaque SGBD pour cr�er et maintenir les + tables de la base de donn�es (par exemple Navicat pour MySql, pgAdmin pour + PostgreSQL, SQLite Manager pour SQLite, etc.).
+ De plus, un outil sp�cifique � chaque SGBD permet d'appliquer certaines optimisations (ajout d'index + par exemple).
+
+ Cependant, il peut �tre int�ressant pour certaines applications de ne pas avoir � g�rer manuellement + les tables de la base de donn�es.
+ Dans ce cas, il est possible de cr�er une fonction C++ pour parcourir la liste des classes + persistantes enregistr�es dans le contexte QxOrm (en utilisant le moteur d'introspection de la + biblioth�que) et ainsi cr�er un script SQL de g�n�ration et mise � jour des tables de la base de + donn�es.
+
+ La biblioth�que QxOrm fournit une fonction C++ cr��e uniquement � titre d'exemple : elle peut donc + servir de base de travail pour cr�er sa propre fonction de g�n�ration de script SQL.
+ Cette fonction se trouve dans le fichier ./src/QxRegister/QxClassX.cpp et se nomme QString + qx::QxClassX::dumpSqlSchema().
+ Elle g�n�re un script SQL et le renvoie sous forme de QString : il est possible d'adapter cette + fonction pour g�n�rer un fichier contenant le script SQL ou bien appliquer chaque instruction SQL + directement au SGBD.
+
+ Voici un exemple d'impl�mentation propos� par dodobibi pour g�rer + une base PostgreSQL : cet exemple g�re les �volutions futures de son application (ajout de + colonnes dans une table existante, ajout d'index sur une colonne existante, etc.).
+ Au lancement de l'application, le num�ro de version est indiqu� de la fa�on suivante :
+
+ + + + + + + +
+
QApplication app(argc, argv);
+app.setProperty("DomainVersion", 1); // Version increment�e � chaque compilation et diffusion de l'application
+
+
+ Une table de la base de donn�es permet de stocker le num�ro de version courant.
+ Une classe persistante C++ est mapp�e sur cette table de la fa�on suivante :
+
+ + + + + + + +
+
#ifndef _DATABASE_VERSION_H_
+#define _DATABASE_VERSION_H_
+ 
+class MY_DLL_EXPORT DatabaseVersion
+{
+public:
+  QString name;
+  long version;
+};
+
+QX_REGISTER_HPP_MY_APP(DatabaseVersion, qx::trait::no_base_class_defined, 0)
+
+#endif // _DATABASE_VERSION_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/DatabaseVersion.h"
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_MY_APP(DatabaseVersion)
+
+namespace qx {
+template <> void register_class(QxClass<DatabaseVersion> & t)
+{
+  t.id(& DatabaseVersion::name, "name");
+  t.data(& DatabaseVersion::version, "version");
+}}
+
+
+ Avec la classe DatabaseVersion, il est possible de v�rifier si la version de la base de donn�es + est � jour.
+ C'est le r�le de la fonction isDatabaseVersionOld() :
+
+ + + + + + + +
+
bool isDatabaseVersionOld()
+{
+  DatabaseVersion dbVersion;
+  dbVersion.name = "MyAppName";
+  QSqlError err = qx::dao::fetch_by_id(dbVersion);
+  if (err.isValid()) { qAssert(false); return false; }
+  return (dbVersion.version < qApp->property("DomainVersion").toInt());
+}
+
+
+ Si au lancement de l'application, la fonction isDatabaseVersionOld() renvoie true, alors + la mise � jour de la base de donn�es est effectu�e de la fa�on suivante :
+
+ + + + + + + +
+
void updateDatabaseVersion()
+{
+  try
+  {
+    int domainVersion = qApp->property("DomainVersion").toInt();
+
+    // On se connecte avec un utilisateur de la base de donn�es qui a les droits de modifications du sch�ma
+    QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
+    db.setUserName("MyAdminLogin");
+    db.setPassword("MyAdminPassword");
+
+    // On s'assure que la session d�marre une transaction et l�ve une exception � la moindre erreur
+    qx::QxSession session(db, true, true);
+
+    // On "fetch" la version de la base de donn�es avec un verrou pour �viter les modifications concurrentes !
+    // Si plusieurs utilisateurs lancent l'application en m�me temps et qu'une mise � jour
+    // est n�cessaire, le premier fera la mise � jour, et les autres seront en attente
+    DatabaseVersion dbVersion;
+    session.fetchByQuery(qx_query("WHERE name='MyAppName' FOR UPDATE"), dbVersion);
+
+    // Pour les autres utilisateurs, une fois le verrou lev�, on v�rifie si la mise � jour est toujours n�cessaire
+    if (dbVersion.version >= domainVersion) { return; }
+
+    // On ex�cute chaque instruction SQL avec la variable "query"
+    QSqlQuery query(db);
+
+    // On r�cup�re toutes les classes persistantes C++ enregistr�es dans le contexte QxOrm
+    qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
+    if (! pAllClasses) { qAssert(false); return; }
+
+    // on r�cup�re la liste des tables existantes dans la base (fonction de Qt)
+    QStringList tables = db.tables();
+
+    for (long k = 0; k < pAllClasses->count(); k++)
+    {
+      qx::IxClass * pClass = pAllClasses->getByIndex(k);
+      if (! pClass) { continue; }
+
+      // Filtre les classes non persistantes
+      if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) { continue; }
+
+      // Filtre les classes � jour : si la version de pClass est <= � la version enregistr�e dans la base, la mise � jour n'est pas n�cessaire
+      if (pClass->getVersion() <= dbVersion.version) { continue; }
+
+      // On cr�e la table si elle n'existe pas, et on d�finit son propri�taire
+      if (! tables.contains(pClass->getName()))
+      {
+        query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);"
+                   "ALTER TABLE " + pClass->getName() + " OWNER TO \"MyAdminLogin\";");
+        session += query.lastError();
+      }
+
+      // On ajoute les colonnes � la table si elles n'existent pas
+      qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
+      for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
+      {
+        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
+        if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
+
+        query.exec("ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";");
+        session += query.lastError();
+
+        if (p->getIsPrimaryKey()) // PRIMARY KEY
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getAllPropertyBagKeys().contains("INDEX")) // INDEX
+        {
+          query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
+                     " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getNotNull()) // NOT NULL
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
+          session += query.lastError();
+        }
+
+        if (p->getAutoIncrement()) // AUTO INCREMENT
+        {
+          query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
+                     "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"MyAdminLogin\"; "
+                     "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
+                     "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
+          session += query.lastError();
+        }
+
+        if (p->getDescription() != "") // DESCRIPTION
+        {
+          // $$ceci est un texte ne n�cessitant pas de caract�res d'�chappement dans postgres grace aux doubles dolars$$
+          query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
+          session += query.lastError();
+        }
+      }
+    }
+
+    // On enregistre la version courante de la base de donn�es
+    dbVersion.version = domainVersion;
+    session.save(dbVersion);
+
+    // Fin du block "try" : la session est d�truite => commit ou rollback automatique
+    // De plus, un commit ou rollback sur la transaction l�ve automatiquement le verrou pos� pr�c�demment
+  }
+  catch (const qx::dao::sql_error & err)
+  {
+    QSqlError sqlError = err.get();
+    qDebug() << sqlError.databaseText();
+    qDebug() << sqlError.driverText();
+    qDebug() << sqlError.number();
+    qDebug() << sqlError.type();
+  }
+}
+
+
+ Remarque : le code pr�c�dent (tout comme la fonction qx::QxClassX::dumpSqlSchema()) peut �tre modifi� pour s'adapter aux + besoins sp�cifiques d'une application.
+ Par exemple, il pourrait �tre int�ressant de cr�er par d�faut une seconde table (en plus de la table + DatabaseVersion) pour enregistrer la liste des classes persistantes enregistr�es dans le + contexte QxOrm : ainsi, au lieu d'utiliser la fonction propos�e par Qt "db.tables()", il serait + possible de r�cup�rer toutes les tables mapp�es sur des classes persistantes avec des informations + suppl�mentaires (num�ro de version pour chaque table, nombre de colonnes enregistr�es dans le contexte + QxOrm, description de chaque table, etc.). +
+
+

+ Comment associer un type SQL � une classe C++ ?

+ + + + + + + + + +
+ Chaque base de donn�es propose des types SQL diff�rents pour stocker l'information.
+ La biblioth�que QxOrm propose une association par d�faut pour les classes C++ les plus fr�quemment + utilis�es dans un programme.
+ Voici cette association par d�faut :
+
+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ Si le type SQL propos� par d�faut par la biblioth�que QxOrm ne correspond pas � la base de donn�es + utilis�e, il peut facilement �tre modifi� (de mani�re globale � toute l'application) en utilisant la + collection suivante :
+
+ + + + + + + +
+
QHash<QString, QString> * lstSqlType = qx::QxClassX::getAllSqlTypeByClassName();
+lstSqlType->insert("QString", "VARCHAR(255)");
+lstSqlType->insert("std::string", "VARCHAR(255)");
+// etc.
+
+
+ Pour modifier le type SQL de mani�re sp�cifique pour une colonne d'une table de la base de donn�es, il + faut d�finir le type SQL dans la fonction de mapping de QxOrm :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<MyClass> & t)
+{
+  //...
+  IxDataMember * p =  t.data(& MyClass::m_MyProperty, "my_property");
+  p->setSqlType("VARCHAR(255)");
+  //...
+}}
+
+
+ Pour les classes non support�es par d�faut par la biblioth�que QxOrm (voir cette + Question-R�ponse de la FAQ : Comment persister un type dont on + ne poss�de pas le code source (classe provenant d'une biblioth�que tierce par exemple) ?), + il est possible d'associer un type SQL par d�faut en utilisant la macro suivante (en dehors de tout + namespace) :
+
+ + + + + + + +
+
QX_REGISTER_TRAIT_GET_SQL_TYPE(MyClass, "my_sql_type")
+
+
+
+

+ Comment utiliser le module QxValidator pour valider automatiquement les donn�es + ?

+ + + + + + + + + +
+ Le module QxValidator + de la biblioth�que QxOrm permet d'ajouter des contraintes sur les propri�t�s enregistr�es dans + le contexte QxOrm.
+ Ces contraintes sont d�finies dans la m�thode de mapping : void + qx::register_class<T>.
+ Si pour une instance de classe donn�e, au moins une contrainte n'est pas respect�e, alors l'instance + est consid�r�e comme invalide : l'objet ne peut alors pas �tre sauvegard� en base de donn�es + (INSERT ou UPDATE).
+
+ Il est �galement possible d'utiliser le module QxValidator pour valider les donn�es au niveau + de la couche pr�sentation de l'application : si les donn�es saisies par un utilisateur ne sont pas + valides, un message d'erreur peut �tre signal�, il n'est alors pas n�cessaire d'essayer d'enregistrer + l'instance courante en base de donn�es.
+ Les r�gles de validation n'ont pas besoin d'�tre dupliqu�es : elles peuvent �tre utilis�es aussi bien + par la couche pr�sentation que par la couche d'acc�s aux donn�es de l'application.
+
+ Voici la description de quelques classes du module QxValidator : +
    +
  • qx::IxValidator : + chaque contrainte d�finie dans la fonction de mapping void qx::register_class<T> est + associ�e � une interface de type qx::IxValidator ;
  • +
  • qx::IxValidatorX : + pour une classe donn�e, la liste des contraintes est associ�e � une interface de type + qx::IxValidatorX. Cette collection peut �tre parcourue � l'ex�cution du programme : �a peut + �tre int�ressant par exemple pour g�n�rer le sch�ma SQL et prendre en compte les contraintes au + niveau de la base de donn�es (voir la Q&R de la FAQ : Comment g�n�rer le sch�ma SQL (cr�ation et mise � jour des tables) en fonction + des classes persistantes C++ d�finies dans le contexte QxOrm ?) ; +
  • +
  • qx::QxInvalidValueX : au moment du processus de validation, lorsqu'une + instance n'est pas valide, la liste des contraintes non respect�es est repr�sent�e par une + collection de type qx::QxInvalidValueX ;
  • +
  • qx::QxInvalidValue : chaque �l�ment de cette collection est de type + qx::QxInvalidValue et contient un message d'erreur (description expliquant pourquoi + l'instance est invalide). +
  • +
+ Le module QxValidator g�re automatiquement la notion d'h�ritage de classe : si des contraintes + sont d�finies au niveau de la classe de base, alors elles seront automatiquement v�rifi�es pour chaque + validation d'une classe d�riv�e.
+
+ Voici un exemple d'utilisation du module QxValidator avec une classe 'person' :
+
+ * fichier 'person.h' :
+ + + + + + + +
+
#ifndef _CLASS_PERSON_H_
+#define _CLASS_PERSON_H_
+ 
+class person
+{
+
+public:
+
+   enum sex { male, female, unknown };
+
+   long        _id;
+   QString     _firstName;
+   QString     _lastName;
+   QDateTime   _birthDate;
+   sex         _sex;
+
+   person() : _id(0), _sex(unknown) { ; }
+   person(long id) : _id(id), _sex(unknown) { ; }
+   virtual ~person() { ; }
+
+private:
+
+   void isValid(qx::QxInvalidValueX & invalidValues);
+
+};
+
+QX_REGISTER_HPP_MY_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _CLASS_PERSON_H_
+
+
+ * fichier 'person.cpp' :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/person.h"
+#include "../include/global_validator.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_MY_EXE(person)
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+   t.id(& person::_id, "id");
+
+   t.data(& person::_firstName, "firstName");
+   t.data(& person::_lastName, "lastName");
+   t.data(& person::_birthDate, "birthDate");
+   t.data(& person::_sex, "sex");
+
+   QxValidatorX<person> * pAllValidator = t.getAllValidator();
+   pAllValidator->add_NotEmpty("firstName");
+   pAllValidator->add_NotEmpty("lastName", "a person must have a lastname");
+   pAllValidator->add_CustomValidator(& person::isValid);
+   pAllValidator->add_CustomValidator_QVariant(& validateFirstName, "firstName");
+   pAllValidator->add_CustomValidator_DataType<QDateTime>(& validateDateTime, "birthDate");
+}}
+
+void person::isValid(qx::QxInvalidValueX & invalidValues)
+{
+   // Cette m�thode est appel�e automatiquement par le module 'QxValidator' :
+   // - avant d'ins�rer ou mettre � jour une instance de type 'person' par les fonctions du namespace 'qx::dao' ;
+   // - en utilisant la fonction 'qx::validate()' avec pour param�tre une instance de type 'person'.
+
+   // L'enregistrement de la m�thode 'person::isValid()' est effectu� dans la fonction de mapping :
+   // pAllValidator->add_CustomValidator(& person::isValid);
+
+   // Dans cette m�thode, il est possible de v�rifier n'importe quelle valeur de l'instance courante
+   // Si une propri�t� est non valide, il suffit d'ins�rer un �l�ment dans la collection 'invalidValues'
+
+   // Remarque : cette m�thode est d�clar�e 'private' pour forcer l'utilisateur � utiliser la fonction 'qx::validate()'
+   // Mais ce n'est pas une obligation : cette m�thode peut �tre d�clar�e 'public' ou 'protected'
+
+   // Par exemple, si on souhaite v�rifier la propri�t� '_sex' d'une personne :
+   if ((_sex != male) && (_sex != female))
+   { invalidValues.insert("le sexe de la personne doit �tre d�fini : masculin ou f�minin"); }
+}
+
+
+ * fichier 'global_validator.h' :
+ + + + + + + +
+
// Les fonctions suivantes ('validateFirstName()' et 'validateDateTime()') sont globales (non li�es � une classe)
+// Elles peuvent ainsi �tre utilis�es par plusieurs classes pour valider une propri�t� (par exemple : valider la saisie d'une adresse IP).
+// Ces fonctions seront appel�es automatiquement par le module 'QxValidator' :
+// - avant d'ins�rer ou mettre � jour une instance de classe par les fonctions du namespace 'qx::dao' ;
+// - en utilisant la fonction 'qx::validate()'.
+ 
+void validateFirstName(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Ici, on peut tester la valeur d'une propri�t� (convertie en type QVariant)
+   // Si la valeur est invalide, il suffit d'ins�rer un message � la collection 'invalidValues'
+
+   // Par exemple, si la valeur ne doit jamais �tre �gale � "admin" :
+   if (value.toString() == "admin")
+   { invalidValues.insert("la valeur ne peut pas �tre �gale � 'admin'"); }
+}
+
+void validateDateTime(const QDateTime & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Ici, on peut tester la valeur d'une propri�t� (en conservant son vrai type, ici il s'agit de tester une date-heure de type 'QDateTime')
+   // Si la valeur est invalide, il suffit d'ins�rer un message � la collection 'invalidValues'
+
+   // Par exemple, si la date-heure doit forc�ment �tre renseign�e :
+   if (! value.isValid())
+   { invalidValues.insert("la date-heure doit �tre renseign�e et doit �tre valide"); }
+}
+
+
+ * fichier 'main.cpp' :
+ + + + + + + +
+
person personValidate;
+personValidate._lastName = "admin";
+qx::QxInvalidValueX invalidValues = qx::validate(personValidate);
+QString sInvalidValues = invalidValues.text();
+qDebug("[QxOrm] test 'QxValidator' module :\n%s", qPrintable(sInvalidValues));
+
+
+ A l'ex�cution de ce bout de code, l'instance 'personValidate' est non valide : la collection + 'invalidValues' contient quatre �l�ments :
+ - "la valeur de la propri�t� 'firstName' ne peut pas �tre vide" ;
+ - "le sexe de la personne doit �tre d�fini : masculin ou f�minin" ;
+ - "la valeur ne peut pas �tre �gale � 'admin'" ;
+ - "la date-heure doit �tre renseign�e et doit �tre valide".
+
+ Le module QxValidator fournit plusieurs validateurs pour effectuer des v�rifications basiques : +
    +
  • add_NotNull() : v�rifie que la valeur n'est pas nulle ;
  • +
  • add_NotEmpty() : v�rifie que la cha�ne de caract�res n'est pas vide ;
  • +
  • add_MinValue() : v�rifie que la valeur num�rique n'est pas inf�rieure au param�tre ;
  • +
  • add_MaxValue() : v�rifie que la valeur num�rique n'est pas sup�rieure au param�tre ;
  • +
  • add_Range() : v�rifie que la valeur num�rique est comprise entre les deux param�tres ; +
  • +
  • add_MinDecimal() : v�rifie que la valeur d�cimale n'est pas inf�rieure au param�tre ; +
  • +
  • add_MaxDecimal() : v�rifie que la valeur d�cimale n'est pas sup�rieure au param�tre ; +
  • +
  • add_RangeDecimal() : v�rifie que la valeur d�cimale est comprise entre les deux + param�tres ;
  • +
  • add_MinLength() : v�rifie que la cha�ne de caract�res a une taille minimale ;
  • +
  • add_MaxLength() : v�rifie que la cha�ne de caract�res ne d�passe pas un certain nombre de + caract�res ;
  • +
  • add_Size() : v�rifie que la taille de la cha�ne de caract�res est comprise entre les deux + param�tres ;
  • +
  • add_DatePast() : v�rifie que la date-heure est dans le pass� ;
  • +
  • add_DateFuture() : v�rifie que la date-heure est dans le futur ;
  • +
  • add_RegExp() : v�rifie que la cha�ne de caract�res est compatible avec l'expression + r�guli�re pass�e en param�tre ;
  • +
  • add_EMail() : v�rifie que la cha�ne de caract�res correspond � un e-mail.
  • +
+ Comme dans l'exemple de la classe 'person', il est possible de d�finir �galement des + validateurs personnalis�s : ce sont des fonctions ou m�thodes de classe qui seront appel�es + automatiquement par le module QxValidator pour valider une propri�t� ou une instance de + classe.
+ Il existe trois types de validateurs personnalis�s : +
    +
  • add_CustomValidator() : m�thode de classe, la signature de la m�thode doit �tre "void + my_class::my_method(qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_QVariant() : fonction globale avec type QVariant (propri�t� + convertie en QVariant), la signature de la fonction doit �tre "void my_validator(const + QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_DataType() : fonction globale avec le type r�el de la propri�t�, la + signature de la fonction doit �tre "void my_validator(const T &, const qx::IxValidator *, + qx::QxInvalidValueX &)" ;
  • +
+ Remarque : � chaque validateur peut �tre associ� un groupe (param�tre optionnel pour chaque + m�thode add_XXX() de la classe qx::IxValidatorX).
+ Il est ainsi possible de cr�er des groupes de validation suivant le contexte d'ex�cution : par + exemple, valider la saisie d'une personne sur une IHM A ne n�cessite peut-�tre pas les m�mes + v�rifications que valider une personne sur une IHM B.
+ Pour ex�cuter la validation d'une instance pour un groupe donn� (par exemple "myGroup"), il + faut appeler la fonction suivante : "qx::QxInvalidValueX invalidValues = + qx::validate(personValidate, "myGroup");".
+
+ Autre remarque : le module QxValidator d�finit des messages par d�faut lorsqu'une + contrainte n'est pas v�rifi�e.
+ Il est possible de red�finir ces messages par d�faut en modifiant la collection suivante : "QHash + * lstMessage = QxClassX::getAllValidatorMessage(); + ".
+ Par exemple : "lstMessage->insert("min_value", "la valeur '%NAME%' doit �tre inf�rieure ou �gale � + '%CONSTRAINT%'");".
+ Les champs %NAME% et %CONSTRAINT% seront automatiquement remplac�s par les valeurs + correspondantes.
+ Pour modifier le message pour un validateur donn� (et non de mani�re globale), il faut utiliser le + param�tre optionnel disponible pour les m�thodes add_XXX() de la classe + qx::IxValidatorX.
+
+

+ Comment utiliser l'interface qx::IxPersistable ?

+ + + + + + + + + +
+ L'interface qx::IxPersistable (ou classe abstraite) dispose uniquement de m�thodes + virtuelles pures.
+ Elle permet d'avoir une classe de base commune pour appeler les fonctions de persistance sans + conna�tre le type r�el de l'instance courante (notion de polymorphisme).
+ La biblioth�que QxOrm n'impose pas de travailler avec une classe de base pour enregistrer un type + persistant dans le contexte QxOrm, cependant il est parfois utile de disposer d'une interface afin + d'�crire des algorithmes g�n�riques.
+
+ La classe qx::IxPersistable met � disposition les m�thodes virtuelles suivantes (pour plus + d'informations sur ces m�thodes, rendez-vous sur la documentation en ligne de la biblioth�que QxOrm) :
+
+
+
virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchAll(qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList());
+virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection() const;
+virtual qx::IxClass * qxClass() const;
+
+
+ Par exemple, � partir d'une liste de pointeurs de type qx::IxPersistable, il est possible + d'enregistrer les �l�ments dans plusieurs tables diff�rentes de la base de donn�es de la fa�on + suivante :
+
+ + + + + + + +
+
QList<qx::IxPersistable *> lst = ...;
+foreach(qx::IxPersistable * p, lst)
+{
+   QSqlError daoError = p->qxSave();
+   if (daoError.isValid()) { /* an error occured */ }
+   // etc...
+}
+
+
+ Pour impl�menter l'interface qx::IxPersistable, il faut : +
    +
  • faire h�riter la classe persistante du type qx::IxPersistable ;
  • +
  • dans la d�finition de la classe (myClass.h par exemple), ajouter la macro + QX_PERSISTABLE_HPP(myClass) ; +
  • +
  • dans l'impl�mentation de la classe (myClass.cpp par exemple), ajouter la macro + QX_PERSISTABLE_CPP(myClass). +
  • +
+ Par exemple, impl�menter l'interface qx::IxPersistable pour la classe author du tutoriel qxBlog revient � �crire (les + modifications par rapport au code du tutoriel apparaissent en gras) :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author : public qx::IxPersistable
+{
+   QX_PERSISTABLE_HPP(author)
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- propri�t�s
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- constructeur, destructeur virtuel
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- m�thodes
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+QX_PERSISTABLE_CPP(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+ Remarque : le projet de test ./test/qxDllSample/dll1/ met � disposition une sorte de + 'super classe de base' : la classe qx::QxPersistable impl�mente l'interface qx::IxPersistable + et h�rite de QObject.
+ Le m�canisme SIGNAL-SLOT de Qt peut donc �tre utilis� avec cette classe, ce qui peut �tre + int�ressant par exemple pour la notion de d�clencheurs (ou trigger).
+ La classe qx::QxPersistable met �galement � disposition des m�thodes virtuelles qu'il est + possible de surcharger pour g�rer notamment la notion de validation des donn�es avec le module QxValidator.
+ La classe qx::QxPersistable ne fait pas partie de la distribution de QxOrm, mais il est + possible de la copier-coller dans un projet afin de profiter de ses fonctionnalit�s : + +
+

+ Comment utiliser le moteur de relations pour r�cup�rer des donn�es associ�es � + plusieurs tables ?

+ + + + + + + + + +
+ La biblioth�que QxOrm supporte quatre types de relations pour lier les classes C++ enregistr�es dans + le contexte QxOrm : one-to-one, one-to-many, many-to-one et + many-to-many.
+ Pour plus de d�tails sur la d�finition de ces relations, il est conseill� de lire le tutoriel qxBlog.
+ Nous allons d�tailler dans cette Q&R les diff�rentes m�thodes de r�cup�ration des donn�es (module QxDao, fonctions du namespace qx::dao) : + + Le premier param�tre des fonctions fetch_by_id_with_relation, fetch_all_with_relation et fetch_by_query_with_relation correspond � la liste des relations � requ�ter.
+ Cette liste de relations peut contenir les �l�ments suivants : +
    +
  • identifiant d'une relation : chaque relation poss�de une cl� d�finie au niveau de la fonction de + param�trage qx::register_class<T> ;
  • +
  • le mot-cl� "*" signifie "r�cup�rer toutes les relations d�finies dans la fonction de + param�trage qx::register_class<T> sur un niveau" ;
  • +
  • le mot-cl� "->" signifie jointure de type "LEFT OUTER JOIN" (jointure par d�faut + de la biblioth�que QxOrm) ;
  • +
  • le mot-cl� ">>" signifie jointure de type "INNER JOIN" entre deux tables.
  • +
+ Remarque : en utilisant le mot-cl� "*" pour indiquer "toutes les relations sur un + niveau", les appels suivants sont �quivalents : +
    +
  • qx::dao::fetch_by_id_with_relation("*", ...) == + qx::dao::fetch_by_id_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_by_query_with_relation("*", ...) == + qx::dao::fetch_by_query_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_all_with_relation("*", ...) == + qx::dao::fetch_all_with_all_relation(...). +
  • +
+
+ Exemple : � partir du tutoriel qxBlog, il est possible de r�cup�rer les donn�es suivantes avec + une seule requ�te :
+
+ 1- r�cup�rer un blog et son author ;
+ 2- pour l'author valoris�, r�cup�rer tous les blog qu'il a �crit ;
+ 3- pour chaque blog que l'author a �crit, r�cup�rer tous les comment + associ�s.
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("author_id->list_blog->list_comment", my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Autre exemple : il est �galement possible de cr�er une liste de relations � r�cup�rer, comme + ceci par exemple :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QStringList relation;
+relation << "author_id->list_blog->list_comment";
+relation << "author_id->list_blog->list_category";
+relation << "list_comment";
+relation << "list_category";
+QSqlError daoError = qx::dao::fetch_by_id_with_relation(relation, my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, 
+       category_7.category_id AS category_7_category_id_0, category_7.name AS category_7_name_0, category_7.description AS category_7_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN category_blog category_blog_7 ON blog.blog_id = category_blog_7.blog_id 
+LEFT OUTER JOIN category category_7 ON category_blog_7.category_id = category_7.category_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Autre exemple : pour r�cup�rer toutes les relations pour un niveau donn�, il faut utiliser le + mot-cl� "*".
+ Pour r�cup�rer toutes les donn�es de toutes les relations sur trois niveaux, il faut �crire :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("*->*->*", my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, blog_2.author_id AS blog_2_author_id_0_2, 
+       author_3.author_id AS author_3_author_id_0, author_3.name AS author_3_name_0, author_3.birthdate AS author_3_birthdate_0, author_3.sex AS author_3_sex_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, comment_6.blog_id AS comment_6_blog_id_0_6, 
+       blog_7.blog_id AS blog_7_blog_id_0, blog_7.blog_text AS blog_7_blog_text_0, blog_7.date_creation AS blog_7_date_creation_0, blog_7.author_id AS blog_7_author_id_0_7, 
+       author_8.author_id AS author_8_author_id_0, author_8.name AS author_8_name_0, author_8.birthdate AS author_8_birthdate_0, author_8.sex AS author_8_sex_0, 
+       comment_9.comment_id AS comment_9_comment_id_0, comment_9.blog_id AS comment_9_blog_id_0, comment_9.comment_text AS comment_9_comment_text_0, comment_9.date_creation AS comment_9_date_creation_0, 
+       category_10.category_id AS category_10_category_id_0, category_10.name AS category_10_name_0, category_10.description AS category_10_description_0, 
+       category_11.category_id AS category_11_category_id_0, category_11.name AS category_11_name_0, category_11.description AS category_11_description_0, 
+       blog_12.blog_id AS blog_12_blog_id_0, blog_12.blog_text AS blog_12_blog_text_0, blog_12.date_creation AS blog_12_date_creation_0, blog_12.author_id AS blog_12_author_id_0_12, 
+       author_13.author_id AS author_13_author_id_0, author_13.name AS author_13_name_0, author_13.birthdate AS author_13_birthdate_0, author_13.sex AS author_13_sex_0, 
+       comment_14.comment_id AS comment_14_comment_id_0, comment_14.blog_id AS comment_14_blog_id_0, comment_14.comment_text AS comment_14_comment_text_0, comment_14.date_creation AS comment_14_date_creation_0, 
+       category_15.category_id AS category_15_category_id_0, category_15.name AS category_15_name_0, category_15.description AS category_15_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN author author_3 ON author_3.author_id = blog_2.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN blog blog_7 ON blog_7.blog_id = comment_6.blog_id 
+LEFT OUTER JOIN author author_8 ON author_8.author_id = blog_7.author_id 
+LEFT OUTER JOIN comment comment_9 ON comment_9.blog_id = blog_7.blog_id 
+LEFT OUTER JOIN category_blog category_blog_10 ON blog_7.blog_id = category_blog_10.blog_id 
+LEFT OUTER JOIN category category_10 ON category_blog_10.category_id = category_10.category_id 
+LEFT OUTER JOIN category_blog category_blog_11 ON blog.blog_id = category_blog_11.blog_id 
+LEFT OUTER JOIN category category_11 ON category_blog_11.category_id = category_11.category_id 
+LEFT OUTER JOIN category_blog category_blog_12 ON category_11.category_id = category_blog_12.category_id 
+LEFT OUTER JOIN blog blog_12 ON category_blog_12.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN author author_13 ON author_13.author_id = blog_12.author_id 
+LEFT OUTER JOIN comment comment_14 ON comment_14.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN category_blog category_blog_15 ON blog_12.blog_id = category_blog_15.blog_id 
+LEFT OUTER JOIN category category_15 ON category_blog_15.category_id = category_15.category_id 
+WHERE blog.blog_id = :blog_id
+
+
+
+

+ Comment appeler une proc�dure stock�e ou une requ�te SQL personnalis�e + ?

+ + + + + + + + + +
+ La biblioth�que QxOrm fournit deux fonctions pour appeler une proc�dure stock�e ou une requ�te SQL + personnalis�e : + + Le premier param�tre de ces deux fonctions, de type qx::QxSqlQuery (ou + qx_query), correspond � la proc�dure stock�e ou � la requ�te SQL personnalis�e.
+ Pour plus d'informations sur la classe qx::QxSqlQuery, rendez-vous sur cette Q&R de la FAQ de QxOrm : Comment construire une requ�te pour interroger la base de donn�es sans + �crire de SQL avec la classe qx::QxSqlQuery ?
+
+ La fonction qx::dao::execute_query<T>() est une fonction template : le type T + doit �tre enregistr� dans le contexte QxOrm (fonction qx::register_class<T>).
+ Toutes les donn�es renvoy�es par la proc�dure stock�e ou la requ�te SQL personnalis�e qui pourront + �tre associ�es aux membres des classes C++ (de type T) seront valoris�es automatiquement.
+ Une recherche automatique est effectu�e sur le nom des champs associ�s aux donn�es.
+ Voici un exemple d'utilisation (disponible dans le projet qxBlog du package QxOrm) :
+
+ + + + + + + +
+
// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+qx_query testStoredProcBis("SELECT * FROM author");
+daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+qx::dump(authorX);
+
+

+ La fonction qx::dao::call_query() n'est pas une fonction template : les r�sultats de + la requ�te doivent �tre parcourus manuellement sur la classe qx::QxSqlQuery (ou + qx_query).
+ Pour r�cup�rer un param�tre de sortie (qui doit �tre pass� � la requ�te en tant que QSql::Out + ou QSql::InOut), il suffit d'utiliser la m�thode : QVariant qx::QxSqlQuery::boundValue(const + QString & sKey) const;.
+
+ Pour parcourir la liste des r�sultats de la requ�te, il faut utiliser les m�thodes suivantes :
+ * long qx::QxSqlQuery::getSqlResultRowCount() const;
+ * long qx::QxSqlQuery::getSqlResultColumnCount() const;
+ * QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const;
+ * QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) const;
+ * QVector qx::QxSqlQuery::getSqlResultAllColumns() const;
+ * void qx::QxSqlQuery::dumpSqlResult();
+
+ Voici un exemple d'utilisation avec la fonction qx::dao::call_query() :
+
+ + + + + + + +
+
qx_query query("CALL MyStoredProc(:param1, :param2)");
+query.bind(":param1", "myValue1");
+query.bind(":param2", 5024, QSql::InOut);
+QSqlError daoError = qx::dao::call_query(query);
+QVariant vNewValue = query.boundValue(":param2");
+query.dumpSqlResult();
+
+
+
+

+ Comment utiliser la classe qx::QxDaoAsync pour appeler des requ�tes de mani�re + asynchrone (multi-thread) ?

+ + + + + + + + + +
+ Il peut �tre parfois int�ressant d'ex�cuter certaines requ�tes � la base de donn�es de mani�re + asynchrone (multi-thread), par exemple pour �viter de bloquer une IHM si une requ�te est trop longue � + s'ex�cuter.
+ Pour simplifier les requ�tes asynchrones, la biblioth�que QxOrm fournit la classe qx::QxDaoAsync.
+ Cette classe ex�cute une requ�te dans un thread d�di� et renvoie un SIGNAL + queryFinished() lorsque la requ�te est termin�e.
+ Pour utiliser la classe qx::QxDaoAsync, il suffit de : +
    +
  • v�rifier que la requ�te fait appel � une classe qui impl�mente l'interface qx::IxPersistable ;
  • +
  • cr�er une instance de type qx::QxDaoAsync (par exemple, une propri�t� membre d'une classe + d�rivant du type QWidget) ;
  • +
  • connecter un SLOT au SIGNAL qx::QxDaoAsync::queryFinished() (par exemple, + un SLOT d�fini dans une classe d�rivant du type QWidget) ;
  • +
  • ex�cuter une requ�te � la base de donn�es en utilisant l'une des m�thodes commen�ant par + async : qx::QxDaoAsync::asyncXXXX(). +
  • +
+ Voici un exemple d'utilisation avec une classe nomm�e MyWidget :
+
+ + + + + + + +
+
class MyWidget : public QWidget
+{ Q_OBJECT
+
+   //...
+   qx::QxDaoAsync m_daoAsync;
+   //...
+Q_SLOTS:
+   void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
+   //...
+
+};
+
+
+ Et voici l'impl�mentation de la classe MyWidget :
+
+ + + + + + + +
+
MyWidget::MyWidget() : QObject()
+{
+   //...
+   QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), 
+                    this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)));
+   //...
+}
+
+void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams)
+{
+   if (! pDaoParams) { return; }
+   qx::QxSqlQuery query = pDaoParams->query;
+   if (! daoError.isValid()) { ; }
+   // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
+   qx::IxPersistable_ptr ptr = pDaoParams->pInstance;
+   // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
+   qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances;
+   //...
+}
+
+
+
+

+ Comment utiliser le module QxModelView pour travailler avec le moteur + model/view de Qt (Qt widgets et vues QML) ?

+ + + + + + + + + +
+ Le module QxModelView + permet d'utiliser le moteur model/view + de Qt avec toutes les classes enregistr�es dans le contexte QxOrm : +
    +
  • Qt widgets : utilisation de QTableView ou QListView par exemple pour + afficher/modifier le contenu d'une table de base de donn�es ;
  • +
  • QML : toute propri�t� enregistr�e dans le contexte QxOrm est accessible en QML : le module QxModelView permet + ainsi de faciliter l'int�raction entre QML et les bases de donn�es.
  • +
+ L'interface qx::IxModel + propose une base commune pour tous les mod�les li�s aux classes persistantes d�clar�es dans le + contexte QxOrm. Les m�thodes de cette classe pr�fix�es par 'qx' appellent les fonctions du + namespace 'qx::dao' et communiquent donc directement avec la base de donn�es.
+
+ Le projet de test qxBlogModelView pr�sent dans le dossier ./test/ du package QxOrm + montre comment cr�er rapidement un mod�le et l'associer au moteur model/view de Qt (d'abord + dans un widget Qt, puis dans une vue QML).
+
+ 1- Exemple de cr�ation d'un mod�le pour afficher/modifier les donn�es de la table 'author' + (voir le tutoriel qxBlog pour la d�finition de la + classe 'author') dans un QTableView :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QTableView and display it
+QTableView tableView;
+tableView.setModel(pModel);
+tableView.show();
+
+
+ Ce qui donne le r�sultat suivant � l'ex�cution :
+
+ qx_model_view_01
+

+ 2- Voici un autre exemple en QML (en Qt5, le module QxModelView �tant + �galement compatible avec Qt4) :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QML view and display it
+QQuickView qmlView;
+qmlView.rootContext()->setContextProperty("myModel", pModel);
+qmlView.setSource(QUrl("qrc:/documents/main.qml"));
+qmlView.show();
+
+
+ Et voici le contenu du fichier 'main.qml' :
+
+ + + + + + + +
+
import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+Item {
+   width: 400
+   height: 300
+   Row {
+      height: 20
+      spacing: 20
+      Button {
+         text: "Clear"
+         onClicked: myModel.clear()
+      }
+      Button {
+         text: "Fetch All"
+         onClicked: myModel.qxFetchAll_()
+      }
+      Button {
+         text: "Save"
+         onClicked: myModel.qxSave_()
+      }
+   }
+   ListView {
+      y: 30
+      height: 270
+      model: myModel
+      delegate: Row {
+         height: 20
+         spacing: 10
+         Text { text: "id: " + author_id }
+         TextField {
+            text: name
+            onTextChanged: name = text
+         }
+      }
+   }
+}
+
+
+ Ce qui donne le r�sultat suivant � l'ex�cution :
+
+ qx_model_view_02
+
+ Comme on peut le constater dans le fichier 'main.qml', les propri�t�s 'author_id' et + 'name' du mod�le 'author' (variable myModel) sont accessibles automatiquement en + lecture/�criture (car elles ont �t� enregistr�es dans le contexte QxOrm).
+ De plus, l'interface qx::IxModel propose une liste de m�thodes accessibles en QML (utilisation de + Q_INVOKABLE) pour communiquer directement avec la base de donn�es : ainsi, le bouton + 'Save' de l'�cran ci-dessus enregistre le mod�le en base de donn�es depuis QML.
+
+ Remarque : un plugin de QxEntityEditor permet de g�n�rer automatiquement le code des + mod�les pour la gestion des relations. Il est ainsi possible de travailler avec des mod�les + imbriqu�s.
+
+

+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/home.html b/doc/qxorm_fr/home.html new file mode 100644 index 0000000..9b65c58 --- /dev/null +++ b/doc/qxorm_fr/home.html @@ -0,0 +1,491 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Accueil + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+

QxOrm (le moteur) + QxEntityEditor (l'�diteur graphique) = la meilleure + solution pour g�rer sa couche de donn�es persistante en C++/Qt !

+
+
+
QxOrm est une biblioth�que C++ de gestion de donn�es. + A partir d'une simple fonction de param�trage (que l'on peut + comparer avec un fichier de mapping Hibernate en Java), vous + aurez acc�s aux fonctionnalit�s suivantes :
+
    +
  • + Persistance + : support des bases de donn�es SQLite, MySQL, PostgreSQL, Oracle, MS SQL Server, MongoDB (gestion des relations 1-1, 1-n, + n-1 et n-n) ; +
  • +
  • + S�rialisation + des donn�es (flux JSON, binaire et XML) ;
  • +
  • + R�flexion + (ou + introspection + ) pour acc�der dynamiquement aux classes, attributs et invoquer des m�thodes ;
  • +
  • + Serveur web HTTP + + : serveur web compatible HTTP 1.1 autonome, performant, multi-plateforme et simple + d'utilisation ;
  • +
  • + API JSON + : interop�rabilit� avec d'autres technologies que C++/Qt (web services REST, applications + QML, langages de script).
  • +
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ QxEntityEditor est un �diteur graphique pour la biblioth�que QxOrm : QxEntityEditor + permet de g�rer graphiquement le mod�le d'entit�s.
+ QxEntityEditor est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et g�n�re du code + natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu� et mobile (Android, iOS, + Windows Phone, Raspberry Pi, etc.).
+ Un manuel utilisateur (documentation) d�di� � l'application QxEntityEditor + est disponible.
+
+ QxEntityEditor est bas� sur un syst�me de plugins et propose diverses fonctionnalit�s pour + importer/exporter le mod�le de donn�es : + + QxEntityEditor +

+
+
+ La biblioth�que QxOrm a pour objectif de simplifier le code C++ tout en offrant un maximum de + fonctionnalit�s.
+ Voici les principaux avantages de QxOrm : +
    +
  • non intrusif : la fonction de param�trage se trouve � + l'ext�rieur des classes. La signature des classes n'est donc pas + modifi�e. QxOrm peut donc �tre utilis� dans des projets + existants ; +
  • +
  • aucune n�cessit� d'appartenir � une hi�rarchie de + classes : les classes n'ont pas besoin de d�river d'un 'super + objet' ; +
  • +
  • pas de mapping XML ; +
  • +
  • 1 seul fichier <QxOrm.h> � inclure dans l'en-t�te + pr�compil� (precompiled-header recommand� pour optimiser les temps + de compilation) ; +
  • +
  • aucune n�cessit� d'utiliser le pr�-compilateur 'moc' fourni + par Qt ; +
  • +
  • v�rification des types � la compilation (utilisation intensive + de m�ta-programmation) ; +
  • +
  • compatible avec Visual C++ sous Windows, + GCC sous Linux, Clang sous Mac OS X, et MinGW sous Windows (d'autres environnements + et + plateformes seront test�s prochainement : mobiles, etc...) ; +
  • +
  • compatible avec le d�veloppement de biblioth�ques partag�es + (shared library, *.dll pour Windows, *.so pour Linux, + etc...). +
  • +
+
+

QxOrm est bas� sur la biblioth�que Qt (compatible Qt4, Qt5, Qt6) :

+ +

+ + + + + + + + + +
QtQt : biblioth�que compl�te : IHM + (QtGui), r�seau (QtNetwork), XML (QtXml), base de donn�es + (QtSql), etc...
+ La documentation est excellente et le code C++ �crit � partir + de cette biblioth�que est � la fois performant et simple de + compr�hension.
+ Depuis le rachat par Nokia puis Digia et sa nouvelle licence LGPL, Qt est + sans contexte la biblioth�que phare du moment.
+ QxOrm est compatible avec les principaux objets d�finis par Qt + : QObject, QString, QDate, QTime, QDateTime, QList, QHash, + QSharedPointer, QScopedPointer, etc...
+ Il est conseill� d'installer et d'utiliser la derni�re version + de Qt disponible � l'adresse suivante : http://www.qt.io/
+

+ +
+

QxOrm est divis� en sous-modules, voici un descriptif rapide :

+
    +
  • +

    QxDao : bas� sur le moteur QtSql de Qt, ce module + permet de communiquer (s�lection, modification, suppression, + transaction, etc...) avec de nombreuses bases de donn�es en mappant + chaque champ d'une table avec les propri�t�s d'une classe C++. Les + relations de type 1-1, 1-n, n-1 et n-n sont tr�s simples � + mettre en place dans le code C++. Ce module supporte la + programmation objet : h�ritage, polymorphisme, composition, + association ainsi que les collections (support des collections de + stl, boost et Qt : std::vector, std::list, + std::unordered_map, QList, QHash, etc...). +

    +
  • +
  • +

    QxRegister, QxDataMember et QxFunction : m�me si + ce n'est pas le but 1er de QxOrm, il est n�cessaire d'�muler le + m�canisme de reflection (ou introspection) pr�sent nativement dans d'autres langages + (Java, C#, etc...) pour utiliser toutes les fonctionnalit�s de + QxOrm.

    +
  • +
  • +

    QxModelView : + toute classe enregistr�e dans le contexte QxOrm peut �tre utilis�e par le moteur model/view de Qt (Qt widgets + et/ou vues QML). + L'interface qx::IxModel expose + automatiquement au moteur QML toutes les propri�t�s d�finies dans le contexte QxOrm. + Ce module permet ainsi de faciliter l'int�raction entre QML et les bases de donn�es.

    +
  • +
  • +

    QxService : bas� sur le + moteur QtNetwork de Qt, + ce module + permet de cr�er de mani�re simple et performante un serveur d'applications en C++ (notion de + services avec demande du client et r�ponse du serveur). QxService utilise la + serialization et l'introspection des donn�es + et fonctions pour pouvoir faire transiter sur le r�seau n'importe quelle classe ou structure. Pour plus + d'informations sur ce module, un tutoriel est disponible en cliquant + ici. +

    +
  • +
  • +

    QxCollection<Key, + Value> : + + cette collection thread-safe permet de cumuler + les avantages d'un std::vector<T> (conserve l'ordre + d'insertion + acc�s rapide par index) et d'un + std::unordered_map<Key, Value> ou encore QHash<Key, + Value> (acc�s rapide par cl� : hash-map). Ce type de collection + est particuli�rement adapt� pour contenir les �l�ments issus d'une + base de donn�es. +

    +
  • +
  • +

    QxSerialize : + + Toute classe d�finie par QxOrm + peut �tre s�rializ�e dans un flux binaire, XML et JSON. Ce module permet + �galement de cloner toutes les instances d'objet. Les principaux + objets de la biblioth�que Qt (QObject, QString, QDate, QTime, + QDateTime, QList, QHash, etc...) sont compatibles avec le module + QxSerialize. Ce module assure une compatibilit� ascendante avec + prise en compte d'un n� de version par classe. +

    +
  • +
  • +

    QxFactory : toute instance + d'objet d�finie par QxOrm + peut �tre cr��e en fonction du nom de la classe.

    +
  • +
  • +

    QxTraits : ce module + contient une liste de classes de + traits non d�finies dans la biblioth�que standard et qui sont utiles pour + l'utilisation de QxOrm. Ces classes de traits se veulent g�n�riques + et peuvent donc �tre utilis�es dans d'autres contextes que celui de + la biblioth�que QxOrm.

    +
  • +
  • +

    QxCache : le 'cache' de + QxOrm peut contenir tous types + d'objets. Il peut permettre par exemple de m�moriser des donn�es + issues d'une base de donn�es pour �viter des requ�tes trop + fr�quentes. Ce cache est g�n�rique et peut �tre utilis� dans d'autres contextes que + celui de QxOrm.

    +
  • +
  • +

    QxValidator : ce module + permet d'ajouter des contraintes + sur les propri�t�s enregistr�es dans le contexte QxOrm. Ces contraintes sont d�finies dans la m�thode de + mapping : void qx::register_class. + Si pour une instance de classe donn�e, au moins une contrainte n'est pas respect�e, alors l'instance est + consid�r�e comme invalide : + l'objet ne peut alors pas �tre sauvegard� en base de donn�es (INSERT ou UPDATE). Pour plus + d'informations sur le module QxValidator, + rendez-vous sur le manuel utilisateur de la biblioth�que QxOrm. +

    +
  • +
  • +

    QxMemLeak : permet une + d�tection rapide des fuites + m�moire en mode Debug une fois l'ex�cution du programme termin�e + (avec indication du fichier et de la ligne => style MFC de + Microsoft). Ce module a �t� d�velopp� par Wu + Yongwei et a subi + quelques modifications pour �tre int�gr� dans QxOrm. Si un autre + outil est d�j� utilis� dans vos projets (Valgrind par exemple), + cette fonctionnalit� ne doit pas �tre activ�e. + Par d�faut, le module QxMemLeak est d�sactiv�.

    +
  • +
+

+
+

Vous pouvez t�l�charger la derni�re version de QxOrm et QxEntityEditor en cliquant ici.
+ Un manuel utilisateur pour apprendre � travailler avec la biblioth�que QxOrm est disponible en cliquant ici.
+ Un exemple rapide d'utilisation de QxOrm montrant les fonctionnalit�s de base de la biblioth�que + est disponible en cliquant ici.
+ Un forum (en anglais) d�di� � QxOrm et QxEntityEditor est disponible en cliquant ici.
+ Vous pouvez �galement retrouver la communaut� fran�aise de QxOrm et QxEntityEditor sur le forum de Developpez.com.
+ Une documentation en ligne du code source de la biblioth�que QxOrm est disponible en cliquant ici.
+

+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/link.html b/doc/qxorm_fr/link.html new file mode 100644 index 0000000..149582e --- /dev/null +++ b/doc/qxorm_fr/link.html @@ -0,0 +1,265 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Forum + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
+ Si vous trouvez un bug ou si vous avez une question concernant le fonctionnement de la biblioth�que + QxOrm ou de l'application QxEntityEditor : + + + + + + + + + + +
+ + + QxOrm forum + + QxEntityEditor forum +
+
+ Pour toutes questions relatives aux librairies boost et Qt : + + + + + + + + + + +
+ + + Qt forum + + boost forum +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+
+ Voici une liste de sites fran�ais concernant tous les domaines du d�veloppement logiciel avec forums, + tutoriaux, documentations, etc... + +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/manual.html b/doc/qxorm_fr/manual.html new file mode 100644 index 0000000..377c668 --- /dev/null +++ b/doc/qxorm_fr/manual.html @@ -0,0 +1,13103 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Manuel d'utilisation de la biblioth�que QxOrm + + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + + +
+ S�lection du manuel : + + Manuel QxOrm + Manuel QxEntityEditor +
+
+
+ + + + + + + + + +
+

Manuel d'utilisation de la biblioth�que QxOrm - Table des + mati�res

+
+
    +
  1. + Introduction +
      +
    1. + Biblioth�que QxOrm +
    2. +
    3. + Aper�u rapide de l'application QxEntityEditor +
    4. +
    5. + Convention d'�criture C++ utilis�e par la biblioth�que + QxOrm +
    6. +
    +
  2. +
  3. + Installation +
      +
    1. + D�pendance � Qt +
    2. +
    3. + D�pendance � boost (optionnel) +
    4. +
    5. + Fichier de configuration QxOrm.pri (ou QxOrm.cmake) +
    6. +
    7. + Compiler la biblioth�que QxOrm (avec qmake ou CMake) +
    8. +
    9. + Pilotes SQL fournis par Qt (drivers) +
    10. +
    +
  4. +
  5. + Persistance - Object Relational Mapping (ORM) +
      +
    1. + D�finir une classe dans le contexte QxOrm (mapping) +
        +
      1. + Cl� primaire autre que le type par d�faut + "long" +
      2. +
      3. + Cl� primaire sur plusieurs colonnes (composite + key) +
      4. +
      5. + Donn�es membres public/protected/private +
      6. +
      7. + Espace de nom (namespace) +
      8. +
      9. + Types C++ support�s par QxOrm +
      10. +
      11. + D�finir une donn�e membre transient +
      12. +
      +
    2. +
    3. + Connexion � la base de donn�es +
    4. +
    5. + Sauvegarder une instance C++ en base de donn�es + (insert/update) +
    6. +
    7. + Supprimer une instance C++ de la base de donn�es + (delete) +
        +
      1. + Suppression logique (soft delete) +
      2. +
      +
    8. +
    9. + R�cup�rer une instance C++ de la base de donn�es + (fetch) +
    10. +
    11. + Requ�tes SQL +
        +
      1. + Utilisation de la classe qx::QxSqlQuery (ou son + alias qx_query) +
      2. +
      3. + Appel de proc�dure stock�e ou requ�te SQL + personnalis�e +
      4. +
      +
    12. +
    13. + Transactions (commit, rollback, session) +
    14. +
    15. + Moteur de relations +
        +
      1. + one-to-many (1-n) +
      2. +
      3. + many-to-one (n-1) +
      4. +
      5. + many-to-many (n-n) +
      6. +
      7. + one-to-one (1-1) +
      8. +
      9. + Requ�te SQL avec relations +
      10. +
      11. + S�lectionner les colonnes des relations � + r�cup�rer et d�finition des alias SQL +
      12. +
      13. + Ajout SQL dans les clauses LEFT OUTER JOIN / + INNER JOIN +
      14. +
      +
    16. +
    17. + Collections support�es par QxOrm +
        +
      1. + Collections de Qt +
      2. +
      3. + Collections de boost +
      4. +
      5. + Collections fournies par l'espace de nom standard + std +
      6. +
      7. + qx::QxCollection +
      8. +
      +
    18. +
    19. + Pointeurs intelligents support�s par QxOrm + (smart-pointers) +
        +
      1. + Pointeurs intelligents de Qt +
      2. +
      3. + Pointeurs intelligents de boost +
      4. +
      5. + Pointeurs intelligents fournis par l'espace de + nom standard std +
      6. +
      7. + qx::dao::ptr +
      8. +
      +
    20. +
    21. + D�clencheurs (triggers) +
    22. +
    23. + Validation d'une instance C++ (validators) +
    24. +
    25. + G�rer la valeur NULL de la base de donn�es +
        +
      1. + boost::optional +
      2. +
      3. + QVariant +
      4. +
      +
    26. +
    27. + H�ritage et polymorphisme +
    28. +
    29. + Interface qx::IxPersistable (classe abstraite) +
    30. +
    31. + Utiliser le pattern C++ PIMPL (Private Implementation + idiom ou d-pointer) +
    32. +
    33. + Persister des types personnalis�s +
    34. +
    35. + G�n�rer le sch�ma DDL SQL de la base de donn�es +
    36. +
    37. + Associer un type SQL � une classe C++ +
    38. +
    39. + Effectuer des requ�tes asynchrones � la base de + donn�es +
    40. +
    41. + Gestion du cache pour sauvegarder des instances C++ + (module QxCache) +
    42. +
    43. + Travailler avec plusieurs bases de donn�es +
    44. +
    45. + D�clarer une classe abstraite dans le contexte QxOrm +
    46. +
    47. + D�clarer automatiquement les m�ta-propri�t�s de Qt + (macro Q_PROPERTY) +
    48. +
    +
  6. +
  7. + S�rialisation +
      +
    1. + N� version pour assurer une compatibilit� ascendante +
    2. +
    3. + Moteur QDataStream de Qt +
    4. +
    5. + Moteur JSON de Qt +
    6. +
    7. + Moteur XML de boost::serialization +
    8. +
    9. + Moteur binaire de boost::serialization +
    10. +
    11. + Autres types de s�rialisation propos�s par boost +
    12. +
    13. + Cloner une instance C++ +
    14. +
    15. + Afficher le d�tail d'une instance C++ (dump au format + XML ou JSON) +
    16. +
    +
  8. +
  9. + Introspection - R�flexion +
      +
    1. + Obtenir dynamiquement la valeur d'une donn�e membre +
    2. +
    3. + Valoriser dynamiquement une donn�e membre +
    4. +
    5. + Appeler dynamiquement une fonction +
    6. +
    7. + Cr�er une instance C++ dynamiquement +
    8. +
    9. + Parcourir la liste des classes/propri�t�s enregistr�es + dans le contexte QxOrm +
    10. +
    +
  10. +
  11. + Services : transf�rer la couche de donn�es persistante sur le + r�seau (module QxService) +
      +
    1. + Param�tres d'entr�e/sortie d'un service + (requ�te/r�ponse) +
    2. +
    3. + D�finir les fonctions publi�es par un service +
    4. +
    5. + Liste des options disponibles c�t� serveur +
    6. +
    7. + Param�trage de la connexion c�t� client +
    8. +
    9. + Gestion de l'authentification dans un service +
    10. +
    11. + Requ�tes client/serveur asynchrones +
    12. +
    +
  12. +
  13. + Moteur mod�le/vue (module QxModelView) +
      +
    1. + D�finir un mod�le "simple" (sans relation) +
    2. +
    3. + Mod�les avec relations (notion de mod�les imbriqu�s) +
    4. +
    5. + Int�raction avec les vues QML +
    6. +
    7. + Int�raction avec les vues QtWidget +
    8. +
    9. + Connexion d'un mod�le au module QxService +
    10. +
    +
  14. +
  15. + QxOrm et MongoDB (C++ ODM Object Document Mapper) +
      +
    1. + Pr�-requis : driver libmongoc et + libbson +
    2. +
    3. + Param�trage du fichier QxOrm.pri (ou + QxOrm.cmake) +
    4. +
    5. + Connexion � la base de donn�es MongoDB +
    6. +
    7. + D�finition d'une classe persistante MongoDB (Collection) + dans le contexte QxOrm (mapping) +
        +
      1. + Gestion des cl�s primaires ObjectId +
      2. +
      +
    8. +
    9. + Ins�rer une instance C++ (Document) dans la base de + donn�es MongoDB (INSERT) +
        +
      1. + Ins�rer une liste d'instances C++ (plusieurs + Documents) dans la base de donn�es MongoDB (INSERT) +
      2. +
      +
    10. +
    11. + Mettre � jour une instance C++ (Document) dans la base + de donn�es MongoDB (UPDATE) +
        +
      1. + Mettre � jour une liste d'instances C++ + (plusieurs Documents) dans la base de donn�es MongoDB (UPDATE) +
      2. +
      +
    12. +
    13. + Supprimer une instance C++ (Document) de la base de + donn�es MongoDB (DELETE) +
        +
      1. + Supprimer une liste d'instances C++ (plusieurs + Documents) de la base de donn�es MongoDB (DELETE) +
      2. +
      +
    14. +
    15. + R�cup�rer une instance C++ (Document) de la base de + donn�es MongoDB (FETCH) +
        +
      1. + R�cup�rer une liste d'instances C++ (plusieurs + Documents) de la base de donn�es MongoDB (FETCH) +
      2. +
      +
    16. +
    17. + Requ�tes JSON +
        +
      1. + Utilisation de la classe qx::QxSqlQuery (ou son + alias qx_query) +
      2. +
      3. + Utiliser le moteur d'aggregation MongoDB +
      4. +
      5. + Ajouter des propri�t�s � la requ�te de type : + 'sort', 'limit', 'skip', etc... +
      6. +
      7. + Ex�cuter une requ�te personnalis�e +
      8. +
      +
    18. +
    19. + Moteur de relations (n�cessite une version MongoDB 3.6 + ou +) +
        +
      1. + Relations : Embedded vs Referenced +
      2. +
      +
    20. +
    21. + Cr�ation automatique des index +
    22. +
    +
  16. +
  17. + Serveur web HTTP/HTTPS (module QxHttpServer) +
      +
    1. + Hello World ! +
    2. +
    3. + Param�trage du serveur web HTTP +
        +
      1. + Connexions s�curis�es SSL/TLS +
      2. +
      +
    4. +
    5. + Routage des URL (d�finir les endpoints / dispatcher) +
        +
      1. + Routage dynamique des URL +
      2. +
      +
    6. +
    7. + R�cup�rer les param�tres de la requ�te HTTP +
    8. +
    9. + G�n�rer la r�ponse HTTP +
    10. +
    11. + Sessions (stockage par client c�t� serveur) +
    12. +
    13. + Cookies +
    14. +
    15. + Gestion des fichiers statiques +
    16. +
    17. + Encodage de transfert en bloc (chunked responses) +
    18. +
    19. + Requ�tes par les API JSON (module QxRestApi) +
    20. +
    21. + WebSocket +
    22. +
    23. + Performance (test� avec Apache Benchmark) +
        +
      1. + Am�liorer les performances avec epoll dispatcher + sous Linux +
      2. +
      +
    24. +
    +
  18. +
  19. + API REST JSON (module QxRestApi) +
      +
    1. + Principe de fonctionnement +
        +
      1. + Cas d'utilisation +
      2. +
      +
    2. +
    3. + Projet de test qxBlogRestApi (QML et serveur web + HTTP) +
    4. +
    5. + R�cup�ration de donn�es (fetch/count/exist) +
        +
      1. + fetch_all +
      2. +
      3. + fetch_by_id +
      4. +
      5. + fetch_by_query +
      6. +
      7. + count +
      8. +
      9. + exist +
      10. +
      +
    6. +
    7. + Ajout de donn�es (insert) +
    8. +
    9. + Mise � jour de donn�es (update) +
    10. +
    11. + Sauvegarde de donn�es (save) +
    12. +
    13. + Suppression de donn�es (delete) +
        +
      1. + delete_all / destroy_all +
      2. +
      3. + delete_by_query / destroy_by_query +
      4. +
      5. + delete_by_id / destroy_by_id +
      6. +
      +
    14. +
    15. + Validation de donn�es (validate) +
    16. +
    17. + Appel RAW SQL ou proc�dure stock�e +
    18. +
    19. + Appel fonctions natives C++ +
    20. +
    21. + Meta-data (structure des classes C++ enregistr�es dans + le contexte QxOrm) +
    22. +
    23. + Envoyer une liste de requ�tes JSON +
    24. +
    +
  20. +
+
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt + Ambassador Program + +
+
+
+
+ +

Introduction

+
+ L'objectif de ce manuel utilisateur est de pr�senter de mani�re structur�e l'ensemble des + fonctionnalit�s propos�es par la biblioth�que QxOrm. + Ce manuel est destin� aux d�veloppeurs et architectes logiciel qui souhaitent g�rer une couche de + donn�es persistante en C++/Qt. + Des comp�tences techniques en C++ et base de donn�es sont requises pour la bonne compr�hension de + ce document. +

+ Remarque : la plupart des fonctionnalit�s pr�sent�es dans ce manuel peuvent �tre d�finies + rapidement et facilement avec l'application QxEntityEditor (l'�diteur graphique de la + biblioth�que QxOrm). + Une documentation d�di�e � l'application QxEntityEditor est + �galement disponible. +

+ Autre remarque : ce manuel est bas� en grande partie sur l'ancienne FAQ + du site QxOrm, toujours accessible en cliquant ici. +

+

Biblioth�que QxOrm +

+
+ QxOrm est une biblioth�que C++ open source de gestion de donn�es (Object Relational Mapping, + ORM).
+ QxOrm est d�velopp� XDL Teamarty, Ing�nieur en d�veloppement logiciel depuis 2003.
+
+ � partir d'une simple fonction de param�trage (que l'on peut comparer avec un fichier de + mapping XML Hibernate), vous aurez + acc�s aux fonctionnalit�s suivantes : +
    +
  • + Persistance + + : support des bases de donn�es SQLite, MySQL, PostgreSQL, Oracle, MS SQL Server, MongoDB (gestion des relations 1-1, + 1-n, n-1 et n-n) ; +
  • +
  • + S�rialisation + des donn�es (flux JSON, binaire et XML) ;
  • +
  • + R�flexion + + (ou + introspection + ) pour acc�der dynamiquement aux classes, attributs et invoquer des m�thodes ;
  • +
  • + Serveur web + HTTP + : serveur web compatible HTTP 1.1 autonome, performant, multi-plateforme et simple + d'utilisation ;
  • +
  • + API JSON + + : interop�rabilit� avec d'autres technologies que C++/Qt (web services REST, + applications QML, langages de script).
  • +
+ QxOrm est d�pendant des excellentes biblioth�ques Qt (compatible � partir de la version 4.5.0) et boost (compatible � partir de la + version 1.38, par d�faut seuls les fichiers d'en-t�te *.hpp sont n�cessaires).
+ La biblioth�que QxOrm a �t� retenue pour faire partie du programme Qt + Ambassador. +

+ Si vous trouvez un bug ou si vous avez une question concernant le fonctionnement de la + biblioth�que QxOrm, + vous pouvez envoyer un mail � : support@qxorm.com.
+ Un forum (en anglais) d�di� � QxOrm est disponible en cliquant ici.
+ Vous pouvez �galement retrouver la communaut� fran�aise de QxOrm sur le forum de Developpez.com. +

+
+

Aper�u rapide de + l'application QxEntityEditor

+
+ QxEntityEditor est un �diteur graphique pour la biblioth�que QxOrm : + QxEntityEditor permet de g�rer graphiquement le mod�le d'entit�s.
+ QxEntityEditor est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et + g�n�re du code natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu� + et mobile (Android, iOS, Windows Phone, Raspberry Pi, etc.).
+ Une vid�o de pr�sentation de l'application QxEntityEditor est + disponible.
+
+ QxEntityEditor est bas� sur un syst�me de plugins et propose diverses fonctionnalit�s + pour importer/exporter le mod�le de donn�es : +
    +
  • g�n�ration automatique du code C++ (classes persistantes enregistr�es dans le contexte + QxOrm) ;
  • +
  • g�n�ration automatique des scripts SQL DDL (sch�ma de base de donn�es) pour les bases + SQLite, MySQL, PostgreSQL, Oracle et MS SQL Server ;
  • +
  • supporte l'�volution du sch�ma de base de donn�es pour chaque version d'un projet + (ALTER TABLE, ADD COLUMN, DROP INDEX, etc.) ;
  • +
  • g�n�ration automatique des classes C++ de services pour transf�rer le mod�le de donn�es + sur le r�seau, en utilisant le module QxService, pour cr�er rapidement des applications client/serveur ; +
  • +
  • importation automatique des structures de bases de donn�es existantes (par connexion + ODBC) pour les bases SQLite, MySQL, PostgreSQL, Oracle et MS SQL Server ;
  • +
  • parce que chaque projet est diff�rent, QxEntityEditor propose plusieurs outils pour + personnaliser les fichiers g�n�r�s (notamment un moteur javascript et un d�bogueur + int�gr�).
  • +
+ QxEntityEditor +

+ QxEntityEditor est d�velopp� XDL Teamarty, Ing�nieur en d�veloppement logiciel depuis + 2003.
+ Un manuel utilisateur d�di� � l'application QxEntityEditor + est disponible.
+

+
+

Convention d'�criture C++ + utilis�e par la biblioth�que QxOrm

+
+ La biblioth�que QxOrm utilise les conventions d'�criture de code C++ suivantes : +
    +
  • toutes les classes, fonctions, variables, etc... sont d�finies dans l'espace de nom (namespace) qx ; +
  • +
  • les macro de QxOrm sont �crites sous la forme QX_... ; +
  • +
  • les classes abstraites (ou interfaces) ont le pr�fixe Ix (par exemple : + IxFactory est une interface pour la cr�ation d'instances) ; +
  • +
  • les autres classes ont le pr�fixe Qx (par exemple : QxDataMember) ; +
  • +
  • les collections d'objets ont pour suffixe X (par exemple : QxDataMemberX + est une collection de QxDataMember) ; +
  • +
  • les fonctions pour communiquer avec les bases de donn�es se trouvent sous le namespace qx::dao (par exemple + : qx::dao::fetch_by_id()) ; +
  • +
  • les fonctions pour la serialization des donn�es se trouvent sous le namespace + qx::serialization (par exemple : qx::serialization::xml::to_file()) ; +
  • +
  • le moteur de reflection (ou introspection) est accessible depuis la classe + qx::QxClassX (par exemple qx::QxClassX::invoke() pour invoquer une + m�thode de classe) ; +
  • +
  • les classes de traits se trouvent sous le namespace qx::trait (par + exemple : qx::trait::is_smart_ptr<T>). +
  • +
+
+
+ +

Installation

+
+ La biblioth�que QxOrm est multi-plateforme et peut �tre install�e sur tous types d'environnement : + Windows, Linux (Unix), Mac OS X, Android, iOS, Windows Phone, etc...
+ Un tutoriel complet (avec captures d'�cran) pour installer un + environnement de d�veloppement avec QxOrm sous Windows est disponible en cliquant ici. +

+ L'objectif de ce chapitre est de pr�senter rapidement les diff�rentes �tapes � suivre pour + installer QxOrm sur tous types d'environnement : + +
+

D�pendance � Qt

+
+ + + + + + + + + +
QtQt : biblioth�que compl�te : IHM + (QtGui), r�seau (QtNetwork), XML (QtXml), base de donn�es + (QtSql), etc.
+ La documentation est excellente et le code C++ �crit � partir + de cette biblioth�que est � la fois performant et simple de + compr�hension.
+ Depuis le rachat par Nokia puis Digia et sa nouvelle licence LGPL, Qt est + sans contexte la biblioth�que phare du moment.
+ QxOrm est compatible avec les principaux objets d�finis par Qt + : QObject, QString, QDate, QTime, QDateTime, QList, QHash, + QSharedPointer, QScopedPointer, etc.
+ Il est conseill� d'installer et d'utiliser la derni�re version + de Qt disponible � l'adresse suivante : http://www.qt.io/
+
+ Remarque : par d�faut, la biblioth�que QxOrm d�pend uniquement des modules QtCore et QtSql. + Il est possible d'activer des fonctionnalit�s suppl�mentaires gr�ce au fichier de configuration QxOrm.pri (ou QxOrm.cmake) : + ces nouvelles fonctionnalit�s peuvent alors ajouter des d�pendances � QxOrm. +

+
+

D�pendance � boost + (optionnel)

+
+ Par d�faut, la biblioth�que QxOrm d�pend uniquement de Qt (QtCore et QtSql). + L'installation de boost est optionnelle et non requise avec la configuration par d�faut. +
+ Remarque : QxOrm propose 2 niveaux de d�pendance � boost en option : +
    +
  • une d�pendance uniquement aux fichiers d'en-t�tes de boost (*.hpp) : option de + compilation _QX_ENABLE_BOOST ;
  • +
  • une d�pendance au module boost serialization : option de compilation + _QX_ENABLE_BOOST_SERIALIZATION. +
  • +
+
+ + + + + + + + + +
boostboost : de nombreux modules de la + biblioth�que boost font partie de la nouvelle norme C++.
+ C'est une biblioth�que reconnue pour sa qualit�, son code 'C++ + moderne', sa documentation, sa portabilit�, etc...
+ QxOrm utilise les fonctionnalit�s suivantes de boost : + smart_pointer, type_traits, + multi_index_container, unordered_container, any, tuple, + foreach, function. Toutes ces fonctionnalit�s sont header only, la + d�pendance au module serialization est optionnelle.
+ Il est conseill� d'installer et d'utiliser la derni�re version + de boost disponible � l'adresse suivante : http://www.boost.org/ +
+
+ Remarque importante : avec l'option de compilation _QX_ENABLE_BOOST, la + biblioth�que QxOrm d�pend uniquement des fichiers d'en-t�te *.hpp de boost (utilisation + des biblioth�ques header only uniquement). + L'installation de boost est donc tr�s simple puisqu'il suffit de d�zipper le package boost (pour + disposer des fichiers d'en-t�te *.hpp). +

+
+

Fichier de configuration + QxOrm.pri (ou QxOrm.cmake)

+
+ Le fichier de configuration QxOrm.pri (ou QxOrm.cmake) est divis� en plusieurs + sections (chacune �tant comment�e) et regroupe les diff�rents param�trages et options de + compilation disponibles. + Il est fortement recommand� de lire attentivement le fichier de configuration QxOrm.pri + avant de compiler la biblioth�que QxOrm. + Il est possible de conserver le param�trage par d�faut, seule la variable + QX_BOOST_INCLUDE_PATH est n�cessaire si votre projet utilise le framework boost : cette + variable indique o� trouver les fichiers d'en-t�te *.hpp de la biblioth�que boost :
+
+ + + + + + + +
+
   isEmpty(QX_BOOST_INCLUDE_PATH) { QX_BOOST_INCLUDE_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_57/include) }   
+
+
+ Si vous ne souhaitez pas modifier le fichier de configuration QxOrm.pri, il est possible + de d�finir une variable d'environnement nomm�e BOOST_INCLUDE : cette variable + d'environnement sera alors utilis�e automatiquement pour valoriser QX_BOOST_INCLUDE_PATH + (lire le fichier QxOrm.pri pour plus d'informations). +

+ Voici une liste non exhaustive des diff�rentes options de compilation disponibles (lire le + fichier de configuration QxOrm.pri pour plus de d�tails), aucune n'�tant activ�e par + d�faut : +
    +
  • _QX_ENABLE_BOOST : ajoute une d�pendance aux fichiers d'en-t�tes de boost + (*.hpp), support des classes boost::shared_ptr, boost::optional, + boost::container, etc... ; +
  • +
  • _QX_ENABLE_BOOST_SERIALIZATION : active les fonctionnalit�s + de s�rialisation avec le module boost::serialization. Cette option n�cessite la + compilation du binaire boost::serialization et ajoute donc une d�pendance � QxOrm ;
  • +
    +
  • _QX_ENABLE_QT_GUI : support de la s�rialisation des types du module QtGui : QBrush, + QColor, QFont, QImage, QMatrix, QPicture, QPixmap, QRegion. Cette option ajoute une + d�pendance � QxOrm (QtGui) ;
  • +
  • _QX_ENABLE_QT_NETWORK : active le module QxService pour + transf�rer la couche de donn�es persistante sur le r�seau (application client/serveur). + Cette option ajoute une d�pendance � QxOrm (QtNetwork) ;
  • +
  • _QX_NO_PRECOMPILED_HEADER : d�sactive l'utilisation d'un en-t�te pr�compil� + (permet de r�duire les temps de compilation d'un projet) : cette option est n�cessaire + pour contourner un bug des versions r�centes de MinGW, pour tous les + autres compilateurs il est recommand� de travailler avec un precompiled header ; +
  • +
  • _QX_NO_RTTI : permet de compiler QxOrm et les projets d�pendants sans les + informations de type C++ RTTI ;
  • +
  • _QX_STATIC_BUILD : permet de compiler la biblioth�que QxOrm en mode statique ; +
  • +
  • _QX_UNITY_BUILD : r�duit les temps de compilation de la biblioth�que QxOrm en + utilisant le concept unity build : un seul fichier source all.cpp � + compiler. Il est recommand� d'activer cette option avec CMake (car ne supporte pas nativement les en-t�tes pr�compil�s) ; +
  • +
  • _QX_ENABLE_MONGODB : support de la base de donn�es + MongoDB, la biblioth�que QxOrm devient ainsi un ODM (Object Document Mapper).
  • +
+
+ Remarque : le fichier de configuration QxOrm.pri (ou QxOrm.cmake) devra + �tre inclus dans tous les projets d�pendants de la biblioth�que QxOrm en ajoutant la ligne + suivante dans le fichier *.pro du projet :
+
+ + + + + + + +
+
   include(my_path_to_QxOrm_library/QxOrm.pri)   
+
+
+ Autre remarque : � la place de qmake, il est possible d'utiliser l'outil de compilation CMake pour configurer et + construire la biblioth�que QxOrm. + CMake propose un outil graphique afin de visualiser et param�trer les diff�rentes options + disponibles : +

+ QxOrm and CMake +

+
+

Compiler la biblioth�que + QxOrm (avec qmake ou CMake)

+
+ QxOrm utilise le processus qmake de la biblioth�que Qt pour g�n�rer les + makefile et compiler le projet (il est �galement possible d'utiliser l'outil de compilation CMake, un fichier + CMakeLists.txt �tant fourni avec la biblioth�que QxOrm).
+ qmake est multi-plateforme et fonctionne parfaitement sous Windows, Linux (Unix) et Mac + OS X.
+ Pour compiler QxOrm, il suffit d'ex�cuter les commandes suivantes :
+
+ + + + + + + +
+
   qmake
+   make debug
+   make release   
+
+
+ Sous Windows, des fichiers *.vcproj et *.sln sont disponibles pour les + �diteurs Microsoft Visual C++.
+ Les fichiers *.pro sont lisibles par l'�diteur Qt Creator, et des plugins existent + permettant de s'interfacer avec de nombreux �diteurs C++.
+ Les fichiers mingw_build_all_debug.bat et mingw_build_all_release.bat pr�sents + dans le dossier ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests + avec le compilateur MinGW sous Windows.
+ Les fichiers gcc_build_all_debug.sh et gcc_build_all_release.sh pr�sents dans le + dossier ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests avec + GCC sous Linux.
+ Enfin, les fichiers osx_build_all_debug.sh et osx_build_all_release.sh pr�sents + dans le dossier ./tools/ permettent de compiler rapidement QxOrm ainsi que tous les tests + sous Mac OS X (merci � Dominique Billet pour l'�criture des scripts).
+
+
+

Pilotes SQL fournis par + Qt (drivers)

+
+ QxOrm utilise le moteur QtSql de Qt bas� sur un syst�me de plugin.
+ Une liste d�taill�e des bases de + donn�es support�es est disponible sur le site de Qt.
+ Le plugin ODBC (QODBC) assure une compatibilit� avec de nombreuses bases de + donn�es.
+ Pour des performances optimales, il est conseill� d'utiliser un plugin sp�cifique � une base de + donn�es : +
    +
  • QMYSQL : MySQL ;
  • +
  • QPSQL : PostgreSQL (versions 7.3 and above) ;
  • +
  • QOCI : Oracle Call Interface Driver ;
  • +
  • QSQLITE : SQLite version 3 ;
  • +
  • QDB2 : IBM DB2 (version 7.1 and above) ;
  • +
  • QIBASE : Borland InterBase ;
  • +
  • QTDS : Sybase Adaptive Server.
  • +
+ Remarque : pour se connecter � une base de donn�es Microsoft SQL Server, il est + n�cessaire d'utiliser le pilote ODBC (plugin QODBC). +

+ Autre remarque : la biblioth�que QxOrm supporte �galement la base de + donn�es MongoDB (C++ ODM Object Document Mapper). +

+
+
+ +

Persistance - Object + Relational Mapping (ORM)

+
+ La biblioth�que QxOrm fournit un moteur de persistance des donn�es bas� sur le module QtSql de Qt. + Ce moteur de persistance utilise la technique de programmation : Object Relational Mapping + (ORM). +

+ D�finition du + site Wikipedia : un mapping objet-relationnel (en anglais object-relational mapping + ou ORM) est une technique de programmation informatique qui cr�e l'illusion d'une base de + donn�es orient�e objet � partir d'une base de donn�es relationnelle en d�finissant des + correspondances entre cette base de donn�es et les objets du langage utilis�. On pourrait le + d�signer par � correspondance entre monde objet et monde relationnel �. + Le mapping objet-relationnel consiste � associer une ou plusieurs classes avec une table, et chaque + attribut de la classe avec un champ de la table. + Les frameworks de mapping objet-relationnel permettent d'�liminer la duplication de code dans les + op�rations CRUD. +

+ Pour effectuer cette correspondance entre le monde objet et le monde relationnel, ainsi pour que + proposer l'ensemble de ses fonctionnalit�s, la biblioth�que QxOrm impose l'enregistrement de + classes C++ dans le contexte QxOrm. + Nous allons donc d�buter ce chapitre de la fa�on suivante : comment enregistrer une classe C++ + dans le contexte QxOrm ? +

+ Remarque : la biblioth�que QxOrm supporte �galement la base de donn�es + MongoDB (C++ ODM Object Document Mapper). +

+

D�finir une classe dans + le contexte QxOrm (mapping)

+
+ Toutes les classes C++ peuvent �tre enregistr�es dans le contexte QxOrm : il n'y a pas besoin de + d�river d'un super objet, et vous pouvez �crire vos m�thodes de classes et accesseurs sans + aucune contrainte. + Enregistrer une classe C++ dans le contexte QxOrm signifie : +
    +
  • dans le fichier en-t�te *.h contenant la d�finition de la classe : utilisation de + la macro QX_REGISTER_HPP(class_name, base_class, class_version) ;
  • +
  • dans le fichier source *.cpp contenant l'impl�mentation de la classe : utilisation + de la macro QX_REGISTER_CPP(class_name) ;
  • +
  • dans le fichier source *.cpp contenant l'impl�mentation de la classe : + sp�cialisation de la fonction template : void + qx::register_class<T>(qx::QxClass<T> & t).
  • +
+ Par exemple, voici comment d�clarer une classe person avec 4 propri�t�s enregistr�es dans + le contexte QxOrm : id, firstName, lastName, birthDate :
+
+ * Fichier person.h :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+/* This macro is necessary to register 'person' class in QxOrm context */
+/* param 1 : the current class to register => 'person' */
+/* param 2 : the base class, if no base class, use the qx trait => 'qx::trait::no_base_class_defined' */
+/* param 3 : the class version used by serialization engine to provide 'ascendant compatibility' */
+
+#endif // _PERSON_H_
+
+
+ * Fichier person.cpp :
+ + + + + + + +
+
#include "precompiled.h"   // Precompiled-header with '#include <QxOrm.h>' and '#include "export.h"'
+#include "person.h"          // Class definition 'person'
+#include <QxOrm_Impl.h>     // Automatic memory leak detection and boost serialization export macro
+
+QX_REGISTER_CPP_MY_TEST_EXE(person)   // This macro is necessary to register 'person' class in QxOrm context
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.setName("t_person");               // 'person' C++ class is mapped to 't_person' database table
+
+  t.id(& person::id, "id");               // Register 'person::id' <=> primary key in your database
+  t.data(& person::firstName, "first_name");      // Register 'person::firstName' property mapped to 'first_name' database column name
+  t.data(& person::lastName, "last_name");  // Register 'person::lastName' property mapped to 'last_name' database column name
+  t.data(& person::birthDate, "birth_date");  // Register 'person::birthDate' property mapped to 'birth_date' database column name
+}}
+
+

+ Remarque : les m�thodes qx::QxClass<T>::id() et qx::QxClass<T>::data() retournent une instance de type : qx::IxDataMember + (classe de base pour l'enregistrement des donn�es membre). + Gr�ce � cette instance, il est possible de personnaliser le comportement par d�faut propos� par + la classe qx::IxDataMember, comme par exemple dans le chapitre : D�finir une donn�e membre transient. +

+ Autre remarque : il est �galement possible d'enregistrer des m�thodes de classe dans le + contexte QxOrm (gestion des m�thodes static et non static) avec les m�thodes qx::QxClass<T>::fct_0(), qx::QxClass<T>::fct_1(), etc... + Cette fonctionnalit� fait partie du moteur d'introspection de la + biblioth�que QxOrm, plus de d�tails dans le chapitre : Appeler + dynamiquement une fonction. +

+

Cl� primaire autre + que le type par d�faut "long"

+
+ Par d�faut, lorsqu'un mapping d'une classe C++ est �crit avec la m�thode void + qx::register_class<T>, l'identifiant associ� � la classe est de type long + (cl� primaire avec auto-incr�mentation dans la base de donn�es).
+
+ Il est possible de d�finir un identifiant d'un autre type en utilisant la macro + QX_REGISTER_PRIMARY_KEY.
+ Cette macro sp�cialise le template qx::trait::get_primary_key<T> pour associer + un type d'identifiant � une classe C++.
+
+ Par exemple, pour d�finir un identifiant unique de type QString pour la classe C++ + myClass (mapp�e vers une table de la BDD avec une colonne de type VARCHAR pour + cl� primaire), il suffit d'�crire : + QX_REGISTER_PRIMARY_KEY(myClass, QString)
+
+ Voici un exemple d'utilisation de la macro QX_REGISTER_PRIMARY_KEY avec une classe + author poss�dant un identifiant de type QString :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+ 
+class author
+{
+public:
+// -- propri�t�s
+   QString  m_id;
+   QString  m_name;
+// -- constructeur, destructeur virtuel
+   author() { ; }
+   virtual ~author() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+

+
+

Cl� primaire sur + plusieurs colonnes (composite key)

+
+ QxOrm supporte la notion de 'multi-columns primary key'.
+ L'identifiant de la classe doit �tre du type suivant : +
    +
  • QPair ou std::pair pour d�finir deux colonnes ; +
  • +
  • boost::tuple (ou std::tuple) pour d�finir de deux � neuf colonnes. +
  • +
+ Il est n�cessaire d'utiliser la macro QX_REGISTER_PRIMARY_KEY() pour + sp�cialiser le template et ainsi d�finir le type d'identifiant sur plusieurs colonnes.
+ La liste des noms des colonnes doit �tre de la forme suivante : + 'column1|column2|column3|etc.'.
+
+ Exemple d'utilisation avec la classe 'author' du projet + 'qxBlogCompositeKey', cette classe poss�de un identifiant sur trois colonnes :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+
+   QX_REGISTER_FRIEND_CLASS(author)
+
+public:
+
+// -- cl� compos�e (cl� primaire d�finie sur plusieurs colonnes dans la base de donn�es)
+   typedef boost::tuple<QString, long, QString> type_composite_key;
+   static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; }
+
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+
+// -- enum
+   enum enum_sex { male, female, unknown };
+
+// -- propri�t�s
+   type_composite_key   m_id;
+   QString              m_name;
+   QDate                m_birthdate;
+   enum_sex             m_sex;
+   list_blog            m_blogX;
+
+// -- constructeur, destructeur virtuel
+   author() : m_id("", 0, ""), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+
+// -- m�thodes
+   int age() const;
+
+// -- m�thodes d'acc�s � la cl� compos�e
+   type_composite_key getId() const    { return m_id; }
+   QString getId_0() const             { return boost::tuples::get<0>(m_id); }
+   long getId_1() const                { return boost::tuples::get<1>(m_id); }
+   QString getId_2() const             { return boost::tuples::get<2>(m_id); }
+
+// -- m�thodes de modification de la cl� compos�e
+   void setId_0(const QString & s)     { boost::tuples::get<0>(m_id) = s; }
+   void setId_1(long l)                { boost::tuples::get<1>(m_id) = l; }
+   void setId_2(const QString & s)     { boost::tuples::get<2>(m_id) = s; }
+
+};
+
+QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<author::type_composite_key, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/author.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, author::str_composite_key());
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key());
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+

+
+

Donn�es membres + public/protected/private

+
+ Pour enregistrer des membres private ou protected dans le contexte QxOrm + (fonction qx::register_class<T>), il faut d�clarer les friend class + n�cessaires.
+ Pour simplifier l'�criture avec les template C++, la biblioth�que QxOrm fournit la + macro suivante : QX_REGISTER_FRIEND_CLASS(myClass).
+ Un exemple d'utilisation se trouve dans le dossier ./test/qxDllSample/dll1/ du package + QxOrm avec la classe CPerson :
+
+ + + + + + + +
+
namespace qx {
+namespace test {
+
+class QX_DLL1_EXPORT CPerson : public QObject
+{
+
+   Q_OBJECT
+   QX_REGISTER_FRIEND_CLASS(qx::test::CPerson)
+
+   // etc...
+
+};
+
+} // namespace test
+} // namespace qx
+
+

+
+

Espace de nom + (namespace)

+
+ Si une classe est d�finie dans un espace de nom (namespace), alors une erreur de + compilation se produit avec l'utilisation des macros : QX_REGISTER_HPP et + QX_REGISTER_CPP. + Pour �viter ces erreurs de compilation, il est n�cessaire d'utiliser les macros suivantes : + QX_REGISTER_COMPLEX_CLASS_NAME_HPP et QX_REGISTER_COMPLEX_CLASS_NAME_CPP.
+
+ Vous trouverez un exemple d'utilisation dans le dossier ./test/qxDllSample/dll1/ de la + distribution de QxOrm avec la classe CPerson d�finie dans l'espace de nom + qx::test :
+
+ + + + + + + +
+
   QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0, qx_test_CPerson)   
+
+
+ Les macros QX_REGISTER_COMPLEX_CLASS_NAME... n�cessitent un param�tre suppl�mentaire + (dans l'exemple ci-dessus il s'agit du param�tre qx_test_CPerson) afin de cr�er une + variable globale.
+ Celle-ci est appel�e d�s le lancement de l'application.
+ La construction de cette instance globale d�clare la classe dans le + module QxFactory (mod�le de conception fabrique ou design pattern factory).
+ Un objet C++ ne pouvant pas se nommer avec des caract�res "::", le param�tre + suppl�mentaire de la macro permet de remplacer tous les "::" par des "_". +

+
+

Types C++ support�s + par QxOrm

+
+ La biblioth�que QxOrm supporte la plupart des types primitifs du standard C++ et du framework + Qt (num�riques, bool�ens, chaines de caract�res, date/heure, collections, pointeurs et + pointeurs intelligents, etc...). + Voici un exemple pr�sentant une liste (non exhaustive) de types C++ support�s ainsi que + l'association par d�faut du type de base de donn�es (format SQLite) : +

+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ Remarque : il est �galement possible de persister un type non g�r� par d�faut par la + biblioth�que QxOrm. Rendez-vous au chapitre Persister des types + personnalis�s pour plus de d�tails sur cette fonctionnalit�. +

+ Autre remarque : concernant l'association d'un type C++ avec le type de base de + donn�es associ�, rendez-vous au chapitre Associer un type SQL � + une classe C++ pour plus de d�tails. +

+
+

D�finir une donn�e + membre transient

+
+ Une donn�e membre transient n'est pas associ�e � une colonne d'une table de la base de + donn�es. + Le module QxDao ignore donc + cette propri�t� pour toutes les requ�tes � la base de donn�es. +

+ A quoi sert l'enregistrement d'une donn�e membre transient dans le contexte QxOrm + ?
+ Enregistrer une donn�e membre transient dans le contexte QxOrm permet de disposer des + autres fonctionnalit�s de la biblioth�que QxOrm sur cette propri�t�, comme par exemple : s�rialisation, introspection, etc... +

+ La m�thode qx::QxClass<T>::data() dispose d'un param�tre optionnel nomm� : + bool bDao (par d�faut, valeur � true). + Par exemple, ajoutons une propri�t� transient nomm�e age � la classe + person (cette propri�t� n'a pas besoin d'�tre stock�e en base de donn�es puisque nous + disposons d�j� de la propri�t� birthDate) : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name";);
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+  t.data(& person::age, "age", 0, true, false);
+}}
+
+
+ Voici une autre fa�on de d�finir une propri�t� transient en r�cup�rant l'instance de + type qx::IxDataMember : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name";);
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+
+  IxDataMember * pDataMember = t.data(& person::age, "age");
+  pDataMember->setDao(false);
+}}
+
+

+
+
+

Connexion � la base de + donn�es

+
+ La connexion � la base de donn�es peut �tre param�tr�e avec la classe singleton : qx::QxSqlDatabase.
+ Voici un exemple de param�trage � une base de donn�es SQLite nomm�e test_qxorm.db : +

+ + + + + + + +
+
   // Init parameters to connect to database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+
+
+ Une fois les param�tres de connexion renseign�s dans la classe singleton qx::QxSqlDatabase, toutes les op�rations avec la base de donn�es + effectu�es par la biblioth�que QxOrm utiliserons ces param�tres. + Pour plus d'informations sur les param�tres de connexion � renseigner, il est recommand� de lire + la documentation de la classe + QSqlDatabase du framework Qt. +

+ Remarque : la classe qx::QxSqlDatabase g�re automatiquement les appels � la base de + donn�es dans diff�rents threads (multi-threading). +

+ Autre remarque : il est possible de g�rer son propre pool de connexions � la base de + donn�es, et de travailler �galement avec plusieurs bases de donn�es distinctes : rendez-vous + dans le chapitre Travailler avec plusieurs bases de + donn�es pour plus d'informations sur cette fonctionnalit�. +

+ Autre remarque : suivant le pilote SQL renseign� dans les param�tres de connexion, la + biblioth�que QxOrm associe automatiquement un g�n�rateur SQL. + Ce g�n�rateur SQL permet de g�rer les sp�cificit�s propres � chaque type de base de donn�es. + Tous les g�n�rateurs SQL h�ritent de la classe de base : qx::dao::detail::IxSqlGenerator : + + + + + + + + +
+
   qx::dao::detail::IxSqlGenerator_ptr pSqlGenerator;
+   pSqlGenerator.reset(new qx::dao::detail::QxSqlGenerator_MSSQLServer());   
+   qx::QxSqlDatabase::getSingleton()->setSqlGenerator(pSqlGenerator);   
+
+

+
+

Sauvegarder une instance + C++ en base de donn�es (insert/update)

+
+ Toutes les fonctions li�es � la base de donn�es sont disponibles dans l'espace de nom + qx::dao.
+
+ Pour sauvegarder une instance C++ (ou une liste d'instances C++) en base de donn�es, la + biblioth�que QxOrm fournit les fonctions suivantes : +
    +
  • qx::dao::insert : ins�re une instance (ou une liste + d'instances) en base de donn�es ;
  • +
  • qx::dao::insert_with_relation : ins�re une instance (ou une + liste d'instances) + ses relations en base de donn�es ;
  • +
  • qx::dao::insert_with_all_relation : ins�re une instance (ou + une liste d'instances) + toutes ses relations en base de donn�es ;
  • +
    +
  • qx::dao::update : met � jour une instance (ou une liste + d'instances) en base de donn�es ;
  • +
  • qx::dao::update_with_relation : met � jour une instance (ou + une liste d'instances) + ses relations en base de donn�es ;
  • +
  • qx::dao::update_with_all_relation : met � jour une instance + (ou une liste d'instances) + toutes ses relations en base de donn�es ;
  • +
  • qx::dao::update_by_query : met � jour une instance (ou une + liste d'instances) en base de donn�es en filtrant avec une requ�te SQL ;
  • +
  • qx::dao::update_by_query_with_relation : met � jour une + instance (ou une liste d'instances) + ses relations en base de donn�es en filtrant avec + une requ�te SQL ;
  • +
  • qx::dao::update_by_query_with_all_relation : met � jour une + instance (ou une liste d'instances) + toutes ses relations en base de donn�es en filtrant + avec une requ�te SQL ;
  • +
  • qx::dao::update_optimized : met � jour uniquement les champs + modifi�s d'une instance (ou d'une liste d'instances) en base de donn�es en utilisant le + pattern is dirty et les fonctionnalit�s de la classe qx::dao::ptr ;
  • +
  • qx::dao::update_optimized_by_query : met � jour uniquement + les champs modifi�s d'une instance (ou d'une liste d'instances) en base de donn�es en + utilisant le pattern is dirty et les fonctionnalit�s de la classe qx::dao::ptr et en filtrant avec une requ�te SQL ;
  • +
    +
  • qx::dao::save : ins�re (si l'�l�ment n'existe pas en base de + donn�es) ou met � jour (si l'�l�ment existe d�j� en base de donn�es) ;
  • +
  • qx::dao::save_with_relation : ins�re (si l'�l�ment n'existe + pas en base de donn�es) ou met � jour (si l'�l�ment existe d�j� en base de donn�es) + ses + relations ;
  • +
  • qx::dao::save_with_all_relation : ins�re (si l'�l�ment + n'existe pas en base de donn�es) ou met � jour (si l'�l�ment existe d�j� en base de + donn�es) + toutes ses relations ;
  • +
  • qx::dao::save_with_relation_recursive : ins�re (si l'�l�ment + n'existe pas en base de donn�es) ou met � jour (si l'�l�ment existe d�j� en base de + donn�es) + toutes les relations sur tous les niveaux : utile pour sauvegarder en 1 + commande une structure en arbre par exemple.
  • +
+
+ Par exemple :
+ + + + + + + +
+
   // Create 3 drugs instances
+   // It is possible to use 'boost' and 'Qt' smart pointer : 'boost::shared_ptr', 'QSharedPointer', etc...
+   typedef boost::shared_ptr<drug> drug_ptr;
+   drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1";
+   drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2";
+   drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3";
+
+   // Insert some drugs into a container
+   // It is possible to use many containers from 'std', 'boost', 'Qt' and 'qx::QxCollection<Key, Value>'
+   typedef std::vector<drug_ptr> type_lst_drug;
+   type_lst_drug lst_drug;
+   lst_drug.push_back(d1);
+   lst_drug.push_back(d2);
+   lst_drug.push_back(d3);
+
+   // Insert drugs from container to database
+   // 'id' property of 'd1', 'd2' and 'd3' are auto-updated
+   QSqlError daoError = qx::dao::insert(lst_drug);
+
+   // Modify and update the second drug into database
+   d2->name = "name2 modified";
+   d2->description = "desc2 modified";
+   daoError = qx::dao::update(d2);
+
+
+

+ Remarque : toutes les fonctions de l'espace de nom qx::dao sont flexibles au niveau des param�tres, elles + peuvent accepter : une instance, une liste d'instances, un pointeur, un pointeur intelligent, + une liste de pointeurs, une liste de pointeurs intelligents, etc... Par exemple : +
    +
  • my_entity t;     /* ... */     + qx::dao::insert(t);
  • +
  • my_entity * t;     /* ... */     + qx::dao::insert(t);
  • +
  • std::shared_ptr<my_entity> t;     /* ... + */     qx::dao::insert(t);
  • +
  • QList<my_entity> lst;     /* ... */     + qx::dao::insert(lst);
  • +
  • QList<std::shared_ptr<my_entity> > lst;     /* ... + */     qx::dao::insert(lst);
  • +
+ Pour connaitre la liste des collections support�es, rendez-vous dans le chapitre : Collections support�es par QxOrm.
+ Pour connaitre la liste des pointeurs intelligents support�s, rendez-vous dans le chapitre : Pointeurs intelligents support�s par QxOrm (smart-pointers).
+

+
+

Supprimer une instance + C++ de la base de donn�es (delete)

+
+ Toutes les fonctions li�es � la base de donn�es sont disponibles dans l'espace de nom + qx::dao.
+
+ Pour supprimer une instance C++ (ou une liste d'instances C++) en base de donn�es, la + biblioth�que QxOrm fournit les fonctions suivantes : + +
+ Par exemple :
+ + + + + + + +
+
   // Create a drug instance with id '18'
+   drug d; d.setId(18);
+
+   // Delete the drug with id '18' from database
+   QSqlError daoError = qx::dao::delete_by_id(d);
+
+   // Delete all drugs from database
+   daoError = qx::dao::delete_all<drug>();
+
+

+

Suppression logique + (soft delete)

+
+ Une suppression logique permet de ne pas effacer de ligne dans une table d'une base de + donn�es (contrairement � une suppression physique) : une colonne suppl�mentaire est ajout�e � + la d�finition de la table pour indiquer que la ligne est supprim�e ou non.
+ Cette colonne peut contenir soit un bool�en (1 signifie ligne supprim�e, 0 ou vide signifie + ligne non supprim�e), soit la date-heure de suppression de la ligne (si vide, la ligne est + consid�r�e comme non supprim�e).
+ Il est donc � tout moment possible de r�activer une ligne supprim�e en r�initialisant la + valeur � vide dans la table de la base de donn�es.
+
+ Pour activer le m�canisme de suppression logique avec la biblioth�que QxOrm, il faut utiliser + la classe qx::QxSoftDelete dans la fonction de mapping + qx::register_class<T>.
+ Voici un exemple d'utilisation avec une classe Bar contenant deux propri�t�s + m_id et m_desc :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<Bar> & t)
+{
+   t.setSoftDelete(qx::QxSoftDelete("deleted_at"));
+
+   t.id(& Bar::m_id, "id");
+   t.data(& Bar::m_desc, "desc");
+}}
+
+
+ Les requ�tes SQL g�n�r�es automatiquement par la biblioth�que QxOrm vont prendre en compte ce + param�tre de suppression logique pour ajouter les conditions n�cessaires (ne pas r�cup�rer + les �l�ments supprim�s, ne pas supprimer physiquement une ligne, etc.).
+ Par exemple, si vous ex�cutez les lignes suivantes avec la classe Bar :
+
+ + + + + + + +
+
Bar_ptr pBar; pBar.reset(new Bar());
+pBar->setId(5);
+QSqlError daoError = qx::dao::delete_by_id(pBar);     qAssert(! daoError.isValid());
+qx_bool bDaoExist = qx::dao::exist(pBar);             qAssert(! bDaoExist);
+daoError = qx::dao::delete_all<Bar>();                qAssert(! daoError.isValid());
+long lBarCount = qx::dao::count<Bar>();               qAssert(lBarCount == 0);
+daoError = qx::dao::destroy_all<Bar>();               qAssert(! daoError.isValid());
+
+
+ Vous obtiendrez les traces suivantes :
+
+ + + + + + + +
+
[QxOrm] sql query (93 ms) : UPDATE Bar SET deleted_at = '20110617115148615' WHERE id = :id
+[QxOrm] sql query (0 ms) : SELECT Bar.id AS Bar_id_0, Bar.deleted_at FROM Bar WHERE Bar.id = :id 
+                                         AND (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (78 ms) : UPDATE Bar SET deleted_at = '20110617115148724'
+[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM Bar WHERE (Bar.deleted_at IS NULL OR Bar.deleted_at = '')
+[QxOrm] sql query (110 ms) : DELETE FROM Bar
+
+
+ Remarque : pour supprimer physiquement une ligne de la base de donn�es, il faut + utiliser les fonctions : qx::dao::destroy_by_id() et + qx::dao::destroy_all().
+
+ Autre remarque : il peut �tre int�ressant de d�finir au niveau du SGBD un index sur la + colonne deleted_at (ou peu importe le nom que vous donnez) afin d'acc�l�rer + l'ex�cution des requ�tes SQL.
+
+
+
+

R�cup�rer une instance + C++ de la base de donn�es (fetch)

+
+ Toutes les fonctions li�es � la base de donn�es sont disponibles dans l'espace de nom + qx::dao.
+
+ Pour valoriser automatiquement les propri�t�s d'une instance C++ (ou d'une liste d'instances + C++) en fonction des donn�es d'une table (ou plusieurs tables si des relations sont d�finies) de + la base de donn�es, la biblioth�que QxOrm fournit les fonctions suivantes : +
    +
  • qx::dao::fetch_by_id : r�cup�re de la base de donn�es + l'�l�ment (ou une liste d'�l�ments) associ� � l'id pass� en param�tre ;
  • +
  • qx::dao::fetch_by_id_with_relation : r�cup�re de la base de + donn�es l'�l�ment (ou une liste d'�l�ments) + ses relations en fonction de l'id pass� en + param�tre ;
  • +
  • qx::dao::fetch_by_id_with_all_relation : r�cup�re de la base + de donn�es l'�l�ment (ou une liste d'�l�ments) + toutes ses relations en fonction de l'id + pass� en param�tre ;
  • +
    +
  • qx::dao::fetch_all : r�cup�re toutes les entr�es d'une table + de la base de donn�es ;
  • +
  • qx::dao::fetch_all_with_relation : r�cup�re toutes les + entr�es d'une table + ses relations de la base de donn�es ;
  • +
  • qx::dao::fetch_all_with_all_relation : r�cup�re toutes les + entr�es d'une table + toutes ses relations de la base de donn�es ;
  • +
    +
  • qx::dao::fetch_by_query : r�cup�re toutes les entr�es d'une + table de la base de donn�es en fonction d'une requ�te SQL ;
  • +
  • qx::dao::fetch_by_query_with_relation : r�cup�re toutes les + entr�es d'une table de la base de donn�es + ses relations en fonction d'une requ�te SQL ; +
  • +
  • qx::dao::fetch_by_query_with_all_relation : r�cup�re toutes + les entr�es d'une table de la base de donn�es + toutes ses relations en fonction d'une + requ�te SQL ;
  • +
    +
  • qx::dao::exist : teste l'existence d'un �l�ment (ou d'une + liste d'�l�ments) en base de donn�es en fonction de son identifiant (primary key). +
  • +
+
+ Par exemple :
+ + + + + + + +
+
   // Fetch drug with id '3' into a new variable
+   drug_ptr d; d.reset(new drug());
+   d->id = 3;
+   QSqlError daoError = qx::dao::fetch_by_id(d);
+
+

+
+

Requ�tes SQL

+
+ La biblioth�que QxOrm fournit plusieurs outils pour effectuer des requ�tes � la base de donn�es + : + + Remarque : QxOrm �tant bas� sur le module QtSql de Qt, il est + toujours possible de requ�ter la base de donn�es en utilisant la classe QSqlQuery de Qt si les + fonctionnalit�s propos�es par QxOrm ne sont pas suffisantes. +

+

Utilisation de la + classe qx::QxSqlQuery (ou son alias qx_query)

+
+ La classe qx::QxSqlQuery (ou bien son alias qx_query) permet + d'interroger la base de donn�es (trier, filtrer, etc.) de deux mani�res diff�rentes : + + Le principal avantage de la premi�re m�thode (�criture manuelle des requ�tes SQL) est de + pouvoir utiliser certaines optimisations sp�cifiques � chaque base de donn�es.
+ La deuxi�me m�thode (utilisation du code C++ pour g�n�rer la requ�te SQL) permet de mapper + automatiquement les param�tres SQL sans utiliser la fonction + qx::QxSqlQuery::bind().
+
+ Voici un exemple d'utilisation de la classe qx::QxSqlQuery avec �criture manuelle + d'une requ�te SQL :
+
+ + + + + + + +
+
// Construit une requ�te pour r�cup�rer uniquement les 'author' de type 'female'
+qx::QxSqlQuery query("WHERE author.sex = :sex");
+query.bind(":sex", author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* traitement avec la collection issue de la base de donn�es */ }
+
+
+ La biblioth�que QxOrm supporte trois syntaxes pour l'�criture des param�tres SQL.
+ Le type de syntaxe peut �tre modifi� de fa�on globale � un projet en utilisant la m�thode + suivante : qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle().
+ Les trois param�tres possibles pour cette m�thode sont : +
    +
  • ph_style_2_point_name : "WHERE author.sex = :sex" (syntaxe par d�faut) ;
  • +
  • ph_style_at_name : "WHERE author.sex = @sex" ;
  • +
  • ph_style_question_mark : "WHERE author.sex = ?".
  • +
+ Voici le m�me exemple en utilisant les m�thodes C++ de la classe qx::QxSqlQuery (ou + bien son alias qx_query) pour g�n�rer la requ�te automatiquement :
+
+ + + + + + + +
+
// Construit une requ�te pour r�cup�rer uniquement les 'author' de type 'female'
+qx_query query;
+query.where("author.sex").isEqualTo(author::female);
+
+QList<author> list_of_female;
+QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female);
+for (long l = 0; l < list_of_female.count(); l++)
+{ /* traitement avec la collection issue de la base de donn�es */ }
+
+
+ Cette utilisation de la classe qx::QxSqlQuery pr�sente l'avantage de ne pas avoir � + mapper les param�tres de la requ�te, tout en restant tr�s proche de l'�criture manuelle d'une + requ�te SQL.
+ Les param�tres seront automatiquement inject�s en utilisant la syntaxe d�finie de mani�re + globale par la m�thode : + qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle().
+
+ Voici un exemple pr�sentant diff�rentes m�thodes disponibles avec la classe + qx::QxSqlQuery (ou bien son alias qx_query) :
+
+ + + + + + + +
+
qx_query query;
+query.where("sex").isEqualTo(author::female)
+     .and_("age").isGreaterThan(38)
+     .or_("last_name").isNotEqualTo("Dupont")
+     .or_("first_name").like("Alfred")
+     .and_OpenParenthesis("id").isLessThanOrEqualTo(999)
+     .and_("birth_date").isBetween(date1, date2)
+     .closeParenthesis()
+     .or_("id").in(50, 999, 11, 23, 78945)
+     .and_("is_deleted").isNotNull()
+     .orderAsc("last_name", "first_name", "sex")
+     .limit(50, 150);
+
+
+ Ce qui produira le code SQL suivant pour les bases de donn�es MySQL, PostgreSQL + et SQLite (pour Oracle et SQLServer, le traitement de la m�thode + limit() est diff�rent) :
+
+ + + + + + + +
+
WHERE sex = :sex_1_0 
+AND age > :age_3_0 
+OR last_name <> :last_name_5_0 
+OR first_name LIKE :first_name_7_0 
+AND ( id <= :id_10_0 AND birth_date BETWEEN :birth_date_12_0_1 AND :birth_date_12_0_2 ) 
+OR id IN (:id_15_0_0, :id_15_0_1, :id_15_0_2, :id_15_0_3, :id_15_0_4) 
+AND is_deleted IS NOT NULL 
+ORDER BY last_name ASC, first_name ASC, sex ASC 
+LIMIT :limit_rows_count_19_0 OFFSET :offset_start_row_19_0
+
+
+ Voici la liste des fonctions et m�thodes disponibles pour utiliser la classe + qx::QxSqlQuery (ou bien son alias qx_query) :
+
+ + + + + + + +
+
// avec les fonctions du namespace qx::dao
+qx::dao::count<T>()
+qx::dao::fetch_by_query<T>()
+qx::dao::update_by_query<T>()
+qx::dao::delete_by_query<T>()
+qx::dao::destroy_by_query<T>()
+qx::dao::fetch_by_query_with_relation<T>()
+qx::dao::fetch_by_query_with_all_relation<T>()
+qx::dao::update_by_query_with_relation<T>()
+qx::dao::update_by_query_with_all_relation<T>()
+qx::dao::update_optimized_by_query<T>()
+
+// avec la classe qx::QxSession
+qx::QxSession::count<T>()
+qx::QxSession::fetchByQuery<T>()
+qx::QxSession::update<T>()
+qx::QxSession::deleteByQuery<T>()
+qx::QxSession::destroyByQuery<T>()
+
+// avec la classe qx::QxRepository<T>
+qx::QxRepository<T>::count()
+qx::QxRepository<T>::fetchByQuery()
+qx::QxRepository<T>::update()
+qx::QxRepository<T>::deleteByQuery()
+qx::QxRepository<T>::destroyByQuery()
+
+
+ Remarque : certaines de ces fonctions ont �galement deux autres param�tres optionnels + : +
    +
  • const QStringList & columns : pour indiquer la liste des colonnes � r�cup�rer + (par d�faut, toutes les colonnes sont r�cup�r�es) ;
  • +
  • const QStringList & relation : pour indiquer les jointures (one-to-one, + one-to-many, many-to-one et many-to-many d�finies dans la fonction + de mapping void qx::register_class<T>()) entre les tables de la base de + donn�es (par d�faut, aucune relation). +
  • +
+
+
+

Appel de proc�dure + stock�e ou requ�te SQL personnalis�e

+
+ La biblioth�que QxOrm fournit deux fonctions pour appeler une proc�dure stock�e ou une + requ�te SQL personnalis�e : + + Le premier param�tre de ces deux fonctions, de type qx::QxSqlQuery (ou son alias qx_query), correspond � la + proc�dure stock�e ou � la requ�te SQL personnalis�e.
+ Pour plus d'informations sur la classe qx::QxSqlQuery, rendez-vous sur ce chapitre du manuel + utilisateur : Utilisation de la classe qx::QxSqlQuery (ou son alias + qx_query).
+
+ La fonction qx::dao::execute_query<T>() est une fonction template : + le type T doit �tre enregistr� dans le contexte QxOrm (fonction + qx::register_class<T>).
+ Toutes les donn�es renvoy�es par la proc�dure stock�e ou la requ�te SQL personnalis�e qui + pourront �tre associ�es aux membres des classes C++ (de type T) seront valoris�es + automatiquement.
+ Une recherche automatique est effectu�e sur le nom des champs associ�s aux donn�es.
+ Voici un exemple d'utilisation (disponible dans le projet qxBlog du package QxOrm) :
+
+ + + + + + + +
+
// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+qx_query testStoredProcBis("SELECT * FROM author");
+daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+qx::dump(authorX);
+
+

+ La fonction qx::dao::call_query() n'est pas une fonction template : les + r�sultats de la requ�te doivent �tre parcourus manuellement sur la classe qx::QxSqlQuery (ou qx_query).
+ Pour r�cup�rer un param�tre de sortie (qui doit �tre pass� � la requ�te en tant que + QSql::Out ou QSql::InOut), il suffit d'utiliser la m�thode : QVariant + qx::QxSqlQuery::boundValue(const QString & sKey) const;.
+
+ Pour parcourir la liste des r�sultats de la requ�te, il faut utiliser les m�thodes suivantes + : +
    +
  • long qx::QxSqlQuery::getSqlResultRowCount() const;
  • +
  • long qx::QxSqlQuery::getSqlResultColumnCount() const;
  • +
  • QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const;
  • +
  • QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) + const;
  • +
  • QVector qx::QxSqlQuery::getSqlResultAllColumns() const;
  • +
  • void qx::QxSqlQuery::dumpSqlResult();
  • +
+ Voici un exemple d'utilisation avec la fonction qx::dao::call_query() + :
+
+ + + + + + + +
+
qx_query query("CALL MyStoredProc(:param1, :param2)");
+query.bind(":param1", "myValue1");
+query.bind(":param2", 5024, QSql::InOut);
+QSqlError daoError = qx::dao::call_query(query);
+QVariant vNewValue = query.boundValue(":param2");
+query.dumpSqlResult();
+
+

+
+
+

Transactions (commit, + rollback, session)

+
+ Une transaction est une suite d'op�rations effectu�es comme une seule + unit� logique de travail.
+ Une fois termin�e, la transaction est : +
    +
  • soit valid�e (commit), alors toutes les modifications sont faites dans la base de + donn�es ;
  • +
  • soit annul�e (rollback), alors toutes les modifications ne sont pas enregistr�e. +
  • +
+ La classe qx::QxSession de la biblioth�que QxOrm permet de g�rer + automatiquement les transactions (validation, annulation) en utilisant le m�canisme C++ RAII :
+
+ + + + + + + +
+
{ // Ouverture d'un scope o� une session sera instanci�e
+
+  // Cr�ation d'une session : une connexion valide � la BDD est assign�e � la session et une transaction est d�marr�e
+  qx::QxSession session;
+
+  // Ex�cution d'une s�rie d'op�rations avec la BDD (en utilisant l'op�rateur += de la classe qx::QxSession et la connexion de la session)
+  session += qx::dao::insert(my_object, session.database());
+  session += qx::dao::update(my_object, session.database());
+  session += qx::dao::fetch_by_id(my_object, session.database());
+  session += qx::dao::delete_by_id(my_object, session.database());
+
+  // Si la session n'est pas valide (donc une erreur s'est produite) => affichage de la 1�re erreur de la session
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // Fermeture du scope : la session est d�truite (transaction => commit ou rollback automatique)
+
+
+ Remarque : une session peut d�clencher une exception de type qx::dao::sql_error lorsqu'une erreur se produit (par d�faut, + aucune exception n'est d�clench�e). Il est possible de param�trer ce comportement en utilisant : +
    +
  • soit le constructeur de la classe qx::QxSession (pour une session en particulier) + ;
  • +
  • soit le param�tre du singleton + qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b) (pour toutes les + sessions). +
  • +
+ Autre remarque : il est important de ne pas oublier de passer la connexion � la base de + donn�es de la session � chaque fonction qx::dao::xxx (en utilisant la m�thode + session.database()).
+ De plus, il est possible d'initialiser une session avec sa propre connexion (provenant d'un pool + de connexions par exemple) en utilisant le constructeur de la classe qx::QxSession.
+
+ La classe qx::QxSession propose �galement des m�thodes de persistance (CRUD), ce qui peut + simplifier l'�criture du code C++ suivant les habitudes de programmation.
+ Voici le m�me exemple en utilisant les m�thodes de la classe qx::QxSession � la place des + fonctions du namespace qx::dao :
+
+ + + + + + + +
+
{ // Ouverture d'un scope o� une session sera instanci�e
+
+  // Cr�ation d'une session : une connexion valide � la BDD est assign�e � la session et une transaction est d�marr�e
+  qx::QxSession session;
+
+  // Ex�cution d'une s�rie d'op�rations avec la BDD
+  session.insert(my_object);
+  session.update(my_object);
+  session.fetchById(my_object);
+  session.deleteById(my_object);
+
+  // Si la session n'est pas valide (donc une erreur s'est produite) => affichage de la 1�re erreur de la session
+  if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); }
+
+} // Fermeture du scope : la session est d�truite (transaction => commit ou rollback automatique)
+
+

+
+

Moteur de relations +

+
+ La biblioth�que QxOrm fournit un puissant moteur de relations permettant de d�finir facilement : + + Remarque : un tutoriel complet sur les relations bas� sur le + projet de test qxBlog (dont les sources sont pr�sentes dans le package QxOrm) est + disponible. +

+

one-to-many (1-n) +

+
+ Une relation one-to-many (1-n) est d�finie par la m�thode : qx::QxClass<T>::relationOneToMany(). + Cette m�thode renvoie une instance de la classe qx::IxSqlRelation (classe de base pour toutes les relations) et + n�cessite 3 param�tres : +
    +
  • V U::* pData : r�f�rence vers la donn�e membre de la classe ;
  • +
  • const QString & sKey : cl� unique associ�e � la relation ;
  • +
  • const QString & sForeignKey : cl� �trang�re d�finie dans la classe/table li�e. +
  • +
+
+ Par exemple : prenons l'exemple d'un author (une personne) qui peut r�diger + plusieurs blog + : nous allons ainsi montrer comment d�finir une relation de type + one-to-many.
+ Au niveau base de donn�es, voici les deux tables qui correspondent :
+
+ qxBlog.table.author
+
+ Fichier author.h :
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- propri�t�s
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- constructeur, destructeur virtuel
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- m�thodes
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ Fichier author.cpp :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+

+
+

many-to-one (n-1) +

+
+ Une relation many-to-one (n-1) est d�finie par la m�thode : qx::QxClass<T>::relationManyToOne(). + Cette m�thode renvoie une instance de la classe qx::IxSqlRelation (classe de base pour toutes les relations) et + n�cessite 2 param�tres : +
    +
  • V U::* pData : r�f�rence vers la donn�e membre de la classe ;
  • +
  • const QString & sKey : cl� unique associ�e � la relation (correspond � une + colonne de la table dans la base de donn�es).
  • +
+
+ Par exemple : un comment est associ� � un blog et un blog peut + contenir plusieurs comment : nous allons ainsi montrer comment + d�finir une relation de type many-to-one.
+ Au niveau base de donn�es, voici les deux tables qui correspondent :
+
+ qxBlog.table.comment
+
+ Fichier comment.h :
+ + + + + + + +
+
#ifndef _QX_BLOG_COMMENT_H_
+#define _QX_BLOG_COMMENT_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT comment
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+// -- propri�t�s
+   long        m_id;
+   QString     m_text;
+   QDateTime   m_dt_create;
+   blog_ptr    m_blog;
+// -- constructeur, destructeur virtuel
+   comment() : m_id(0) { ; }
+   virtual ~comment() { ; }
+};
+
+QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<comment> comment_ptr;
+typedef QList<comment_ptr> list_comment;
+
+#endif // _QX_BLOG_COMMENT_H_
+
+
+
+ Fichier comment.cpp :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/comment.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(comment)
+
+namespace qx {
+template <> void register_class(QxClass<comment> & t)
+{
+   t.id(& comment::m_id, "comment_id");
+
+   t.data(& comment::m_text, "comment_text");
+   t.data(& comment::m_dt_create, "date_creation");
+
+   t.relationManyToOne(& comment::m_blog, "blog_id");
+}}
+
+
+

+
+

many-to-many + (n-n)

+
+ Une relation many-to-many (n-n) est d�finie par la m�thode : qx::QxClass<T>::relationManyToMany(). + Cette m�thode renvoie une instance de la classe qx::IxSqlRelation (classe de base pour toutes les relations) et + n�cessite 5 param�tres : +
    +
  • V U::* pData : r�f�rence vers la donn�e membre de la classe ;
  • +
  • const QString & sKey : cl� unique associ�e � la relation ;
  • +
  • const QString & sExtraTable : nom de la table suppl�mentaire permettant de + stocker les id de chaque c�t� des relations ;
  • +
  • const QString & sForeignKeyOwner : cl� �trang�re d�finie dans la table + suppl�mentaire pour repr�senter la classe/table courante ;
  • +
  • const QString & sForeignKeyDataType : cl� �trang�re d�finie dans la table + suppl�mentaire pour repr�senter la classe/table associ�e � la relation.
  • +
+
+ Par exemple : une category r�f�rence plusieurs blog et un blog + peut + appartenir � plusieurs category : nous allons ainsi montrer + comment d�finir une relation de type many-to-many. + Ce type de relation implique une table suppl�mentaire dans la base de + donn�es pour stocker la liste des id de chaque c�t� des + relations.
+ Au niveau base de donn�es, voici les trois tables qui correspondent :
+
+ qxBlog.table.category
+
+ Fichier category.h :
+ + + + + + + +
+
#ifndef _QX_BLOG_CATEGORY_H_
+#define _QX_BLOG_CATEGORY_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT category
+{
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef qx::QxCollection<long, blog_ptr> list_blog;
+// -- propri�t�s
+   long        m_id;
+   QString     m_name;
+   QString     m_desc;
+   list_blog   m_blogX;
+// -- constructeur, destructeur virtuel
+   category() : m_id(0) { ; }
+   virtual ~category() { ; }
+};
+
+QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0)
+
+typedef QSharedPointer<category> category_ptr;
+typedef qx::QxCollection<long, category_ptr> list_category;
+
+#endif // _QX_BLOG_CATEGORY_H_
+
+
+
+ Fichier category.cpp :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/category.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(category)
+
+namespace qx {
+template <> void register_class(QxClass<category> & t)
+{
+   t.id(& category::m_id, "category_id");
+
+   t.data(& category::m_name, "name");
+   t.data(& category::m_desc, "description");
+
+   t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id");
+}}
+
+
+

+
+

one-to-one (1-1) +

+
+ Une relation one-to-one (1-1) permet de repr�senter 2 entit�s distinctes qui partagent + le m�me identifiant en base de donn�es. + Une relation one-to-one (1-1) est d�finie par la m�thode : qx::QxClass<T>::relationOneToOne(). + Cette m�thode renvoie une instance de la classe qx::IxSqlRelation (classe de base pour toutes les relations) et + n�cessite 2 param�tres : +
    +
  • V U::* pData : r�f�rence vers la donn�e membre de la classe ;
  • +
  • const QString & sKey : cl� unique associ�e � la relation.
  • +
+
+ Par exemple : prenons l'exemple d'une table person et d'une autre table + author : un author est �galement une person, les 2 tables pourraient + partager le m�me identifiant en base de donn�es. + Au niveau base de donn�es, voici les 2 tables qui correspondent (person_id == + author_id) :
+
+ qxBlog.table.person +


+
+

Requ�te SQL avec + relations

+
+ La biblioth�que QxOrm supporte quatre types de relations pour lier les classes C++ + enregistr�es dans le contexte QxOrm : one-to-one, one-to-many, + many-to-one et many-to-many.
+ Pour plus de d�tails sur la d�finition de ces relations, il est conseill� de lire le tutoriel qxBlog.
+ Nous allons d�tailler dans cette Q&R les diff�rentes m�thodes de r�cup�ration des donn�es + (module QxDao, fonctions du + namespace qx::dao) : + + Le premier param�tre des fonctions fetch_by_id_with_relation, fetch_all_with_relation + et fetch_by_query_with_relation correspond � la liste des relations � + requ�ter.
+ Cette liste de relations peut contenir les �l�ments suivants : +
    +
  • identifiant d'une relation : chaque relation poss�de une cl� d�finie au niveau de la + fonction de param�trage qx::register_class<T> ;
  • +
  • le mot-cl� "*" signifie "r�cup�rer toutes les relations d�finies dans la + fonction de param�trage qx::register_class<T> sur un niveau" ;
  • +
  • le mot-cl� "->" signifie jointure de type "LEFT OUTER JOIN" (jointure + par d�faut de la biblioth�que QxOrm) ;
  • +
  • le mot-cl� ">>" signifie jointure de type "INNER JOIN" entre deux + tables.
  • +
+ Remarque : en utilisant le mot-cl� "*" pour indiquer "toutes les relations sur un + niveau", les appels suivants sont �quivalents : +
    +
  • qx::dao::fetch_by_id_with_relation("*", ...) == + qx::dao::fetch_by_id_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_by_query_with_relation("*", ...) == + qx::dao::fetch_by_query_with_all_relation(...) ; +
  • +
  • qx::dao::fetch_all_with_relation("*", ...) == + qx::dao::fetch_all_with_all_relation(...). +
  • +
+
+ Exemple : � partir du tutoriel qxBlog, il est possible de r�cup�rer les donn�es + suivantes avec une seule requ�te :
+
+ 1- r�cup�rer un blog et son author ;
+ 2- pour l'author valoris�, r�cup�rer tous les blog qu'il a �crit ;
+ 3- pour chaque blog que l'author a �crit, r�cup�rer tous les + comment associ�s.
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("author_id->list_blog->list_comment", my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Autre exemple : il est �galement possible de cr�er une liste de relations � r�cup�rer, + comme ceci par exemple :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QStringList relation;
+relation << "author_id->list_blog->list_comment";
+relation << "author_id->list_blog->list_category";
+relation << "list_comment";
+relation << "list_category";
+QSqlError daoError = qx::dao::fetch_by_id_with_relation(relation, my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, 
+       category_7.category_id AS category_7_category_id_0, category_7.name AS category_7_name_0, category_7.description AS category_7_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN category_blog category_blog_7 ON blog.blog_id = category_blog_7.blog_id 
+LEFT OUTER JOIN category category_7 ON category_blog_7.category_id = category_7.category_id 
+WHERE blog.blog_id = :blog_id
+
+

+ Autre exemple : pour r�cup�rer toutes les relations pour un niveau donn�, il faut + utiliser le mot-cl� "*".
+ Pour r�cup�rer toutes les donn�es de toutes les relations sur trois niveaux, il faut �crire + :
+
+ + + + + + + +
+
blog_ptr my_blog = blog_ptr(new blog(10));
+QSqlError daoError = qx::dao::fetch_by_id_with_relation("*->*->*", my_blog);
+
+
+ Ce qui g�n�re la requ�te SQL suivante : +
+
SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, 
+       author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, 
+       blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, blog_2.author_id AS blog_2_author_id_0_2, 
+       author_3.author_id AS author_3_author_id_0, author_3.name AS author_3_name_0, author_3.birthdate AS author_3_birthdate_0, author_3.sex AS author_3_sex_0, 
+       comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0, 
+       category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0, 
+       comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, comment_6.blog_id AS comment_6_blog_id_0_6, 
+       blog_7.blog_id AS blog_7_blog_id_0, blog_7.blog_text AS blog_7_blog_text_0, blog_7.date_creation AS blog_7_date_creation_0, blog_7.author_id AS blog_7_author_id_0_7, 
+       author_8.author_id AS author_8_author_id_0, author_8.name AS author_8_name_0, author_8.birthdate AS author_8_birthdate_0, author_8.sex AS author_8_sex_0, 
+       comment_9.comment_id AS comment_9_comment_id_0, comment_9.blog_id AS comment_9_blog_id_0, comment_9.comment_text AS comment_9_comment_text_0, comment_9.date_creation AS comment_9_date_creation_0, 
+       category_10.category_id AS category_10_category_id_0, category_10.name AS category_10_name_0, category_10.description AS category_10_description_0, 
+       category_11.category_id AS category_11_category_id_0, category_11.name AS category_11_name_0, category_11.description AS category_11_description_0, 
+       blog_12.blog_id AS blog_12_blog_id_0, blog_12.blog_text AS blog_12_blog_text_0, blog_12.date_creation AS blog_12_date_creation_0, blog_12.author_id AS blog_12_author_id_0_12, 
+       author_13.author_id AS author_13_author_id_0, author_13.name AS author_13_name_0, author_13.birthdate AS author_13_birthdate_0, author_13.sex AS author_13_sex_0, 
+       comment_14.comment_id AS comment_14_comment_id_0, comment_14.blog_id AS comment_14_blog_id_0, comment_14.comment_text AS comment_14_comment_text_0, comment_14.date_creation AS comment_14_date_creation_0, 
+       category_15.category_id AS category_15_category_id_0, category_15.name AS category_15_name_0, category_15.description AS category_15_description_0 
+FROM blog 
+LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id 
+LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id 
+LEFT OUTER JOIN author author_3 ON author_3.author_id = blog_2.author_id 
+LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id 
+LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id 
+LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id 
+LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id 
+LEFT OUTER JOIN blog blog_7 ON blog_7.blog_id = comment_6.blog_id 
+LEFT OUTER JOIN author author_8 ON author_8.author_id = blog_7.author_id 
+LEFT OUTER JOIN comment comment_9 ON comment_9.blog_id = blog_7.blog_id 
+LEFT OUTER JOIN category_blog category_blog_10 ON blog_7.blog_id = category_blog_10.blog_id 
+LEFT OUTER JOIN category category_10 ON category_blog_10.category_id = category_10.category_id 
+LEFT OUTER JOIN category_blog category_blog_11 ON blog.blog_id = category_blog_11.blog_id 
+LEFT OUTER JOIN category category_11 ON category_blog_11.category_id = category_11.category_id 
+LEFT OUTER JOIN category_blog category_blog_12 ON category_11.category_id = category_blog_12.category_id 
+LEFT OUTER JOIN blog blog_12 ON category_blog_12.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN author author_13 ON author_13.author_id = blog_12.author_id 
+LEFT OUTER JOIN comment comment_14 ON comment_14.blog_id = blog_12.blog_id 
+LEFT OUTER JOIN category_blog category_blog_15 ON blog_12.blog_id = category_blog_15.blog_id 
+LEFT OUTER JOIN category category_15 ON category_blog_15.category_id = category_15.category_id 
+WHERE blog.blog_id = :blog_id
+
+
+
+

S�lectionner les + colonnes des relations � r�cup�rer et d�finition des alias SQL

+
+ Il est parfois n�cessaire de ne pas requ�ter toutes les colonnes d'une table par soucis + d'optimisation : en effet, s�lectionner les colonnes r�ellement utilis�es par un traitement + permet de limiter les flux r�seau entre la base de donn�es et l'application C++, ce qui + am�liore les performances.
+
+ Concernant les relations, la biblioth�que QxOrm fournit une syntaxe sp�cifique pour + s�lectionner les colonnes � r�cup�rer, sous la forme : my_relation { col_1, col_2, etc... + }. + Si cette syntaxe n'est pas utilis�e, par d�faut, QxOrm r�cup�re toutes les colonnes.
+
+ Par exemple : imaginons la requ�te suivante qui permet de r�cup�rer : +
    +
  • uniquement la colonne blog_text de la table blog ;
  • +
  • uniquement les colonnes name et birthdate de la table author ; +
  • +
  • uniquement la colonne comment_text de la table comment.
  • +
+ + + + + + + +
+
   // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... }
+   list_blog lstBlogComplexRelation;
+   QStringList relations = QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text }";
+   QSqlError daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation);
+
+   qx::dump(lstBlogComplexRelation);
+   qAssert(lstBlogComplexRelation.size() > 0);
+   qAssert(lstBlogComplexRelation[0]->m_text != ""); // Fetched
+   qAssert(lstBlogComplexRelation[0]->m_dt_creation.isNull()); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched
+   qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0);
+   qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched
+   qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched
+
+
+ Remarque : une autre syntaxe est disponible afin de renseigner les colonnes � ne pas + r�cup�rer : my_relation -{ col_1, col_2, etc... }. +

+ Autre remarque : il est �galement possible de d�finir un alias par relation � + utiliser dans la requ�te SQL. + Ceci est utile pour l'�criture des conditions dans la clause WHERE. + Un alias SQL peut �tre d�fini entre les caract�res < >. +

+ Exemple : voici un exemple de fetch avec relations en d�finissant des alias SQL par + relation : +

+ + + + + + + +
+
list_blog lstBlogComplexRelation3;
+QStringList relations;
+relations << "<blog_alias> { blog_text }";
+relations << "author_id <author_alias> { name, birthdate }";
+relations << "list_comment <list_comment_alias> { comment_text } -> blog_id <blog_alias_2> -> * <..._my_alias_suffix>";
+QSqlError daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation3);
+qx::dump(lstBlogComplexRelation3);
+
+

+ Ce qui g�n�re la requ�te SQL suivante : +
+
+
SELECT blog_alias.blog_id AS blog_alias_blog_id_0, blog_alias.blog_text AS blog_alias_blog_text_0, blog_alias.author_id AS blog_alias_author_id_0, author_alias.author_id AS author_alias_author_id_0, author_alias.name AS author_alias_name_0, author_alias.birthdate AS author_alias_birthdate_0, list_comment_alias.comment_id AS list_comment_alias_comment_id_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0, list_comment_alias.comment_text AS list_comment_alias_comment_text_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0_2, blog_alias_2.blog_id AS blog_alias_2_blog_id_0, blog_alias_2.blog_text AS blog_alias_2_blog_text_0, blog_alias_2.date_creation AS blog_alias_2_date_creation_0, blog_alias_2.author_id AS blog_alias_2_author_id_0_3, author_my_alias_suffix.author_id AS author_my_alias_suffix_author_id_0, author_my_alias_suffix.name AS author_my_alias_suffix_name_0, author_my_alias_suffix.birthdate AS author_my_alias_suffix_birthdate_0, author_my_alias_suffix.sex AS author_my_alias_suffix_sex_0, comment_my_alias_suffix.comment_id AS comment_my_alias_suffix_comment_id_0, comment_my_alias_suffix.blog_id AS comment_my_alias_suffix_blog_id_0, comment_my_alias_suffix.comment_text AS comment_my_alias_suffix_comment_text_0, comment_my_alias_suffix.date_creation AS comment_my_alias_suffix_date_creation_0, comment_my_alias_suffix.blog_id AS comment_my_alias_suffix_blog_id_0_5, category_my_alias_suffix.category_id AS category_my_alias_suffix_category_id_0, category_my_alias_suffix.name AS category_my_alias_suffix_name_0, category_my_alias_suffix.description AS category_my_alias_suffix_description_0
+  FROM blog AS blog_alias
+  LEFT OUTER JOIN author author_alias ON author_alias.author_id = blog_alias.author_id
+  LEFT OUTER JOIN comment list_comment_alias ON list_comment_alias.blog_id = blog_alias.blog_id
+  LEFT OUTER JOIN blog blog_alias_2 ON blog_alias_2.blog_id = list_comment_alias.blog_id
+  LEFT OUTER JOIN author author_my_alias_suffix ON author_my_alias_suffix.author_id = blog_alias_2.author_id
+  LEFT OUTER JOIN comment comment_my_alias_suffix ON comment_my_alias_suffix.blog_id = blog_alias_2.blog_id
+  LEFT OUTER JOIN category_blog category_blog_6 ON blog_alias_2.blog_id = category_blog_6.blog_id
+  LEFT OUTER JOIN category category_my_alias_suffix ON category_blog_6.category_id = category_my_alias_suffix.category_id
+
+

+
+

Ajout SQL dans les + clauses LEFT OUTER JOIN / INNER JOIN

+
+ La classe qx::QxSqlQuery (ou son alias qx_query) dispose + de la m�thode suivante : +

+ + + + + + + +
+
QxSqlQuery & QxSqlQuery::addJoinQuery(const QString & relationKeyOrAlias, const QxSqlQuery & joinQuery);
+
+

+ La m�thode qx::QxSqlQuery::addJoinQuery() permet d'ins�rer des sous-requ�tes SQL dans + les clauses LEFT OUTER JOIN / INNER JOIN.
+ Par exemple : +

+ + + + + + + +
+
// Test to add join SQL sub-queries (inside LEFT OUTER JOIN or INNER JOIN)
+list_blog lstBlogWithJoinQueries;
+qx_query query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1");
+query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL");
+query.addJoinQuery("author_alias", qx_query().freeText("AND author_alias.sex = :sex", QVariantList() << author::female));
+daoError = qx::dao::fetch_by_query_with_relation(QStringList() << "<blog_alias> { blog_text }" << "author_id <author_alias> { name, birthdate, sex }" 
+                                                               << "list_comment <list_comment_alias> { comment_text }", query, lstBlogWithJoinQueries);
+qx::dump(lstBlogWithJoinQueries);
+qAssert(lstBlogWithJoinQueries.size() > 0);
+qAssert(lstBlogWithJoinQueries[0]->m_text == "update blog_text_1");
+qAssert(lstBlogWithJoinQueries[0]->m_author->m_sex == author::female);
+
+

+ Le code C++ ci-dessus va construire la requ�te SQL suivante : +

+
+
SELECT blog_alias.blog_id AS blog_alias_blog_id_0, blog_alias.blog_text AS blog_alias_blog_text_0, blog_alias.author_id AS blog_alias_author_id_0, author_alias.author_id AS author_alias_author_id_0, author_alias.name AS author_alias_name_0, author_alias.birthdate AS author_alias_birthdate_0, author_alias.sex AS author_alias_sex_0, list_comment_alias.comment_id AS list_comment_alias_comment_id_0, list_comment_alias.blog_id AS list_comment_alias_blog_id_0, list_comment_alias.comment_text AS list_comment_alias_comment_text_0
+  FROM blog AS blog_alias
+  LEFT OUTER JOIN author author_alias ON (author_alias.author_id = blog_alias.author_id
+      AND author_alias.sex = :sex)
+  LEFT OUTER JOIN comment list_comment_alias ON (list_comment_alias.blog_id = blog_alias.blog_id
+      AND list_comment_alias.comment_text IS NOT NULL)
+  WHERE blog_alias.blog_text = :blog_alias_blog_text_1_0
+
+

+
+
+

Collections support�es + par QxOrm

+
+ QxOrm supporte de nombreux conteneurs livr�s avec Qt, boost ou la biblioth�que standard std. + La biblioth�que QxOrm fournit �galement son propre conteneur, nomm� qx::QxCollection, particuli�rement adapt� pour stocker les donn�es + issues d'une base de donn�es. + Le d�veloppeur a donc � sa disposition un large choix : QxOrm n'impose aucune contrainte sur + l'utilisation des collections. +

+

Collections de Qt +

+
+ + + + + + + +
+
+  QList<T>  
+  QVector<T>  
+  QSet<T>  
+  QLinkedList<T>  
+  QHash<Key, Value>  
+  QMap<Key, Value>  
+  QMultiHash<Key, Value>  
+  QMultiMap<Key, Value>  
+
+
+
+
+

Collections de + boost

+
+ + + + + + + +
+
+  boost::unordered_map<Key, Value>  
+  boost::unordered_set<T>  
+  boost::unordered_multimap<Key, Value>  
+  boost::unordered_multiset<T>  
+
+
+
+
+

Collections fournies + par l'espace de nom standard std

+
+ + + + + + + +
+
+  std::list<T>  
+  std::vector<T>  
+  std::set<T>  
+  std::map<Key, Value>  
+
+  std::unordered_map<Key, Value>  
+  std::unordered_set<T>  
+  std::unordered_multimap<Key, Value>  
+  std::unordered_multiset<T>  
+
+
+
+
+

qx::QxCollection +

+
+ Il existe de nombreux container dans les biblioth�ques stl, boost et + Qt.
+ Il est donc l�gitime de se poser cette question : � quoi sert qx::QxCollection<Key, + Value> ?
+ qx::QxCollection<Key, Value> est un nouveau + container (bas� sur l'excellente biblioth�que boost::multi_index_container) qui poss�de les fonctionnalit�s + suivantes : +
    +
  • conserve l'ordre d'insertion des �l�ments dans la liste ; +
  • +
  • acc�s rapide � un �l�ment par son index : �quivaut � std::vector<T> ou + QList<T> par exemple ; +
  • +
  • acc�s rapide � un �l�ment par une cl� (hash-map) : �quivaut � QHash<Key, + Value> ou boost::unordered_map<Key, Value> par exemple ; +
  • +
  • fonctions de tri sur le type Key et sur le type Value ; +
  • +
  • thread-safe. +
  • +
+ Remarque : + qx::QxCollection<Key, Value> est compatible avec la macro foreach fournie + par la biblioth�que Qt ainsi que par la macro BOOST_FOREACH fournie par la biblioth�que boost.
+ Cependant, chaque �l�ment renvoy� par ces deux macros correspond � un objet de type + std::pair<Key, Value>.
+ Pour obtenir un r�sultat 'plus naturel' et plus lisible, il est conseill� d'utiliser la macro + _foreach : cette macro utilise BOOST_FOREACH pour tous les container + sauf pour qx::QxCollection<Key, Value>.
+ Dans ce cas, l'�l�ment renvoy� correspond au type Value (voir par la suite l'exemple + d'utilisation).
+ La macro _foreach est donc compatible avec tous les container (stl, + Qt, boost, etc.) puisqu'elle utilise la macro BOOST_FOREACH.

+ Autre Remarque : + qx::QxCollection<Key, Value> est particuli�rement adapt� pour recevoir des + donn�es issues d'une base de donn�es.
+ En effet, ces donn�es peuvent �tre tri�es (en utilisant ORDER BY dans une requ�te SQL + par exemple), il est donc important de conserver l'ordre d'insertion des �l�ments dans la + liste.
+ De plus, chaque donn�e issue d'une base de donn�es poss�de un identifiant unique. Il est donc + int�ressant de pouvoir acc�der � un �l�ment en fonction de cet identifiant unique de mani�re + extr�mement rapide (hash-map).

+ Exemple d'utilisation de la collection qx::QxCollection<Key, Value> :
+
+ + + + + + + +
+
/* d�finition d'une classe drug avec 3 propri�t�s : 'code', 'name', 'description' */
+class drug { public: QString code; QString name; QString desc; };
+
+/* pointeur intelligent associ� � la classe drug */
+typedef boost::shared_ptr<drug> drug_ptr;
+
+/* collection de drugs (acc�s rapide � un �l�ment de la collection par la propri�t� 'code') */
+qx::QxCollection<QString, drug_ptr> lstDrugs;
+
+/* cr�ation de 3 nouveaux drugs */
+drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1";
+drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2";
+drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3";
+
+/* insertion des 3 drugs dans la collection */
+lstDrugs.insert(d1->code, d1);
+lstDrugs.insert(d2->code, d2);
+lstDrugs.insert(d3->code, d3);
+
+/* parcours la collection en utilisant le mot-cl� '_foreach' */
+_foreach(drug_ptr p, lstDrugs)
+{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); }
+
+/* parcours la collection en utilisant une boucle 'for' */
+for (long l = 0; l < lstDrugs.count(); ++l)
+{
+   drug_ptr p = lstDrugs.getByIndex(l);
+   QString code = lstDrugs.getKeyByIndex(l);
+   qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc);
+}
+
+/* parcours la collection en utilisant le style Java avec 'QxCollectionIterator' */
+qx::QxCollectionIterator<QString, drug_ptr> itr(lstDrugs);
+while (itr.next())
+{
+   QString code = itr.key();
+   qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc);
+}
+
+/* effectue un tri croissant par cl� (propri�t� 'code') et d�croissant par valeur */
+lstDrugs.sortByKey(true);
+lstDrugs.sortByValue(false);
+
+/* acc�s rapide � un drug par son 'code' */
+drug_ptr p = lstDrugs.getByKey("code2");
+
+/* acc�s rapide � un drug par son index (position) dans la collection */
+drug_ptr p = lstDrugs.getByIndex(2);
+
+/* teste si un drug existe dans la collection et si la liste est vide */
+bool bExist = lstDrugs.exist("code3");
+bool bEmpty = lstDrugs.empty();
+
+/* supprime de la collection le 2�me �l�ment */
+lstDrugs.removeByIndex(2);
+
+/* supprime de la collection l'�l�ment avec le code 'code3' */
+lstDrugs.removeByKey("code3");
+
+/* efface tous les �l�ments de la collection */
+lstDrugs.clear();
+
+

+
+
+

Pointeurs intelligents + support�s par QxOrm (smart-pointers)

+
+ QxOrm supporte de nombreux pointeurs intelligents livr�s avec Qt, boost ou la biblioth�que standard std. + La biblioth�que QxOrm fournit �galement son propre pointeur intelligent, nomm� qx::dao::ptr, apportant de nouvelles fonctionnalit�s lorsqu'il est + utilis� avec les fonctions de l'espace de nom qx::dao. + Le d�veloppeur a donc � sa disposition un large choix : QxOrm n'impose aucune contrainte sur + l'utilisation des pointeurs intelligents. +

+

Pointeurs + intelligents de Qt

+
+ + + + + + + +
+
+  QSharedPointer<T>  
+  QScopedPointer<T>  
+  QWeakPointer<T>  
+  QSharedDataPointer<T>  
+
+
+
+
+

Pointeurs + intelligents de boost

+
+ + + + + + + +
+
+  boost::shared_ptr<T>  
+  boost::intrusive_ptr<T>  
+  boost::scoped_ptr<T>  
+  boost::weak_ptr<T>  
+
+
+
+
+

Pointeurs + intelligents fournis par l'espace de nom standard std

+
+ + + + + + + +
+
+  std::shared_ptr<T>  
+  std::unique_ptr<T>  
+  std::weak_ptr<T>  
+
+
+
+
+

qx::dao::ptr

+
+ QxOrm est compatible avec les pointeurs intelligents des biblioth�ques boost et + Qt.
+ Le pointeur intelligent d�velopp� par QxOrm est bas� sur QSharedPointer et + apporte de nouvelles fonctionnalit�s s'il est utilis� avec les fonctions + 'qx::dao::...'.
+ qx::dao::ptr<T> conserve automatiquement les valeurs + issues de la base de donn�es.
+ Il est ainsi possible de v�rifier � tout moment si une instance d'objet a subi des + modifications gr�ce � la m�thode 'isDirty()' : cette m�thode peut renvoyer la liste de + toutes les propri�t�s ayant �t� modifi�es.
+ qx::dao::ptr<T> peut �galement �tre utilis� par la fonction + 'qx::dao::update_optimized()' pour mettre � jour en base de donn�es uniquement les + champs modifi�s.
+ qx::dao::ptr<T> peut �tre utilis� avec un objet simple ou bien avec la plupart + des containers : stl, boost, Qt et qx::QxCollection<Key, + Value>.
+
+ Exemple d'utilisation du pointeur intelligent qx::dao::ptr<T> :
+
+ + + + + + + +
+
// exemple d'utilisation de la m�thode 'isDirty()'
+qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(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("|"))); }
+
+// met � jour uniquement la propri�t� 'm_text' de l'instance 'blog_isdirty'
+daoError = qx::dao::update_optimized(blog_isdirty);
+qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());
+qx::dump(blog_isdirty);
+
+// exemple d'utilisation de la m�thode 'isDirty()' avec une liste d'objets
+typedef qx::dao::ptr< QList<author_ptr> > type_lst_author_test_is_dirty;
+
+type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+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("|"))); }
+
+// met � jour la propri�t� 'm_name' en position 1, la propri�t� 'm_birthdate' en position 2 et ne change rien en position 0
+daoError = qx::dao::update_optimized(container_isdirty);
+qAssert(! daoError.isValid() && ! container_isdirty.isDirty());
+qx::dump(container_isdirty);
+
+// r�cup�re uniquement la propri�t� 'm_dt_creation' du 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);
+
+

+
+
+

D�clencheurs + (triggers)

+
+ Les Trigger de QxOrm permettent d'effectuer divers traitements avant et/ou apr�s + une insertion, une mise � jour ou bien une suppression dans la base de donn�es.
+ Un exemple d'utilisation se trouve dans le dossier ./test/qxDllSample/dll2/ avec la + classe BaseClassTrigger.
+ Cette classe contient cinq propri�t�s : m_id, m_dateCreation, + m_dateModification, m_userCreation et m_userModification.
+ Ces propri�t�s se mettront � jour automatiquement pour chaque classe h�ritant de + BaseClassTrigger (cf. les classes Foo et Bar du m�me projet).
+ Il est n�cessaire de sp�cialiser le template 'qx::dao::detail::QxDao_Trigger<T>' + pour profiter de cette fonctionnalit�.
+
+ + + + + + + +
+
#ifndef _QX_BASE_CLASS_TRIGGER_H_
+#define _QX_BASE_CLASS_TRIGGER_H_
+
+class QX_DLL2_EXPORT BaseClassTrigger
+{
+
+   QX_REGISTER_FRIEND_CLASS(BaseClassTrigger)
+
+protected:
+
+   long        m_id;
+   QDateTime   m_dateCreation;
+   QDateTime   m_dateModification;
+   QString     m_userCreation;
+   QString     m_userModification;
+
+public:
+
+   BaseClassTrigger() : m_id(0)  { ; }
+   virtual ~BaseClassTrigger()   { ; }
+
+   long getId() const                     { return m_id; }
+   QDateTime getDateCreation() const      { return m_dateCreation; }
+   QDateTime getDateModification() const  { return m_dateModification; }
+   QString getUserCreation() const        { return m_userCreation; }
+   QString getUserModification() const    { return m_userModification; }
+
+   void setId(long l)                              { m_id = l; }
+   void setDateCreation(const QDateTime & dt)      { m_dateCreation = dt; }
+   void setDateModification(const QDateTime & dt)  { m_dateModification = dt; }
+   void setUserCreation(const QString & s)         { m_userCreation = s; }
+   void setUserModification(const QString & s)     { m_userModification = s; }
+
+   void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
+   void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);
+
+};
+
+QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0)
+
+namespace qx {
+namespace dao {
+namespace detail {
+
+template <>
+struct QxDao_Trigger<BaseClassTrigger>
+{
+
+   static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeInsert(dao); } }
+   static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { if (t) { t->onBeforeUpdate(dao); } }
+   static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onBeforeFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+   static inline void onAfterFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
+   { Q_UNUSED(t); Q_UNUSED(dao); }
+
+};
+
+} // namespace detail
+} // namespace dao
+} // namespace qx
+
+#endif // _QX_BASE_CLASS_TRIGGER_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/BaseClassTrigger.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger)
+
+namespace qx {
+template <> void register_class(QxClass<BaseClassTrigger> & t)
+{
+   IxDataMember * pData = NULL;
+
+   pData = t.id(& BaseClassTrigger::m_id, "id");
+
+   pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation");
+   pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification");
+   pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation");
+   pData = t.data(& BaseClassTrigger::m_userModification, "user_modification");
+}}
+
+void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateCreation = QDateTime::currentDateTime();
+   m_dateModification = QDateTime::currentDateTime();
+   m_userCreation = "current_user_1";
+   m_userModification = "current_user_1";
+}
+
+void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
+{
+   Q_UNUSED(dao);
+   m_dateModification = QDateTime::currentDateTime();
+   m_userModification = "current_user_2";
+}
+
+
+

+
+

Validation d'une instance + C++ (validators)

+
+ Le module QxValidator de la biblioth�que QxOrm permet d'ajouter des + contraintes sur les propri�t�s enregistr�es dans le contexte QxOrm.
+ Ces contraintes sont d�finies dans la m�thode de mapping : void + qx::register_class<T>.
+ Si pour une instance de classe donn�e, au moins une contrainte n'est pas respect�e, alors + l'instance est consid�r�e comme invalide : l'objet ne peut alors pas �tre sauvegard� en base de + donn�es (INSERT ou UPDATE).
+
+ Il est �galement possible d'utiliser le module QxValidator pour valider les donn�es au + niveau de la couche pr�sentation de l'application : si les donn�es saisies par un utilisateur ne + sont pas valides, un message d'erreur peut �tre signal�, il n'est alors pas n�cessaire d'essayer + d'enregistrer l'instance courante en base de donn�es.
+ Les r�gles de validation n'ont pas besoin d'�tre dupliqu�es : elles peuvent �tre utilis�es aussi + bien par la couche pr�sentation que par la couche d'acc�s aux donn�es de l'application.
+
+ Voici la description de quelques classes du module QxValidator : +
    +
  • qx::IxValidator : chaque contrainte d�finie dans la fonction de + mapping void qx::register_class<T> est associ�e � une interface de type + qx::IxValidator ; +
  • +
  • qx::IxValidatorX : pour une classe donn�e, la liste des contraintes + est associ�e � une interface de type qx::IxValidatorX. Cette collection peut �tre + parcourue � l'ex�cution du programme : �a peut �tre int�ressant par exemple pour g�n�rer + le sch�ma DDL SQL et prendre en compte les contraintes au niveau de la base de donn�es + (voir le chapitre suivant du manuel utilisateur : G�n�rer le sch�ma + DDL SQL de la base de donn�es) ;
  • +
  • qx::QxInvalidValueX : au moment du processus de validation, + lorsqu'une instance n'est pas valide, la liste des contraintes non respect�es est + repr�sent�e par une collection de type qx::QxInvalidValueX ;
  • +
  • qx::QxInvalidValue : chaque �l�ment de cette collection est de type + qx::QxInvalidValue et contient un message d'erreur (description expliquant pourquoi + l'instance est invalide). +
  • +
+ Le module QxValidator g�re automatiquement la notion d'h�ritage de classe : si des + contraintes sont d�finies au niveau de la classe de base, alors elles seront automatiquement + v�rifi�es pour chaque validation d'une classe d�riv�e.
+
+ Voici un exemple d'utilisation du module QxValidator avec une classe 'person' + :
+
+ * fichier 'person.h' :
+ + + + + + + +
+
#ifndef _CLASS_PERSON_H_
+#define _CLASS_PERSON_H_
+ 
+class person
+{
+
+public:
+
+   enum sex { male, female, unknown };
+
+   long        _id;
+   QString     _firstName;
+   QString     _lastName;
+   QDateTime   _birthDate;
+   sex         _sex;
+
+   person() : _id(0), _sex(unknown) { ; }
+   person(long id) : _id(id), _sex(unknown) { ; }
+   virtual ~person() { ; }
+
+private:
+
+   void isValid(qx::QxInvalidValueX & invalidValues);
+
+};
+
+QX_REGISTER_HPP_MY_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _CLASS_PERSON_H_
+
+
+ * fichier 'person.cpp' :
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/person.h"
+#include "../include/global_validator.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_MY_EXE(person)
+
+namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+   t.id(& person::_id, "id");
+
+   t.data(& person::_firstName, "firstName");
+   t.data(& person::_lastName, "lastName");
+   t.data(& person::_birthDate, "birthDate");
+   t.data(& person::_sex, "sex");
+
+   QxValidatorX<person> * pAllValidator = t.getAllValidator();
+   pAllValidator->add_NotEmpty("firstName");
+   pAllValidator->add_NotEmpty("lastName", "a person must have a lastname");
+   pAllValidator->add_CustomValidator(& person::isValid);
+   pAllValidator->add_CustomValidator_QVariant(& validateFirstName, "firstName");
+   pAllValidator->add_CustomValidator_DataType<QDateTime>(& validateDateTime, "birthDate");
+}}
+
+void person::isValid(qx::QxInvalidValueX & invalidValues)
+{
+   // Cette m�thode est appel�e automatiquement par le module 'QxValidator' :
+   // - avant d'ins�rer ou mettre � jour une instance de type 'person' par les fonctions du namespace 'qx::dao' ;
+   // - en utilisant la fonction 'qx::validate()' avec pour param�tre une instance de type 'person'.
+
+   // L'enregistrement de la m�thode 'person::isValid()' est effectu� dans la fonction de mapping :
+   // pAllValidator->add_CustomValidator(& person::isValid);
+
+   // Dans cette m�thode, il est possible de v�rifier n'importe quelle valeur de l'instance courante
+   // Si une propri�t� est non valide, il suffit d'ins�rer un �l�ment dans la collection 'invalidValues'
+
+   // Remarque : cette m�thode est d�clar�e 'private' pour forcer l'utilisateur � utiliser la fonction 'qx::validate()'
+   // Mais ce n'est pas une obligation : cette m�thode peut �tre d�clar�e 'public' ou 'protected'
+
+   // Par exemple, si on souhaite v�rifier la propri�t� '_sex' d'une personne :
+   if ((_sex != male) && (_sex != female))
+   { invalidValues.insert("le sexe de la personne doit �tre d�fini : masculin ou f�minin"); }
+}
+
+
+ * fichier 'global_validator.h' :
+ + + + + + + +
+
// Les fonctions suivantes ('validateFirstName()' et 'validateDateTime()') sont globales (non li�es � une classe)
+// Elles peuvent ainsi �tre utilis�es par plusieurs classes pour valider une propri�t� (par exemple : valider la saisie d'une adresse IP).
+// Ces fonctions seront appel�es automatiquement par le module 'QxValidator' :
+// - avant d'ins�rer ou mettre � jour une instance de classe par les fonctions du namespace 'qx::dao' ;
+// - en utilisant la fonction 'qx::validate()'.
+ 
+void validateFirstName(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Ici, on peut tester la valeur d'une propri�t� (convertie en type QVariant)
+   // Si la valeur est invalide, il suffit d'ins�rer un message � la collection 'invalidValues'
+
+   // Par exemple, si la valeur ne doit jamais �tre �gale � "admin" :
+   if (value.toString() == "admin")
+   { invalidValues.insert("la valeur ne peut pas �tre �gale � 'admin'"); }
+}
+
+void validateDateTime(const QDateTime & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues)
+{
+   // Ici, on peut tester la valeur d'une propri�t� (en conservant son vrai type, ici il s'agit de tester une date-heure de type 'QDateTime')
+   // Si la valeur est invalide, il suffit d'ins�rer un message � la collection 'invalidValues'
+
+   // Par exemple, si la date-heure doit forc�ment �tre renseign�e :
+   if (! value.isValid())
+   { invalidValues.insert("la date-heure doit �tre renseign�e et doit �tre valide"); }
+}
+
+
+ * fichier 'main.cpp' :
+ + + + + + + +
+
person personValidate;
+personValidate._lastName = "admin";
+qx::QxInvalidValueX invalidValues = qx::validate(personValidate);
+QString sInvalidValues = invalidValues.text();
+qDebug("[QxOrm] test 'QxValidator' module :\n%s", qPrintable(sInvalidValues));
+
+
+ A l'ex�cution de ce bout de code, l'instance 'personValidate' est non valide : la + collection 'invalidValues' contient quatre �l�ments :
+ - "la valeur de la propri�t� 'firstName' ne peut pas �tre vide" ;
+ - "le sexe de la personne doit �tre d�fini : masculin ou f�minin" ;
+ - "la valeur ne peut pas �tre �gale � 'admin'" ;
+ - "la date-heure doit �tre renseign�e et doit �tre valide".
+
+ Le module QxValidator fournit plusieurs validateurs pour effectuer des v�rifications + basiques : +
    +
  • add_NotNull() : v�rifie que la valeur n'est pas nulle ;
  • +
  • add_NotEmpty() : v�rifie que la cha�ne de caract�res n'est pas vide ;
  • +
  • add_MinValue() : v�rifie que la valeur num�rique n'est pas inf�rieure au param�tre + ;
  • +
  • add_MaxValue() : v�rifie que la valeur num�rique n'est pas sup�rieure au param�tre + ;
  • +
  • add_Range() : v�rifie que la valeur num�rique est comprise entre les deux + param�tres ;
  • +
  • add_MinDecimal() : v�rifie que la valeur d�cimale n'est pas inf�rieure au + param�tre ;
  • +
  • add_MaxDecimal() : v�rifie que la valeur d�cimale n'est pas sup�rieure au + param�tre ;
  • +
  • add_RangeDecimal() : v�rifie que la valeur d�cimale est comprise entre les deux + param�tres ;
  • +
  • add_MinLength() : v�rifie que la cha�ne de caract�res a une taille minimale ;
  • +
  • add_MaxLength() : v�rifie que la cha�ne de caract�res ne d�passe pas un certain + nombre de caract�res ;
  • +
  • add_Size() : v�rifie que la taille de la cha�ne de caract�res est comprise entre + les deux param�tres ;
  • +
  • add_DatePast() : v�rifie que la date-heure est dans le pass� ;
  • +
  • add_DateFuture() : v�rifie que la date-heure est dans le futur ;
  • +
  • add_RegExp() : v�rifie que la cha�ne de caract�res est compatible avec + l'expression r�guli�re pass�e en param�tre ;
  • +
  • add_EMail() : v�rifie que la cha�ne de caract�res correspond � un e-mail.
  • +
+ Comme dans l'exemple de la classe 'person', il est possible de d�finir �galement des + validateurs personnalis�s : ce sont des fonctions ou m�thodes de classe qui seront appel�es + automatiquement par le module QxValidator pour valider une propri�t� ou une instance de + classe.
+ Il existe trois types de validateurs personnalis�s : +
    +
  • add_CustomValidator() : m�thode de classe, la signature de la m�thode doit �tre + "void my_class::my_method(qx::QxInvalidValueX &)" ;
  • +
  • add_CustomValidator_QVariant() : fonction globale avec type QVariant + (propri�t� convertie en QVariant), la signature de la fonction doit �tre "void + my_validator(const QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)" ; +
  • +
  • add_CustomValidator_DataType() : fonction globale avec le type r�el de la + propri�t�, la signature de la fonction doit �tre "void my_validator(const T &, const + qx::IxValidator *, qx::QxInvalidValueX &)" ;
  • +
+ Remarque : � chaque validateur peut �tre associ� un groupe (param�tre optionnel pour + chaque m�thode add_XXX() de la classe qx::IxValidatorX).
+ Il est ainsi possible de cr�er des groupes de validation suivant le contexte d'ex�cution : par + exemple, valider la saisie d'une personne sur une IHM A ne n�cessite peut-�tre pas les m�mes + v�rifications que valider une personne sur une IHM B.
+ Pour ex�cuter la validation d'une instance pour un groupe donn� (par exemple "myGroup"), + il faut appeler la fonction suivante : "qx::QxInvalidValueX invalidValues = + qx::validate(personValidate, "myGroup");".
+
+ Autre remarque : le module QxValidator d�finit des messages par d�faut lorsqu'une + contrainte n'est pas v�rifi�e.
+ Il est possible de red�finir ces messages par d�faut en modifiant la collection suivante : + "QHash * lstMessage = QxClassX::getAllValidatorMessage();".
+ Par exemple : "lstMessage->insert("min_value", "la valeur '%NAME%' doit �tre inf�rieure ou + �gale � '%CONSTRAINT%'");".
+ Les champs %NAME% et %CONSTRAINT% seront automatiquement remplac�s par les valeurs + correspondantes.
+ Pour modifier le message pour un validateur donn� (et non de mani�re globale), il faut utiliser + le param�tre optionnel disponible pour les m�thodes add_XXX() de la classe + qx::IxValidatorX.
+
+
+

G�rer la valeur NULL de + la base de donn�es

+
+ Les bases de donn�es poss�dent la notion de valeur NULL : pour plus de d�tails sur la valeur + NULL, rendez-vous sur la + page Wikipedia.
+ La biblioth�que QxOrm permet de g�rer la valeur NULL de plusieurs fa�ons diff�rentes : +
    +
  • utilisation de la classe boost::optional fournie par boost ; +
  • +
  • utilisation de la classe QVariant fournie par Qt ;
  • +
  • utilisation de pointeurs ou pointeurs intelligents : un pointeur NULL est associ� � la + valeur NULL en base de donn�es.
  • +
+
+

boost::optional +

+
+ La classe boost::optional<T> fournie par boost est particuli�rement + adapt�e pour g�rer la notion de valeur NULL en base de donn�es.
+ Pour utiliser boost::optional<T> avec la biblioth�que QxOrm, il est n�cessaire + de d�finir l'option de compilation _QX_ENABLE_BOOST, ou bien d'inclure + l'en-t�te <QxExtras/QxBoostOptionalOnly.h>.
+ Voici un exemple de classe dont toutes les propri�t�s (sauf la cl� primaire) peuvent �tre + NULL en utilisant boost::optional :
+
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   boost::optional<QString> firstName;
+   boost::optional<QString> lastName;
+   boost::optional<QDateTime> birthDate;  
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+#endif // _PERSON_H_
+
+
+ La classe boost::optional<T> se manipule facilement : rendez-vous sur la documentation fournie par boost pour plus de d�tails. +

+
+

QVariant

+
+ La classe QVariant fournie + par Qt permet �galement de g�rer la notion de valeur NULL en base de donn�es.
+ Voici un exemple de classe dont toutes les propri�t�s (sauf la cl� primaire) peuvent �tre + NULL en utilisant QVariant + :
+
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QVariant firstName;
+   QVariant lastName;
+   QVariant birthDate;  
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }  
+};
+
+#endif // _PERSON_H_
+
+
+ Cette solution a pour d�savantage de perdre le type de donn�e compar� � boost::optional<T>.
+ Il est donc recommand� d'utiliser boost::optional<T> pour g�rer la valeur NULL avec la + biblioth�que QxOrm. +

+
+
+

H�ritage et + polymorphisme

+
+ On retrouve g�n�ralement dans les diff�rents outils de type ORM trois diff�rentes + strat�gies pour g�rer la notion d'h�ritage avec la base de donn�es : +
    +
  • Single Table Inheritance (une seule table regroupant toutes + les propri�t�s d'une hi�rarchie d'h�ritage de classes) ; +
  • +
  • Class Table Inheritance (� chaque classe d'une hi�rarchie + d'h�ritage est associ�e une table dans la base de donn�es) ; +
  • +
  • Concrete Table Inheritance (une table par classe concr�te + dans la hi�rarchie d'h�ritage). +
  • +
+ QxOrm utilise par d�faut la strat�gie Concrete Table Inheritance (les autres + strat�gies ne sont pas fonctionnelles � l'heure actuelle).
+ De nombreux tutoriaux et forums sont disponibles sur internet pour plus de d�tails sur cette + notion d'h�ritage.
+ Un exemple d'utilisation avec une classe de base se trouve dans le dossier + ./test/qxDllSample/dll2/ avec la classe BaseClassTrigger. +

+
+

Interface + qx::IxPersistable (classe abstraite)

+
+ L'interface qx::IxPersistable (ou classe abstraite) dispose uniquement de + m�thodes virtuelles pures.
+ Elle permet d'avoir une classe de base commune pour appeler les fonctions de persistance sans + conna�tre le type r�el de l'instance courante (notion de polymorphisme).
+ La biblioth�que QxOrm n'impose pas de travailler avec une classe de base pour enregistrer un + type persistant dans le contexte QxOrm, cependant il est parfois utile de disposer d'une + interface afin d'�crire des algorithmes g�n�riques.
+
+ La classe qx::IxPersistable met � disposition les m�thodes virtuelles suivantes (pour + plus d'informations sur ces m�thodes, rendez-vous sur la documentation en ligne de la biblioth�que QxOrm) :
+
+
+
virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchAll(qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL);
+virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL);
+virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL);
+virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList());
+virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection() const;
+virtual qx::IxClass * qxClass() const;
+
+
+ Par exemple, � partir d'une liste de pointeurs de type qx::IxPersistable, il est possible + d'enregistrer les �l�ments dans plusieurs tables diff�rentes de la base de donn�es de la fa�on + suivante :
+
+ + + + + + + +
+
QList<qx::IxPersistable *> lst = ...;
+foreach(qx::IxPersistable * p, lst)
+{
+   QSqlError daoError = p->qxSave();
+   if (daoError.isValid()) { /* an error occured */ }
+   // etc...
+}
+
+
+ Pour impl�menter l'interface qx::IxPersistable, il faut : +
    +
  • faire h�riter la classe persistante du type qx::IxPersistable ;
  • +
  • dans la d�finition de la classe (myClass.h par exemple), ajouter la macro + QX_PERSISTABLE_HPP(myClass) ; +
  • +
  • dans l'impl�mentation de la classe (myClass.cpp par exemple), ajouter la macro + QX_PERSISTABLE_CPP(myClass). +
  • +
+ Par exemple, impl�menter l'interface qx::IxPersistable pour la classe author du tutoriel qxBlog revient � �crire + (les modifications par rapport au code du tutoriel apparaissent en gras) :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_AUTHOR_H_
+#define _QX_BLOG_AUTHOR_H_
+
+class blog;
+
+class QX_BLOG_DLL_EXPORT author : public qx::IxPersistable
+{
+   QX_PERSISTABLE_HPP(author)
+public:
+// -- typedef
+   typedef boost::shared_ptr<blog> blog_ptr;
+   typedef std::vector<blog_ptr> list_blog;
+// -- enum
+   enum enum_sex { male, female, unknown };
+// -- propri�t�s
+   QString     m_id;
+   QString     m_name;
+   QDate       m_birthdate;
+   enum_sex    m_sex;
+   list_blog   m_blogX;
+// -- constructeur, destructeur virtuel
+   author() : m_id(0), m_sex(unknown) { ; }
+   virtual ~author() { ; }
+// -- m�thodes
+   int age() const;
+};
+
+QX_REGISTER_PRIMARY_KEY(author, QString)
+QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
+
+typedef boost::shared_ptr<author> author_ptr;
+typedef qx::QxCollection<QString, author_ptr> list_author;
+
+#endif // _QX_BLOG_AUTHOR_H_
+
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/author.h"
+#include "../include/blog.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(author)
+QX_PERSISTABLE_CPP(author)
+
+namespace qx {
+template <> void register_class(QxClass<author> & t)
+{
+   t.id(& author::m_id, "author_id");
+
+   t.data(& author::m_name, "name");
+   t.data(& author::m_birthdate, "birthdate");
+   t.data(& author::m_sex, "sex");
+
+   t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
+
+   t.fct_0<int>(& author::age, "age");
+}}
+
+int author::age() const
+{
+   if (! m_birthdate.isValid()) { return -1; }
+   return (QDate::currentDate().year() - m_birthdate.year());
+}
+
+
+
+ Remarque : le projet de test ./test/qxDllSample/dll1/ met � disposition une sorte + de 'super classe de base' : la classe qx::QxPersistable impl�mente l'interface qx::IxPersistable et h�rite de QObject.
+ Le m�canisme SIGNAL-SLOT de Qt peut donc �tre utilis� avec cette classe, ce qui + peut �tre int�ressant par exemple pour la notion de d�clencheurs (ou trigger).
+ La classe qx::QxPersistable met �galement � disposition des m�thodes virtuelles qu'il est + possible de surcharger pour g�rer notamment la notion de validation des donn�es avec le module + QxValidator.
+ La classe qx::QxPersistable ne fait pas partie de la distribution de QxOrm, mais il est + possible de la copier-coller dans un projet afin de profiter de ses fonctionnalit�s : + +
+
+

Utiliser le pattern C++ + PIMPL (Private Implementation idiom ou d-pointer)

+
+ D�finition du site + cppreference : "Pointer to implementation" or "pImpl" is a C++ programming technique that + removes implementation details of a class from its object representation by placing them in a + separate class, accessed through an opaque pointer. + This technique is used to construct C++ library interfaces with stable ABI and to reduce + compile-time dependencies. +

+ Les + avantages � utiliser le pattern PIMPL pour d�finir une classe persistente enregistr�e + dans le contexte QxOrm : +
    +
  • Compilation Firewall : si l'impl�mentation priv�e change, le code client n'a pas + besoin d'�tre recompil� ;
  • +
  • R�duction des temps de compilation : les fichiers d'en-t�tes (*.h, *.hpp) sont + moins volumineux ;
  • +
  • Compatibilit� binaire : vous pouvez d�velopper plusieurs versions d'une + biblioth�que sans casser la compatibilit� ;
  • +
  • R�duction de la taille des ex�cutables g�n�r�s.
  • +
+ Les + inconvients du pattern PIMPL : +
    +
  • L�g�re baisse des performances : n�cessit� d'utiliser un niveau d'indirection + suppl�mentaire avec le pointeur opaque ;
  • +
  • N�cessit� d'allouer un pointeur par instance (peut causer des probl�mes de memory + fragmentation).
  • +
+
+ La biblioth�que QxOrm fournit un projet de test o� toutes les classes persistantes sont cod�es + en utilisant le pattern PIMPL : qxBlogPImpl (avec gestion des relations).
+ Il est �galement possible d'utiliser l'application + QxEntityEditor pour g�n�rer facilement et automatiquement toutes les + classes persistantes d'un projet C++ avec l'option PIMPL.
+
+ Exemple de classe persistante C++ enregistr�e dans le contexte QxOrm en utilisant le pattern + PIMPL (avec relations 1-n, n-1 et n-n) :
+
+ + + + + + + +
+
#ifndef _QX_BLOG_BLOG_H_
+#define _QX_BLOG_BLOG_H_
+
+class author;
+class comment;
+class category;
+
+class QX_BLOG_DLL_EXPORT blog
+{
+
+   QX_REGISTER_FRIEND_CLASS(blog)
+
+private:
+
+   struct blog_impl;
+   std::unique_ptr<blog_impl> m_pImpl; //!< Private implementation idiom
+
+public:
+
+   blog();
+   virtual ~blog();
+
+   blog(const blog & other);
+   blog & operator=(const blog & other);
+
+#ifdef Q_COMPILER_RVALUE_REFS
+   blog(blog && other) Q_DECL_NOEXCEPT;
+   blog & operator=(blog && other) Q_DECL_NOEXCEPT;
+#endif // Q_COMPILER_RVALUE_REFS
+
+   long id() const;
+   QString text() const;
+   QDateTime dateCreation() const;
+
+   void setId(long l);
+   void setText(const QString & s);
+   void setDateCreation(const QDateTime & d);
+
+   std::shared_ptr<author> & getAuthor();
+   QList< std::shared_ptr<comment> > & listOfComments();
+   qx::QxCollection<long, QSharedPointer<category> > & listOfCategories();
+
+};
+
+QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)
+
+typedef std::shared_ptr<blog> blog_ptr;
+typedef std::vector<blog_ptr> list_blog;
+
+#endif // _QX_BLOG_BLOG_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/blog.h"
+#include "../include/author.h"
+#include "../include/comment.h"
+#include "../include/category.h"
+
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(blog)
+
+struct Q_DECL_HIDDEN blog::blog_impl
+{
+   long           m_id;
+   QString        m_text;
+   QDateTime      m_dt_creation;
+   author_ptr     m_author;
+   list_comment   m_commentX;
+   list_category  m_categoryX;
+
+   blog_impl() : m_id(0) { ; }
+   ~blog_impl() { ; }
+};
+
+namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   IxDataMember * pImpl = t.pimpl(& blog::m_pImpl);
+
+   t.id(& blog::blog_impl::m_id, "blog_id", 0, pImpl);
+
+   t.data(& blog::blog_impl::m_text, "blog_text", 0, true, true, pImpl);
+   t.data(& blog::blog_impl::m_dt_creation, "date_creation", 0, true, true, pImpl);
+
+   t.relationManyToOne(& blog::blog_impl::m_author, "author_id", 0, pImpl);
+   t.relationOneToMany(& blog::blog_impl::m_commentX, "list_comment", "blog_id", 0, pImpl);
+   t.relationManyToMany(& blog::blog_impl::m_categoryX, "list_category", "category_blog", "blog_id", "category_id", 0, pImpl);
+}}
+
+blog::blog() : m_pImpl(new blog_impl()) { ; }
+
+blog::~blog() { ; }
+
+blog::blog(const blog & other) : m_pImpl(new blog_impl(* other.m_pImpl)) { ; }
+
+blog & blog::operator=(const blog & other)
+{
+   if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); }
+   return (* this);
+}
+
+#ifdef Q_COMPILER_RVALUE_REFS
+blog::blog(blog && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; }
+blog & blog::operator=(blog && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); }
+#endif // Q_COMPILER_RVALUE_REFS
+
+long blog::id() const { return m_pImpl->m_id; }
+
+QString blog::text() const { return m_pImpl->m_text; }
+
+QDateTime blog::dateCreation() const { return m_pImpl->m_dt_creation; }
+
+void blog::setId(long l) { m_pImpl->m_id = l; }
+
+void blog::setText(const QString & s) { m_pImpl->m_text = s; }
+
+void blog::setDateCreation(const QDateTime & d) { m_pImpl->m_dt_creation = d; }
+
+std::shared_ptr<author> & blog::getAuthor() { return m_pImpl->m_author; }
+
+QList< std::shared_ptr<comment> > & blog::listOfComments() { return m_pImpl->m_commentX; }
+
+qx::QxCollection<long, QSharedPointer<category> > & blog::listOfCategories() { return m_pImpl->m_categoryX; }
+
+

+
+

Persister des types + personnalis�s

+
+ La biblioth�que QxOrm permet de persister n'importe quel type, m�me si ce dernier n'est pas + enregistr� dans le contexte QxOrm par la m�thode qx::register_class<T>().
+
+ Il est n�cessaire d'�crire les fonctions de s�rialisation de la biblioth�que boost, en utilisant + la m�thode non intrusive (puisque le code source n'est pas disponible ou ne peut pas �tre + modifi�). + Pour plus d'informations sur la s�rialisation des donn�es avec la biblioth�que boost, + rendez-vous sur le tutoriel de developpez.com.
+
+ Par exemple, imaginons une classe 'ExtObject3D' provenant d'une biblioth�que tierce et + dont le code source n'est pas disponible ou ne peut pas �tre modifi�. + Voici le code n�cessaire pour pouvoir persister une instance de type 'ExtObject3D' en + base de donn�es :
+
+ + + + + + + +
+
#ifndef _PERSIST_EXTOBJECT3D_H_
+#define _PERSIST_EXTOBJECT3D_H_
+
+#include "ExtObject3D.h"
+
+#include <boost/serialization/serialization.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/nvp.hpp>
+ 
+namespace boost {
+namespace serialization {
+
+template <class Archive>
+void save(Archive & ar, const ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(t.getX()), y(t.getY()), z(t.getZ()), angle(t.getAngle());
+
+   ar << boost::serialization::make_nvp("x", x);
+   ar << boost::serialization::make_nvp("y", y);
+   ar << boost::serialization::make_nvp("z", z);
+   ar << boost::serialization::make_nvp("angle", angle);
+}
+
+template <class Archive>
+void load(Archive & ar, ExtObject3D & t, unsigned int version)
+{
+   Q_UNUSED(version);
+   double x(0.0), y(0.0), z(0.0), angle(0.0);
+
+   ar >> boost::serialization::make_nvp("x", x);
+   ar >> boost::serialization::make_nvp("y", y);
+   ar >> boost::serialization::make_nvp("z", z);
+   ar >> boost::serialization::make_nvp("angle", angle);
+
+   t.setX(x);
+   t.setY(y);
+   t.setZ(z);
+   t.setAngle(angle);
+}
+
+} // namespace serialization
+} // namespace boost
+ 
+BOOST_SERIALIZATION_SPLIT_FREE(ExtObject3D)
+
+#endif // _PERSIST_EXTOBJECT3D_H_
+
+
+ Le code ci-dessus est suffisant pour persister une instance de type 'ExtObject3D' en base + de donn�es : il est ainsi possible d'utiliser une propri�t� de type 'ExtObject3D' dans + une classe persistante enregistr�e dans le contexte QxOrm. + Cette propri�t� peut �tre mapp�e sur une colonne de type TEXT ou VARCHAR en base + de donn�es.
+
+ Le comportement par d�faut de la biblioth�que QxOrm est le suivant : l'instance est s�rialis�e + au format XML avant d'�tre ins�r�e ou mise � jour en base de donn�es. + Ce comportement par d�faut peut �tre utile par exemple si l'on souhaite enregistrer une + collection d'objets sans vouloir faire de relation (et donc g�rer une autre table dans la base + de donn�es). + Par exemple, si l'on utilise une propri�t� de type std::vector<mon_objet> dans une + classe persistante sans relation associ�e, la liste d'�l�ments sera automatiquement enregistr�e + au format XML en base de donn�es.
+
+ Remarque : ce comportement par d�faut peut �tre facilement modifi� pour un type donn�. + Le moteur QtSql utilise le type QVariant pour faire le lien entre le code C++ et + la base de donn�es. + Le type QVariant peut contenir du texte, des valeurs num�riques, du binaire, etc. + Il peut donc �tre int�ressant de sp�cialiser le comportement par d�faut (s�rialisation XML) si + l'on souhaite stocker des donn�es au format binaire ou bien optimiser les performances (la + s�rialisation XML peut �tre couteuse en temps d'ex�cution). + Il suffit de proposer (en plus des fonctions de s�rialisation boost) les conversions n�cessaires + en QVariant, par exemple avec la classe 'ExtObject3D' :
+
+ + + + + + + +
+
namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< ExtObject3D > {
+static inline QVariant toVariant(const ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{ /* Ici je convertis ExtObject3D en QVariant */ } };
+
+template <> struct QxConvert_FromVariant< ExtObject3D > {
+static inline qx_bool fromVariant(const QVariant & v, ExtObject3D & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{ /* Ici je convertis QVariant en ExtObject3D */; return qx_bool(true); } };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+

+ Remarque : Voici un template pour cr�er un type personnalis� persistable : +

+ + + + + + + +
+
#ifndef _MY_CUSTOM_PERSISTABLE_TYPE_H_
+#define _MY_CUSTOM_PERSISTABLE_TYPE_H_
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <QxOrm.h>
+
+class MyPersistableType
+{
+   /* What you want here */
+};
+
+QX_REGISTER_CLASS_NAME(MyPersistableType)
+QX_CLASS_VERSION(MyPersistableType, 0)
+
+QDataStream & operator<< (QDataStream & stream, const MyPersistableType & t)
+{
+   /* Your implementation here */
+}
+
+QDataStream & operator>> (QDataStream & stream, MyPersistableType & t)
+{
+   /* Your implementation here */
+}
+
+namespace qx {
+namespace cvt {
+namespace detail {
+
+template <> struct QxConvert_ToVariant< MyPersistableType > {
+static inline QVariant toVariant(const MyPersistableType & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{
+   /* Here I convert from MyPersistableType to QVariant */
+} };
+
+template <> struct QxConvert_FromVariant< MyPersistableType > {
+static inline qx_bool fromVariant(const QVariant & v, MyPersistableType & t, const QString & format, int index, qx::cvt::context::ctx_type ctx)
+{
+   /* Here I convert from QVariant to MyPersistableType */
+   return qx_bool(true);
+} };
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+#ifndef _QX_NO_JSON
+
+namespace qx {
+namespace cvt {
+namespace detail {
+
+template <>
+struct QxConvert_ToJson< MyPersistableType >
+{
+   static inline QJsonValue toJson(const MyPersistableType & t, const QString & format)
+   {
+      /* Your implementation here */
+   }
+};
+
+template <>
+struct QxConvert_FromJson< MyPersistableType >
+{
+   static inline qx_bool fromJson(const QJsonValue & j, MyPersistableType & t, const QString & format)
+   {
+      /* Your implementation here */
+   }
+};
+
+} // namespace detail
+} // namespace cvt
+} // namespace qx
+
+#endif // _QX_NO_JSON
+
+// ------------------------------------
+// If you are using boost serialization, you have also to implement save/load functions like above 'ExtObject3D' example
+// ------------------------------------
+
+#endif // _MY_CUSTOM_PERSISTABLE_TYPE_H_
+
+

+
+

G�n�rer le sch�ma DDL SQL + de la base de donn�es

+
+ + !!! Il est fortement recommand� d'utiliser + l'application QxEntityEditor pour g�rer cette probl�matique !!! +
+
+ La biblioth�que QxOrm ne fournit pas de m�canisme pour g�rer automatiquement la cr�ation et mise + � jour des tables dans la base de donn�es.
+ En effet, la fonction qx::dao::create_table<T> doit �tre utilis�e uniquement pour + cr�er des prototypes.
+ Il est fortement recommand� d'utiliser un outil sp�cifique � chaque SGBD pour cr�er et maintenir + les tables de la base de donn�es (par exemple Navicat pour MySql, pgAdmin + pour PostgreSQL, SQLite Manager pour SQLite, etc.).
+ De plus, un outil sp�cifique � chaque SGBD permet d'appliquer certaines optimisations (ajout + d'index par exemple).
+
+ Cependant, il peut �tre int�ressant pour certaines applications de ne pas avoir � g�rer + manuellement les tables de la base de donn�es.
+ Dans ce cas, il est possible de cr�er une fonction C++ pour parcourir la liste des classes + persistantes enregistr�es dans le contexte QxOrm (en utilisant le moteur d'introspection de la + biblioth�que) et ainsi cr�er un script SQL de g�n�ration et mise � jour des tables de la base de + donn�es.
+
+ La biblioth�que QxOrm fournit une fonction C++ cr��e uniquement � titre d'exemple : elle peut + donc servir de base de travail pour cr�er sa propre fonction de g�n�ration de script SQL.
+ Cette fonction se trouve dans le fichier ./src/QxRegister/QxClassX.cpp et se nomme QString + qx::QxClassX::dumpSqlSchema().
+ Elle g�n�re un script SQL et le renvoie sous forme de QString : il est possible d'adapter + cette fonction pour g�n�rer un fichier contenant le script SQL ou bien appliquer chaque + instruction SQL directement au SGBD.
+
+ Voici un exemple d'impl�mentation propos� par dodobibi pour + g�rer une base PostgreSQL : cet exemple g�re les �volutions futures de son application + (ajout de colonnes dans une table existante, ajout d'index sur une colonne existante, etc.).
+ Au lancement de l'application, le num�ro de version est indiqu� de la fa�on suivante :
+
+ + + + + + + +
+
QApplication app(argc, argv);
+app.setProperty("DomainVersion", 1); // Version increment�e � chaque compilation et diffusion de l'application
+
+
+ Une table de la base de donn�es permet de stocker le num�ro de version courant.
+ Une classe persistante C++ est mapp�e sur cette table de la fa�on suivante :
+
+ + + + + + + +
+
#ifndef _DATABASE_VERSION_H_
+#define _DATABASE_VERSION_H_
+ 
+class MY_DLL_EXPORT DatabaseVersion
+{
+public:
+  QString name;
+  long version;
+};
+
+QX_REGISTER_HPP_MY_APP(DatabaseVersion, qx::trait::no_base_class_defined, 0)
+
+#endif // _DATABASE_VERSION_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/DatabaseVersion.h"
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_MY_APP(DatabaseVersion)
+
+namespace qx {
+template <> void register_class(QxClass<DatabaseVersion> & t)
+{
+  t.id(& DatabaseVersion::name, "name");
+  t.data(& DatabaseVersion::version, "version");
+}}
+
+
+ Avec la classe DatabaseVersion, il est possible de v�rifier si la version de la base de + donn�es est � jour.
+ C'est le r�le de la fonction isDatabaseVersionOld() :
+
+ + + + + + + +
+
bool isDatabaseVersionOld()
+{
+  DatabaseVersion dbVersion;
+  dbVersion.name = "MyAppName";
+  QSqlError err = qx::dao::fetch_by_id(dbVersion);
+  if (err.isValid()) { qAssert(false); return false; }
+  return (dbVersion.version < qApp->property("DomainVersion").toInt());
+}
+
+
+ Si au lancement de l'application, la fonction isDatabaseVersionOld() renvoie true, + alors la mise � jour de la base de donn�es est effectu�e de la fa�on suivante :
+
+ + + + + + + +
+
void updateDatabaseVersion()
+{
+  try
+  {
+    int domainVersion = qApp->property("DomainVersion").toInt();
+
+    // On se connecte avec un utilisateur de la base de donn�es qui a les droits de modifications du sch�ma
+    QSqlDatabase db = qx::QxSqlDatabase::getSingleton()->getDatabaseCloned();
+    db.setUserName("MyAdminLogin");
+    db.setPassword("MyAdminPassword");
+
+    // On s'assure que la session d�marre une transaction et l�ve une exception � la moindre erreur
+    qx::QxSession session(db, true, true);
+
+    // On "fetch" la version de la base de donn�es avec un verrou pour �viter les modifications concurrentes !
+    // Si plusieurs utilisateurs lancent l'application en m�me temps et qu'une mise � jour
+    // est n�cessaire, le premier fera la mise � jour, et les autres seront en attente
+    DatabaseVersion dbVersion;
+    session.fetchByQuery(qx_query("WHERE name='MyAppName' FOR UPDATE"), dbVersion);
+
+    // Pour les autres utilisateurs, une fois le verrou lev�, on v�rifie si la mise � jour est toujours n�cessaire
+    if (dbVersion.version >= domainVersion) { return; }
+
+    // On ex�cute chaque instruction SQL avec la variable "query"
+    QSqlQuery query(db);
+
+    // On r�cup�re toutes les classes persistantes C++ enregistr�es dans le contexte QxOrm
+    qx::QxCollection<QString, qx::IxClass *> * pAllClasses = qx::QxClassX::getAllClasses();
+    if (! pAllClasses) { qAssert(false); return; }
+
+    // on r�cup�re la liste des tables existantes dans la base (fonction de Qt)
+    QStringList tables = db.tables();
+
+    for (long k = 0; k < pAllClasses->count(); k++)
+    {
+      qx::IxClass * pClass = pAllClasses->getByIndex(k);
+      if (! pClass) { continue; }
+
+      // Filtre les classes non persistantes
+      if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) { continue; }
+
+      // Filtre les classes � jour : si la version de pClass est <= � la version enregistr�e dans la base, la mise � jour n'est pas n�cessaire
+      if (pClass->getVersion() <= dbVersion.version) { continue; }
+
+      // On cr�e la table si elle n'existe pas, et on d�finit son propri�taire
+      if (! tables.contains(pClass->getName()))
+      {
+        query.exec("CREATE TABLE " + pClass->getName() + " ( ) WITH (OIDS = FALSE);"
+                   "ALTER TABLE " + pClass->getName() + " OWNER TO \"MyAdminLogin\";");
+        session += query.lastError();
+      }
+
+      // On ajoute les colonnes � la table si elles n'existent pas
+      qx::IxDataMemberX * pDataMemberX = pClass->getDataMemberX();
+      for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++)
+      {
+        qx::IxDataMember * p = pDataMemberX->get_WithDaoStrategy(l);
+        if (! p || (p->getVersion() <= dbVersion.version)) { continue; }
+
+        query.exec("ALTER TABLE " + pClass->getName() + " ADD COLUMN " + p->getName() + " " + p->getSqlType() + ";");
+        session += query.lastError();
+
+        if (p->getIsPrimaryKey()) // PRIMARY KEY
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ADD PRIMARY KEY (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getAllPropertyBagKeys().contains("INDEX")) // INDEX
+        {
+          query.exec("CREATE INDEX " + pClass->getName() + "_" + p->getName() + "_idx" + 
+                     " ON " + pClass->getName() + " USING " + p->getPropertyBag("INDEX").toString() + " (" + p->getName() + ");");
+          session += query.lastError();
+        }
+
+        if (p->getNotNull()) // NOT NULL
+        {
+          query.exec("ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " SET NOT NULL;");
+          session += query.lastError();
+        }
+
+        if (p->getAutoIncrement()) // AUTO INCREMENT
+        {
+          query.exec("CREATE SEQUENCE " + pClass->getName() + "_" + p->getName() + "_seq" + "; "
+                     "ALTER TABLE " + pClass->getName() + "_" + p->getName() + "_seq" + " OWNER TO \"MyAdminLogin\"; "
+                     "ALTER TABLE " + pClass->getName() + " ALTER COLUMN " + p->getName() + " " +
+                     "SET DEFAULT nextval('" + pClass->getName() + "_" + p->getName() + "_seq" + "'::regclass);");
+          session += query.lastError();
+        }
+
+        if (p->getDescription() != "") // DESCRIPTION
+        {
+          // $$ceci est un texte ne n�cessitant pas de caract�res d'�chappement dans postgres grace aux doubles dolars$$
+          query.exec("COMMENT ON COLUMN " + pClass->getName() + "." + p->getName() + " IS $$" + p->getDescription() + "$$ ;");
+          session += query.lastError();
+        }
+      }
+    }
+
+    // On enregistre la version courante de la base de donn�es
+    dbVersion.version = domainVersion;
+    session.save(dbVersion);
+
+    // Fin du block "try" : la session est d�truite => commit ou rollback automatique
+    // De plus, un commit ou rollback sur la transaction l�ve automatiquement le verrou pos� pr�c�demment
+  }
+  catch (const qx::dao::sql_error & err)
+  {
+    QSqlError sqlError = err.get();
+    qDebug() << sqlError.databaseText();
+    qDebug() << sqlError.driverText();
+    qDebug() << sqlError.number();
+    qDebug() << sqlError.type();
+  }
+}
+
+
+ Remarque : le code pr�c�dent (tout comme la fonction qx::QxClassX::dumpSqlSchema()) peut �tre modifi� pour s'adapter + aux besoins sp�cifiques d'une application.
+ Par exemple, il pourrait �tre int�ressant de cr�er par d�faut une seconde table (en plus de la + table DatabaseVersion) pour enregistrer la liste des classes persistantes enregistr�es + dans le contexte QxOrm : ainsi, au lieu d'utiliser la fonction propos�e par Qt + "db.tables()", il serait possible de r�cup�rer toutes les tables mapp�es sur des classes + persistantes avec des informations suppl�mentaires (num�ro de version pour chaque table, nombre + de colonnes enregistr�es dans le contexte QxOrm, description de chaque table, etc.). +

+
+

Associer un type SQL � + une classe C++

+
+ Chaque base de donn�es propose des types SQL diff�rents pour stocker l'information.
+ La biblioth�que QxOrm propose une association par d�faut pour les classes C++ les plus + fr�quemment utilis�es dans un programme.
+ Voici cette association par d�faut :
+
+ + + + + + + +
+
"bool" <-> "SMALLINT"
+"qx_bool" <-> "SMALLINT"
+"short" <-> "SMALLINT"
+"int" <-> "INTEGER"
+"long" <-> "INTEGER"
+"long long" <-> "INTEGER"
+"float" <-> "FLOAT"
+"double" <-> "FLOAT"
+"long double" <-> "FLOAT"
+"unsigned short" <-> "SMALLINT"
+"unsigned int" <-> "INTEGER"
+"unsigned long" <-> "INTEGER"
+"unsigned long long" <-> "INTEGER"
+"std::string" <-> "TEXT"
+"std::wstring" <-> "TEXT"
+"QString" <-> "TEXT"
+"QVariant" <-> "TEXT"
+"QUuid" <-> "TEXT"
+"QDate" <-> "DATE"
+"QTime" <-> "TIME"
+"QDateTime" <-> "TIMESTAMP"
+"QByteArray" <-> "BLOB"
+"qx::QxDateNeutral" <-> "TEXT"
+"qx::QxTimeNeutral" <-> "TEXT"
+"qx::QxDateTimeNeutral" <-> "TEXT"
+
+
+ Si le type SQL propos� par d�faut par la biblioth�que QxOrm ne correspond pas � la base de + donn�es utilis�e, il peut facilement �tre modifi� (de mani�re globale � toute l'application) en + utilisant la collection suivante :
+
+ + + + + + + +
+
QHash<QString, QString> * lstSqlType = qx::QxClassX::getAllSqlTypeByClassName();
+lstSqlType->insert("QString", "VARCHAR(255)");
+lstSqlType->insert("std::string", "VARCHAR(255)");
+// etc.
+
+
+ Pour modifier le type SQL de mani�re sp�cifique pour une colonne d'une table de la base de + donn�es, il faut d�finir le type SQL dans la fonction de mapping de QxOrm :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<MyClass> & t)
+{
+  //...
+  IxDataMember * p =  t.data(& MyClass::m_MyProperty, "my_property");
+  p->setSqlType("VARCHAR(255)");
+  //...
+}}
+
+
+ Pour les classes non support�es par d�faut par la biblioth�que QxOrm (voir ce chapitre du manuel + utilisateur : Persister des types personnalis�s), il est + possible d'associer un type SQL par d�faut en utilisant la macro suivante (en dehors de tout + namespace) :
+
+ + + + + + + +
+
QX_REGISTER_TRAIT_GET_SQL_TYPE(MyClass, "my_sql_type")
+
+

+
+

Effectuer des requ�tes + asynchrones � la base de donn�es

+
+ Il peut �tre parfois int�ressant d'ex�cuter certaines requ�tes � la base de donn�es de mani�re + asynchrone (multi-thread), par exemple pour �viter de bloquer une IHM si une requ�te est trop + longue � s'ex�cuter.
+ Pour simplifier les requ�tes asynchrones, la biblioth�que QxOrm fournit la classe qx::QxDaoAsync.
+ Cette classe ex�cute une requ�te dans un thread d�di� et renvoie un SIGNAL + queryFinished() lorsque la requ�te est termin�e.
+ Pour utiliser la classe qx::QxDaoAsync, il suffit de : +
    +
  • v�rifier que la requ�te fait appel � une classe qui impl�mente l'interface qx::IxPersistable ;
  • +
  • cr�er une instance de type qx::QxDaoAsync (par exemple, une propri�t� membre d'une + classe d�rivant du type QWidget) ;
  • +
  • connecter un SLOT au SIGNAL qx::QxDaoAsync::queryFinished() (par + exemple, un SLOT d�fini dans une classe d�rivant du type QWidget) ;
  • +
  • ex�cuter une requ�te � la base de donn�es en utilisant l'une des m�thodes commen�ant par + async : qx::QxDaoAsync::asyncXXXX(). +
  • +
+ Voici un exemple d'utilisation avec une classe nomm�e MyWidget :
+
+ + + + + + + +
+
class MyWidget : public QWidget
+{ Q_OBJECT
+
+   //...
+   qx::QxDaoAsync m_daoAsync;
+   //...
+Q_SLOTS:
+   void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams);
+   //...
+
+};
+
+
+ Et voici l'impl�mentation de la classe MyWidget :
+
+ + + + + + + +
+
MyWidget::MyWidget() : QObject()
+{
+   //...
+   QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), 
+                    this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)));
+   //...
+}
+
+void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams)
+{
+   if (! pDaoParams) { return; }
+   qx::QxSqlQuery query = pDaoParams->query;
+   if (! daoError.isValid()) { ; }
+   // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
+   qx::IxPersistable_ptr ptr = pDaoParams->pInstance;
+   // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
+   qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances;
+   //...
+}
+
+

+
+

Gestion du cache pour + sauvegarder des instances C++ (module QxCache)

+
+ Le cache propos� par la biblioth�que QxOrm (module QxCache) est thread-safe et permet de stocker + facilement n'importe quel type de donn�es.
+ Les fonctions pour acc�der au cache se trouvent dans le namespace + qx::cache.
+ Le cache permet une optimisation du programme : il est possible par exemple de stocker des + �l�ments issus d'une requ�te effectu�e en base de donn�es.
+
+ Chaque �l�ment stock� dans le cache est associ� � une cl� de type QString : cette cl� + permet de retrouver rapidement un �l�ment du cache.
+ Si un nouvel �l�ment est stock� dans le cache avec une cl� qui existe d�j�, alors l'ancien + �l�ment associ� � cette cl� est effac� automatiquement du cache.
+
+ Le cache de la biblioth�que QxOrm ne g�re pas la dur�e de vie des objets : il n'y a aucun + delete effectu� par le cache.
+ C'est pourquoi il est fortement recommand� (mais ce n'est pas une obligation) de privil�gier le + stockage de pointeurs intelligents : par exemple, boost::shared_ptr<T> pour la biblioth�que boost ou + bien QSharedPointer<T> pour la biblioth�que Qt.
+
+ Le cache peut avoir un co�t relatif maximum pour �viter une utilisation de la m�moire trop + importante : chaque �l�ment ins�r� dans le cache peut indiquer un co�t repr�sentant une + estimation de sa taille m�moire (par exemple, le nombre d'�l�ments d'une collection).
+ Lorsque le co�t maximum du cache est atteint, les premiers �l�ments ins�r�s dans le cache sont + supprim�s (en respectant l'ordre d'insertion dans le cache) jusqu'� ce que la limite du cache ne + soit plus d�pass�e.
+
+ Il est possible d'associer � chaque �l�ment du cache une date-heure d'insertion.
+ Si aucune date-heure n'est renseign�e, alors la date-heure courante est prise en compte.
+ Ce m�canisme permet de v�rifier si un �l�ment stock� dans le cache n�cessite une mise � jour ou + non.
+
+ Voici un exemple d'utilisation du cache de la biblioth�que QxOrm (fonctions du namespace + qx::cache) :
+
+ + + + + + + +
+
// D�fini le co�t maximum du cache � 500
+qx::cache::max_cost(500);
+
+// R�cup�re une liste de 'author' de la base de donn�es
+boost::shared_ptr< QList<author> > list_author;
+QSqlError daoError = qx::dao::fetch_all(list_author);
+
+// Ins�re la liste de 'author' dans le cache
+qx::cache::set("list_author", list_author);
+
+// R�cup�re une liste de 'blog' de la base de donn�es
+QSharedPointer< std::vector<blog> > list_blog;
+daoError = qx::dao::fetch_all(list_blog);
+
+// Ins�re la liste de 'blog' dans le cache (co�t = nombre de 'blog')
+qx::cache::set("list_blog", list_blog, list_blog.count());
+
+// Pointeur vers un objet de type 'comment'
+comment_ptr my_comment;
+my_comment.reset(new comment(50));
+daoError = qx::dao::fetch_by_id(my_comment);
+
+// Ins�re le 'comment' dans le cache en pr�cisant une date-heure d'insertion
+qx::cache::set("comment", my_comment, 1, my_comment->dateModif());
+
+// R�cup�re la liste de 'blog' stock�e dans le cache
+list_blog = qx::cache::get< QSharedPointer< std::vector<blog> > >("list_blog");
+
+// R�cup�re la liste de 'blog' sans pr�ciser le type
+qx_bool bGetOk = qx::cache::get("list_blog", list_blog);
+
+// Supprime du cache la liste de 'author'
+bool bRemoveOk = qx::cache::remove("list_author");
+
+// Compte le nombre d'�l�ments du cache
+long lCount = qx::cache::count();
+
+// R�cup�re le co�t actuel des �l�ments stock�s dans le cache
+long lCurrentCost = qx::cache::current_cost();
+
+// V�rifie qu'un �l�ment associ� � la cl� "comment" existe dans le cache
+bool bExist = qx::cache::exist("comment");
+
+// R�cup�re le 'comment' stock� dans le cache avec sa date-heure d'insertion
+QDateTime dt;
+bGetOk = qx::cache::get("comment", my_comment, dt);
+
+// Vide le cache
+qx::cache::clear();
+
+

+
+

Travailler avec plusieurs + bases de donn�es

+
+ Dans le chapitre Connexion � la base de donn�es, nous avons vu comment + param�trer la connexion par d�faut avec la classe singleton : qx::QxSqlDatabase. + La biblioth�que QxOrm �tant bas�e sur le moteur QtSql de Qt, elle + utilise en interne la classe QSqlDatabase de Qt. + Toutes les fonctions d'acc�s � la base de donn�es (namespace qx::dao, classe + qx::QxSession, etc...) + ont un param�tre optionnel : QSqlDatabase * pDatabase = NULL : +
    +
  • si la valeur de ce param�tre est � NULL (valeur par d�faut) : alors la biblioth�que QxOrm + utilise la classe singleton qx::QxSqlDatabase pour se connecter � la base de donn�es (avec + gestion automatique du multi-threading) ;
  • +
  • si la valeur est non nulle : alors la biblioth�que QxOrm utilise la connexion fournie par + le pointeur QSqlDatabase * pDatabase.
  • +
+ Ce param�tre permet donc de g�rer son propre pool de connexions � une ou plusieurs bases de + donn�es. +

+
+

D�clarer une classe + abstraite dans le contexte QxOrm

+
+ Une classe abstraite C++ (contenant au moins une m�thode virtuelle pure) ne peut pas �tre mapp�e + avec une table d'une base de donn�es (puisqu'elle ne peut pas �tre instanci�e).
+ Cependant, il peut �tre int�ressant de d�finir une classe abstraite contenant une liste de + propri�t�s utilis�es par plusieurs objets persistants.
+ Un exemple de classe abstraite se trouve dans le dossier ./test/qxDllSample/dll2/ de la + distribution de QxOrm avec la classe BaseClassTrigger.
+ QxOrm propose le m�canisme suivant pour d�finir une classe abstraite dans le contexte QxOrm : +
    +
  • d�clarer la classe avec la m�thode 'void register_class' comme n'importe qu'elle + autre classe ;
  • +
  • utiliser la macro QX_REGISTER_ABSTRACT_CLASS(className) juste apr�s la d�finition + de la classe.
  • +
+
+
+

D�clarer automatiquement + les m�ta-propri�t�s de Qt (macro Q_PROPERTY)

+
+ Toute classe h�ritant du type QObject peut d�clarer ses propri�t�s avec la macro Q_PROPERTY : + les propri�t�s deviennent alors des m�ta-propri�t�s. + Ce m�canisme permet au framework Qt de proposer un moteur d'introspection gr�ce au + pr�-compilateur moc. + Les m�ta-propri�t�s peuvent alors �tre utilis�es par exemple par le moteur QML, + QtScript, etc.
+
+ La biblioth�que QxOrm n�cessite une d�claration de chacune des propri�t�s d'une classe + dans la fonction de mapping void qx::register_class<T>() afin de proposer + l'ensemble de ses fonctionnalit�s (persistance des donn�es, s�rialisation XML, JSON et binaire, + etc.). + Il est possible de d�clarer automatiquement dans le contexte QxOrm l'ensemble des + m�ta-propri�t�s sans maintenir une fonction de mapping void qx::register_class<T>() + : la macro QX_REGISTER_ALL_QT_PROPERTIES() utilise le moteur d'introspection de Qt pour + parcourir la liste des m�ta-propri�t�s.
+
+ Voici un exemple d'utilisation avec la classe TestQtProperty se trouvant dans le dossier + ./test/qxDllSample/dll1/include/ de la distribution QxOrm :
+
+ + + + + + + +
+
#ifndef _QX_TEST_QT_META_PROPERTY_H_
+#define _QX_TEST_QT_META_PROPERTY_H_
+ 
+class QX_DLL1_EXPORT TestQtProperty : public QObject
+{
+
+   Q_OBJECT
+   Q_PROPERTY(int id READ id WRITE setId)
+   Q_PROPERTY(long number READ number WRITE setNumber)
+   Q_PROPERTY(QString desc READ desc WRITE setDesc)
+   Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate)
+   Q_PROPERTY(QVariant photo READ photo WRITE setPhoto)
+
+protected:
+
+   int         m_id;
+   long        m_number;
+   QString     m_desc;
+   QDateTime   m_birthDate;
+   QVariant    m_photo;
+
+public:
+
+   TestQtProperty() : QObject(), m_id(0), m_number(0) { ; }
+   virtual ~TestQtProperty() { ; }
+
+   int id() const                { return m_id; }
+   long number() const           { return m_number; }
+   QString desc() const          { return m_desc; }
+   QDateTime birthDate() const   { return m_birthDate; }
+   QVariant photo() const        { return m_photo; }
+
+   void setId(int i)                         { m_id = i; }
+   void setNumber(long l)                    { m_number = l; }
+   void setDesc(const QString & s)           { m_desc = s; }
+   void setBirthDate(const QDateTime & dt)   { m_birthDate = dt; }
+   void setPhoto(const QVariant & v)         { m_photo = v; }
+ 
+};
+
+QX_REGISTER_HPP_QX_DLL1(TestQtProperty, QObject, 0)
+
+#endif // _QX_TEST_QT_META_PROPERTY_H_
+
+
+ + + + + + + +
+
#include "../include/precompiled.h"
+
+#include "../include/TestQtProperty.h"
+
+#include <QxOrm_Impl.h>
+ 
+QX_REGISTER_CPP_QX_DLL1(TestQtProperty)
+QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id")
+
+
+ Pour ceux qui ne souhaitent pas utiliser la macro QX_REGISTER_ALL_QT_PROPERTIES, il est + possible d'�crire � la place les quatre lignes de code suivantes :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<TestQtProperty> & t)
+{ qx::register_all_qt_properties<TestQtProperty>(t, "id"); }
+} // namespace qx
+
+
+ Remarque : le deuxi�me param�tre de la macro QX_REGISTER_ALL_QT_PROPERTIES permet + d'indiquer la propri�t� qui servira de cl� primaire dans la base de donn�es. + Si ce param�tre est vide, cela signifie que la classe ne poss�de pas de cl� primaire ou bien que + celle-ci est d�finie dans une classe de base.
+
+ Toute propri�t� d�finie avec la macro Q_PROPERTY peut s'enregistrer dans le contexte + QxOrm de deux mani�res diff�rentes :
+ 1- par la m�thode classique : t.data(& MyQObject::my_property, "my_property", + 0);
+ 2- ou bien sans mentionner le pointeur vers la donn�e membre de la classe : + t.data("my_property", 0);
+
+ Peu importe la m�thode d'enregistrement des propri�t�s dans le contexte QxOrm, elles seront + accessibles par la m�me interface qx::IxDataMember et proposent donc les m�mes fonctionnalit�s. + Il est possible d'utiliser les deux m�thodes dans une m�me fonction de mapping void + qx::register_class<T>(). + Chaque m�thode d'enregistrement pr�sente des avantages et inconv�nients.
+
+ Voici la liste des avantages de la deuxi�me m�thode d'enregistrement des propri�t�s dans le + contexte QxOrm : +
    +
  • temps de compilation du projet beaucoup plus rapide ;
  • +
  • taille de l'ex�cutable g�n�r� plus petite ;
  • +
  • forte int�gration avec le moteur d'introspection du framework Qt ;
  • +
  • pas besoin de maintenir la fonction de mapping en utilisant la macro + QX_REGISTER_ALL_QT_PROPERTIES. +
  • +
+ Voici les inconv�nients par rapport � la m�thode classique d'enregistrement des propri�t�s : +
    +
  • n�cessite un h�ritage de la classe QObject pour pouvoir utiliser la macro + Q_PROPERTY ; +
  • +
  • ex�cution du programme plus lente (utilisation du type QVariant � la place des + template C++) ; +
  • +
  • ne supporte pas la notion de relation entre tables de la base de donn�es + (one-to-one, one-to-many, many-to-one et many-to-many) ;
  • +
  • pas d'acc�s au pointeur sur la donn�e membre de la classe (conversion n�cessaire au type + QVariant pour acc�der et modifier une valeur). +
  • +
+
+
+ +

S�rialisation

+
+ La s�rialisation est un m�canisme permettant de sauvegarder l'�tat d'une instance d'objet + dans un flux (fichier, r�seau, etc...) sous un certain format (binaire, XML, JSON, texte, etc...). + La d�s�rialisation est le processus inverse permettant de restaurer l'�tat d'un objet � + partir d'un flux. + Pour plus d'informations sur la notion de s�rialisation : rendez-vous sur la page + Wikipedia. +

+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre s�rialis�e dans diff�rents formats : + + Remarque : le moteur de s�rialisation de la biblioth�que QxOrm permet de proposer des + fonctionnalit�s suppl�mentaires comme le clonage d'entit�s, le dump d'entit�s (format XML ou JSON) ou encore le + module QxService. +

+ Autre remarque : par d�faut, toutes les propri�t�s enregistr�es dans le contexte QxOrm sont + s�rialisables. Pour supprimer une propri�t� du moteur de s�rialisation, il est possible d'�crire + :
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  IxDataMember * pDataMember = t.data(& person::age, "age");
+  pDataMember->setSerialize(false);
+}}
+
+

+

N� version pour assurer + une compatibilit� ascendante

+
+ La compatibilit� ascendante permet � une application de pouvoir d�s�rialiser un flux provenant + d'une version ant�rieure. + La biblioth�que QxOrm impose un num�ro de version par classe ainsi qu'un num�ro de version pour + chaque propri�t� enregistr�e dans le contexte QxOrm afin de pouvoir assurer une compatibilit� + ascendante automatiquement. +

+ Par exemple, imaginons une classe person cr��e dans une application en version A : + nous renseignons dans la macro QX_REGISTER_HPP une n� de version � 0 (correspond � la + 1�re version de notre classe person), ainsi qu'un n� de version � 0 pour chacune des + propri�t�s de la classe (si param�tre non renseign�, 0 est la valeur par d�faut). + Ce qui donne le r�sultat suivant : +

+ * Fichier person.h :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _PERSON_H_
+
+
+ * Fichier person.cpp :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name", 0);
+  t.data(& person::lastName, "last_name", 0);
+  t.data(& person::birthDate, "birth_date", 0);
+}}
+
+

+ Dans la version B de notre application, nous modifions la classe person pour + ajouter 2 nouvelles propri�t�s : sex et address. Notre classe ayant �volu�e, il + faut donc incr�menter son n� de version, et les nouvelles propri�t�s doivent avoir un n� de + version � 1, ce qui donne : +

+ * Fichier person.h :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+   QString sex;
+   QString address;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 1)
+
+#endif // _PERSON_H_
+
+
+ * Fichier person.cpp :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name", 0);
+  t.data(& person::lastName, "last_name", 0);
+  t.data(& person::birthDate, "birth_date", 0);
+  t.data(& person::sex, "sex", 1);
+  t.data(& person::address, "address", 1);
+}}
+
+

+ Remarque : en proc�dant ainsi, la biblioth�que QxOrm peut s�rialiser une instance de la + classe person dans une application en version A, puis d�s�rialiser � partir de ce flux + issu de la version A afin de recr�er une instance de la classe person dans une version B + de l'application. +

+ Autre remarque : la suppression d'une propri�t� casse la compatibilit� ascendante. + Il est donc recommand� de ne jamais supprimer de propri�t� pour utiliser le moteur de + s�rialisation : il est possible par exemple de mettre une visibilit� � private et de + supprimer les accesseurs get/set, la propri�t� devenant ainsi inaccessible � l'ext�rieur + de la classe, elle peut alors �tre consid�r�e comme �tant obsol�te. +

+
+

Moteur QDataStream de + Qt

+
+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre s�rialis�e en utilisant le moteur QDataStream de + Qt. + Les fonctions pour utiliser ce type de s�rialisation sont disponibles dans l'espace de nom : namespace + qx::serialization::qt. + + Remarque : la s�rialisation QDataStream est portable (s�rialisation/d�s�rialisation compatible sur + tous types d'environnement : Windows, Linux, Mac OS X, etc...). + Le flux s�rialis� est au format binaire : la taille du flux est donc r�duite (compar� � un flux + XML par exemple). + La s�rialisation QDataStream �tant bas�e sur le moteur d'introspection de la biblioth�que + QxOrm, elle est moins performante que les s�rialisations bas�es sur le moteur boost::serialization. +

+ Par exemple :
+ + + + + + + +
+
   // Fetch a drug with id '3' in a new variable
+   // drug is a C++ class registered in QxOrm context
+   drug d;
+   d.id = 3;
+   QSqlError daoError = qx::dao::fetch_by_id(d);
+
+   // Serialize the drug to a file
+   qx::serialization::qt::to_file(d, "export_drug.txt");
+
+   // Import drug from file in a new instance
+   drug d2;
+   qx::serialization::qt::from_file(d2, "export_drug.txt");
+
+   // Check if d == d2
+   qAssert(d == d2);
+
+
+ Remarque : dans l'exemple ci-dessus, nous s�rialisons une instance C++. + Toutes les fonctions du namespace qx::serialization peuvent �galement s�rialiser des listes d'instances + C++. + Pour connaitre la liste des collections support�es, rendez-vous dans le chapitre : Collections support�es par QxOrm. +

+
+

Moteur JSON de Qt

+
+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre s�rialis�e en utilisant le moteur QJson de Qt (n�cessite + Qt5). + Les fonctions pour utiliser ce type de s�rialisation sont disponibles dans l'espace de nom : namespace + qx::serialization::json. + + Remarque : le moteur de s�rialisation JSON est le plus permissif (compar� au moteur + XML par exemple) : en effet, les propri�t�s d'une instance peuvent �tre d�finies dans + n'importe quel ordre, les propri�t�s peuvent �tre supprim�es ou ajout�es. + La d�s�rialisation JSON ne retourne jamais d'erreur : elle ignore tout si le format des donn�es + est incorrect (le flux JSON doit par contre �tre valide) ou bien si des propri�t�s sont absentes + : le moteur JSON est donc beaucoup plus flexible que le moteur XML. +

+ Autre remarque : la s�rialisation JSON est bas�e sur le moteur d'introspection de la biblioth�que QxOrm, + elle est moins performante que les s�rialisations bas�es sur le moteur boost::serialization. +

+ Par exemple :
+ + + + + + + +
+
   // Fetch a list of authors from database and serialize them to a JSON file
+   list_author list_of_author;
+   qx::dao::fetch_all(list_of_author);
+   qx::serialization::json::to_file(list_of_author, "list_of_author.json");
+
+
+ L'exemple ci-dessus g�n�re le flux JSON suivant :
+
+
{
+    "author_id_2": {
+        "author_id": "author_id_2",
+        "birthdate": "2016-03-24",
+        "list_blog": [
+        ],
+        "name": "author_2",
+        "sex": 1
+    },
+    "author_id_3": {
+        "author_id": "author_id_3",
+        "birthdate": "2016-03-24",
+        "list_blog": [
+        ],
+        "name": "author_3",
+        "sex": 1
+    }
+}
+
+

+ Remarque : le module QxRestApi de la biblioth�que QxOrm est bas� + sur le moteur de s�rialisation JSON. +

+ Autre remarque : il est possible de personnaliser le format de sortie JSON (filtrer les + propri�t�s du flux JSON g�n�r� par la s�rialisation). + Les fonctions de s�rialisation JSON dispose d'un param�tre optionnel de type QString + nomm� format. + Les pr�-requis pour utiliser le param�tre format sont : +
    +
  • le param�tre format doit �tre pr�fix� par : filter: ;
  • +
  • les propri�t�s � exporter sont d�finies entre { } ;
  • +
  • les relations sont s�par�es par le caract�re | ;
  • +
  • il est possible d'utiliser le caract�re * pour d�finir : toutes les + relations sur 1 niveau ;
  • +
  • le caract�re - devant les { } signifie : toutes les + propri�t�s sauf.
  • +
+
+ Exemple : voici un exemple de s�rialisation JSON en d�finissant un format de sortie pour + filtrer certaines propri�t�s : +

+ + + + + + + +
+
// Serialize a C++ instance to a JSON string
+QString jsonFormat = "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *";
+QString outputJsonFiltered = qx::serialization::json::to_string(blog, 1, jsonFormat);
+qDebug("[QxOrm] custom JSON serialization process (filtered) : \n%s", qPrintable(outputJsonFiltered));
+
+// Fill a C++ instance based on a JSON string
+blog_ptr blogFromJsonFiltered; blogFromJsonFiltered.reset(new blog());
+qx::serialization::json::from_string(blogFromJsonFiltered, outputJsonFiltered, 1, jsonFormat);
+qx::dump(blogFromJsonFiltered);
+qAssert(blogFromJsonFiltered->m_text != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_dt_creation.isNull()); // Not fetched
+qAssert(blogFromJsonFiltered->m_author->m_sex == author::unknown); // Not fetched
+qAssert(blogFromJsonFiltered->m_author->m_name != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_commentX.size() > 0);
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_dt_create.isNull()); // Not fetched
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_text != ""); // Fetched
+qAssert(blogFromJsonFiltered->m_commentX[0]->m_blog);
+
+

+
+

Moteur XML de + boost::serialization

+
+ Le moteur XML de boost::serialization n'est pas activ� par d�faut : pour activer cette + fonctionnalit�, il est n�cessaire de d�finir les options de compilation + _QX_ENABLE_BOOST_SERIALIZATION et _QX_ENABLE_BOOST_SERIALIZATION_XML dans le fichier de configuration QxOrm.pri (ou QxOrm.cmake). + Il est �galement n�cessaire de compiler le binaire boost::serialization (ce module de boost n'�tant pas header only), + et de renseigner le chemin d'acc�s � ce binaire dans les variables QX_BOOST_LIB_PATH, + QX_BOOST_LIB_SERIALIZATION_DEBUG et QX_BOOST_LIB_SERIALIZATION_RELEASE du fichier de configuration QxOrm.pri (ou QxOrm.cmake). +

+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre s�rialis�e en utilisant le moteur XML de boost::serialization. + Les fonctions pour utiliser ce type de s�rialisation sont disponibles dans l'espace de nom : namespace + qx::serialization::xml (m�mes fonctions que dans l'espace de nom + qx::serialization::qt). +

+ Ce type de s�rialisation poss�de les caract�ristiques suivantes : +
    +
  • portable : compatible sur tous types d'environnement : Windows, Linux, Mac OS X, + etc... ;
  • +
  • slowest : plus lente que les s�rialisations binary et text ;
  • +
  • largest : taille des flux g�n�r�s plus importante que les s�rialisations + binary et text ; +
  • +
  • human-readable : un flux XML peut facilement �tre analys� et lu par un �diteur + externe ou un �tre humain.
  • +
+
+
+

Moteur binaire de + boost::serialization

+
+ Le moteur binaire de boost::serialization n'est pas activ� par d�faut : pour activer cette + fonctionnalit�, il est n�cessaire de d�finir les options de compilation + _QX_ENABLE_BOOST_SERIALIZATION et _QX_ENABLE_BOOST_SERIALIZATION_BINARY dans le fichier de configuration QxOrm.pri (ou QxOrm.cmake). + Il est �galement n�cessaire de compiler le binaire boost::serialization (ce module de boost n'�tant pas header only), + et de renseigner le chemin d'acc�s � ce binaire dans les variables QX_BOOST_LIB_PATH, + QX_BOOST_LIB_SERIALIZATION_DEBUG et QX_BOOST_LIB_SERIALIZATION_RELEASE du fichier de configuration QxOrm.pri (ou QxOrm.cmake). +

+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre s�rialis�e en utilisant le moteur binaire de boost::serialization. + Les fonctions pour utiliser ce type de s�rialisation sont disponibles dans l'espace de nom : namespace + qx::serialization::binary (m�mes fonctions que dans l'espace de nom + qx::serialization::qt). +

+ Ce type de s�rialisation poss�de les caract�ristiques suivantes : +
    +
  • non-portable : un flux s�rialis� sur un environnement Windows peut �tre + incompatible si d�s�rialisation sur un environnement Linux par exemple : il est donc + fortement recommand� de rester sur le m�me environnement ;
  • +
  • fastest : plus rapide que les s�rialisations XML et text ;
  • +
  • smallest : taille des flux g�n�r�s r�duite compar� aux s�rialisations XML + et text ;
  • +
  • non-human-readable : un flux binaire n'est pas lisible (pas de log possible par + exemple).
  • +
+
+
+

Autres types de + s�rialisation propos�s par boost

+
+ Le moteur boost::serialization propose d'autres types de s�rialisation. + Ces diff�rents types ne sont pas activ�s par d�faut, pour utiliser ces fonctionnalit�s (m�mes + fonctions que dans l'espace de nom qx::serialization::qt), il est + n�cessaire de d�finir les options de compilation suivantes dans le fichier + de configuration QxOrm.pri (ou QxOrm.cmake) : + +
+
+

Cloner une instance + C++

+
+ Toute classe C++ enregistr�e dans le contexte QxOrm peut �tre clon�e en utilisant une des + fonctions suivantes : + + Par exemple : +

+ + + + + + + +
+
   drug_ptr d1;
+   d1.reset(new drug());
+   d1->name = "name1";
+   d1->description = "desc1";
+
+   // Clone a drug
+   drug_ptr d_clone = qx::clone(* d1);
+
+   // Check if (d1 == d_clone)
+   qAssert((* d1) == (* d_clone));
+
+
+ Remarque importante : il faut faire attention lorsqu'on clone un pointeur intelligent + (boost::shared_ptr ou QSharedPointer par exemple) dont l'�l�ment parent + (root) peut �tre r�f�renc� plusieurs fois dans sa hi�rarchie (cas d'une structure en + arbre par exemple). + Dans ce cas, afin de prot�ger le pointeur parent d'une double suppression (2 pointeurs + intelligents qui pointent sur le m�me pointeur brut), il est conseill� de cloner de cette fa�on + : +

+ + + + + + + +
+
// 'pOther' type is boost::shared_ptr<myClass> (smart-pointer)
+boost::shared_ptr<myClass> * pCloneTemp = qx::clone_to_nude_ptr(pOther);
+boost::shared_ptr<myClass> pClone = (pCloneTemp ? (* pCloneTemp) : boost::shared_ptr<myClass>());
+if (pCloneTemp) { delete pCloneTemp; pCloneTemp = NULL; }
+// Now use 'pClone' ...
+
+

+
+

Afficher le d�tail d'une + instance C++ (dump au format XML ou JSON)

+
+ Toute instance C++ enregistr�e dans le contexte QxOrm peut �tre affich�e au format JSON. + Si le moteur XML de boost::serialization est activ�, alors il est + �galement possible d'afficher un dump sous format XML (param�tre d'entr�e de la fonction + qx::dump). + Cette fonctionnalit� peut �tre utile pour faire du d�bogage par exemple, ou bien pour g�n�rer + des logs. +

+ + + + + + + +
+
   blog_ptr b;
+   b.reset(new blog());
+   b->id = 36;
+   qx::dao::fetch_by_id_with_all_relation(b);
+
+   // Dump 'b' instance result from database (XML or JSON serialization)
+   // Second parameter is optional : 'true' = JSON format, 'false' = XML format
+   qx::dump(b, false);
+
+
+ Ce qui g�n�re le flux XML suivant : +

+
+
+[QxOrm] start dump 'boost::shared_ptr<blog>'
+<boost.shared_ptr-blog- class_id="0" tracking_level="0" version="1">
+	<px class_id="1" tracking_level="1" version="0" object_id="_0">
+		<blog_id>113</blog_id>
+		<blog_text class_id="2" tracking_level="0" version="0">update blog_text_1</blog_text>
+		<date_creation class_id="3" tracking_level="0" version="0">20100409162612000</date_creation>
+		<author_id class_id="4" tracking_level="0" version="1">
+			<px class_id="5" tracking_level="1" version="0" object_id="_1">
+				<author_id>author_id_2</author_id>
+				<name>author_2</name>
+				<birthdate class_id="6" tracking_level="0" version="0">20100409</birthdate>
+				<sex>1</sex>
+				<list_blog class_id="7" tracking_level="0" version="0">
+					<count>0</count>
+					<item_version>1</item_version>
+				</list_blog>
+			</px>
+		</author_id>
+		<list_comment class_id="8" tracking_level="0" version="0">
+			<count>2</count>
+			<item class_id="9" tracking_level="0" version="1">
+				<px class_id="10" tracking_level="1" version="0" object_id="_2">
+					<comment_id>209</comment_id>
+					<comment_text>comment_1 text</comment_text>
+					<date_creation>20100409162612000</date_creation>
+					<blog_id>
+						<px class_id_reference="1" object_id="_3">
+							<blog_id>113</blog_id>
+							<blog_text></blog_text>
+							<date_creation></date_creation>
+							<author_id>
+								<px class_id="-1"></px>
+							</author_id>
+							<list_comment>
+								<count>0</count>
+							</list_comment>
+							<list_category class_id="11" tracking_level="0" version="0">
+								<count>0</count>
+							</list_category>
+						</px>
+					</blog_id>
+				</px>
+			</item>
+			<item>
+				<px class_id_reference="10" object_id="_4">
+					<comment_id>210</comment_id>
+					<comment_text>comment_2 text</comment_text>
+					<date_creation>20100409162612000</date_creation>
+					<blog_id>
+						<px class_id_reference="1" object_id="_5">
+							<blog_id>113</blog_id>
+							<blog_text></blog_text>
+							<date_creation></date_creation>
+							<author_id>
+								<px class_id="-1"></px>
+							</author_id>
+							<list_comment>
+								<count>0</count>
+							</list_comment>
+							<list_category>
+								<count>0</count>
+							</list_category>
+						</px>
+					</blog_id>
+				</px>
+			</item>
+		</list_comment>
+		<list_category>
+			<count>2</count>
+			<item class_id="12" tracking_level="0" version="0">
+				<first>355</first>
+				<second class_id="13" tracking_level="0" version="0">
+					<qt_shared_ptr class_id="14" tracking_level="1" version="0" object_id="_6">
+						<category_id>355</category_id>
+						<name>category_1</name>
+						<description>desc_1</description>
+						<list_blog class_id="15" tracking_level="0" version="0">
+							<count>0</count>
+						</list_blog>
+					</qt_shared_ptr>
+				</second>
+			</item>
+			<item>
+				<first>357</first>
+				<second>
+					<qt_shared_ptr class_id_reference="14" object_id="_7">
+						<category_id>357</category_id>
+						<name>category_3</name>
+						<description>desc_3</description>
+						<list_blog>
+							<count>0</count>
+						</list_blog>
+					</qt_shared_ptr>
+				</second>
+			</item>
+		</list_category>
+	</px>
+</boost.shared_ptr-blog->
+[QxOrm] end dump 'boost::shared_ptr<blog>'
+
+
+
+
+
+ +

Introspection - R�flexion +

+
+ Toute classe enregistr�e dans le contexte QxOrm par la m�thode qx::register_class<T>() + peut �tre utilis�e par le moteur d'introspection (ou r�flexion) de la biblioth�que QxOrm. + Le moteur d'introspection permet d'obtenir de fa�on dynamique (donc pendant l'ex�cution du + programme) des informations propres � un type. + Ces informations correspondent � des m�ta-donn�es et d�crivent de fa�on exhaustive les + caract�ristiques d'une classe (propri�t�s, m�thodes, etc.). + De nombreux langages de programmation (par exemple Java ou C#) int�grent nativement ce m�canisme, + ce n'est pas le cas du C++, c'est pourquoi la biblioth�que QxOrm �mule un moteur d'introspection. + Pour plus de d�tails sur l'introspection (ou r�flexion), rendez-vous sur la page Wikipedia. +

+ Voici la liste des classes disponibles pour acc�der aux m�ta-donn�es : +
    +
  • qx::QxClassX : + singleton permettant de parcourir l'ensemble des classes enregistr�es dans le contexte QxOrm + par la m�thode qx::register_class<T>() ;
  • +
  • qx::IxClass : + interface pour une classe enregistr�e dans le contexte QxOrm ;
  • +
  • qx::IxDataMemberX : liste des propri�t�s associ�es � une classe ;
  • +
  • qx::IxDataMember : interface pour une propri�t� d'une classe ;
  • +
  • qx::IxFunctionX : + liste des m�thodes associ�es � une classe ;
  • +
  • qx::IxFunction : + interface pour une m�thode d'une classe (static ou non static).
  • +
+ Une instance de type qx::IxClass poss�de la liste des propri�t�s d'une classe (qx::IxDataMemberX) ainsi que la liste des m�thodes d'une classe (qx::IxFunctionX).
+
+ Le moteur d'introspection de la biblioth�que QxOrm permet par exemple de : + +
+ Remarque : le module QxService de la biblioth�que QxOrm (cliquez ici pour acc�der au tutoriel) permettant de cr�er un serveur + d'applications C++ est bas� sur le moteur d'introspection pour appeler dynamiquement les m�thodes + de type service (demande du client) sur le serveur, ainsi que pour cr�er dynamiquement les + instances des classes de param�tre (entr�e/sortie).
+
+ Autre remarque : il est possible d'ajouter de nouvelles informations au moteur + d'introspection en utilisant la notion de property bag. + En effet, les classes qx::IxClass, qx::IxDataMember et qx::IxFunction + poss�dent chacune une liste d'�l�ments de type QVariant accessibles par cl� de type + QString (voir la + classe qx::QxPropertyBag pour plus de d�tails sur cette notion). +

+ Autre remarque : afin d'initialiser le moteur d'introspection QxOrm, il est recommand� + d'appeler la fonction suivante en d�but de programme (main par exemple) : +

+ + + + + + + +
+
// Following command is recommanded to initialize QxOrm introspection engine
+qx::QxClassX::registerAllClasses(true);
+
+

+

Obtenir dynamiquement la + valeur d'une donn�e membre

+
+ Pour obtenir dynamiquement la valeur d'une donn�e membre en utilisant le moteur d'introspection + de la biblioth�que QxOrm, il est n�cessaire de passer par la classe : qx::IxDataMember. + La classe qx::IxDataMember fournit plusieurs m�thodes pour obtenir la valeur d'une + donn�e membre (chacune prenant en param�tre un pointeur g�n�rique de type void * + correspondant � l'adresse de l'instance courante) : + + Par exemple : imaginons un pointeur g�n�rique de type void * vers une classe + person. Nous pouvons obtenir la valeur de la propri�t� firstName de type + QString de la fa�on suivante : +

+ + + + + + + +
+
// Generic pointer of type void * : we know that p is of type 'person'
+void * p = ...;
+
+// Get a pointer to the registered data member 'firstName' of class 'person'
+qx::IxDataMember * pDataMember = qx::QxClassX::getDataMember("person", "firstName");
+
+// First method to get the data member value with the real type
+QString sFirstName = pDataMember->getValue<QString>(p);
+
+// Second method to get the data member value converted in QVariant
+QVariant vFirstName = pDataMember->toVariant(p);
+
+// Third method to get the value encapsulated in qx::any type
+boost::any aFirstName = pDataMember->getValueAnyPtr(p);
+
+// Check if all values are equals
+qAssert((sFirstName == vFirstName.toString()) && (sFirstName == (* boost::any_cast<QString *>(aFirstName))));
+
+

+
+

Valoriser dynamiquement + une donn�e membre

+
+ De la m�me fa�on que pour obtenir la valeur d'une donn�e membre, la classe qx::IxDataMember + permet de valoriser une donn�e membre (modifier sa valeur). + La classe qx::IxDataMember fournit les 2 m�thodes suivantes (chacune prend en + param�tre un pointeur de type void * correspondant � l'adresse de l'instance courante, + ainsi que la nouvelle valeur � positionner) : +
    +
  • fromVariant() : valorise la donn�e membre en fonction du param�tre + de type QVariant ;
  • +
  • setValue<T>() : valorise la donn�e membre avec un param�tre + du type r�el T de la donn�e membre.
  • +
+ Par exemple : imaginons un pointeur g�n�rique de type void * vers une classe + person. Nous pouvons modifier la valeur de la propri�t� firstName de type + QString de la fa�on suivante : +

+ + + + + + + +
+
// Generic pointer of type void * : we know that p is of type 'person'
+void * p = ...;
+
+// Get a pointer to the registered data member 'firstName' of class 'person'
+qx::IxDataMember * pDataMember = qx::QxClassX::getDataMember("person", "firstName");
+
+// First method to change the data member value
+QVariant vFirstName = QVariant("my new firstname 1");
+pDataMember->fromVariant(p, vFirstName);
+
+// Other method to change the data member value (using real type)
+QString sFirstName = "other firstname 2";
+pDataMember->setValue<QString>(p, sFirstName);
+
+

+
+

Appeler dynamiquement une + fonction

+
+ Tout comme les donn�es membre (propri�t�s), il est possible d'enregistrer des m�thodes membre + (fonctions) dans le contexte QxOrm (support des m�thodes static et non static). + Le moteur d'introspection de la biblioth�que QxOrm permet d'invoquer dynamiquement des m�thodes + de classe. + Toutes les fonctions enregistr�es dans le contexte QxOrm sont associ�es � une instance de la + classe : qx::IxFunction. + Pour enregistrer des m�thodes dans le contexte QxOrm, il faut utiliser : + + Par exemple : on souhaite enregistrer dans le contexte QxOrm plusieurs m�thodes d'une + classe person : +

+ * Fichier person.h :
+ + + + + + + +
+
#ifndef _PERSON_H_
+#define _PERSON_H_
+
+class person
+{
+public:
+   long id;
+   QString firstName;
+   QString lastName;
+   QDateTime birthDate;
+
+   person() : id(0) { ; }
+   virtual ~person() { ; }
+
+   long getId() const;
+   void myMethodWith2Params(int param1, const QString & param2);
+
+   static double myStaticMethodWith1Param(long param1);
+
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(person, qx::trait::no_base_class_defined, 0)
+
+#endif // _PERSON_H_
+
+
+ * Fichier person.cpp :
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<person> & t)
+{
+  t.id(& person::id, "id");
+  t.data(& person::firstName, "first_name");
+  t.data(& person::lastName, "last_name");
+  t.data(& person::birthDate, "birth_date");
+
+  t.fct_0<long>(& person::getId, "getId");
+  t.fct_2<void, int, const QString &>(& person::myMethodWith2Params, "myMethodWith2Params");
+
+  t.fctStatic_1<double, long>(& person::myStaticMethodWith1Param, "myStaticMethodWith1Param");
+}}
+
+

+ Une fois enregistr�es dans le contexte QxOrm, il est possible d'appeler dynamiquement ces + fonctions avec les m�thodes qx::QxClassX::invoke() et qx::QxClassX::invokeStatic() : +

+ + + + + + + +
+
   // Generic pointer of type void * : we know that p is of type 'person'
+   void * p = ...;
+
+   // Call method 'long getId() const' and get return value
+   boost::any returnValue;
+   qx::QxClassX::invoke("person", "getId", p, "", (& returnValue));
+   long lId = boost::any_cast<long>(returnValue);
+
+   // Call method 'myMethodWith2Params' with 2 parameters encapsulated in a string (default separator for parameters is character '|')
+   // This way to pass parameters to the function works only if parameters are numeric or string
+   // If parameters are more complex, then you have to encapsulate parameters in a list of qx::any, as shown below
+   qx::QxClassX::invoke("person", "myMethodWith2Params", p, "36|my string param 2");
+
+   // Call method 'myMethodWith2Params' with 2 parameters encapsulated in a list of qx::any : std::vector<qx::any>
+   std::vector<boost::any> lstParams;
+   int iParam1 = 36; lstParams.push_back(iParam1); // Parameter at position 1
+   QString sParam2 = "my string param 2"; lstParams.push_back(sParam2); // Parameter at position 2
+   qx::QxClassX::invoke("person", "myMethodWith2Params", p, lstParams);
+
+   // Call static method 'myStaticMethodWith1Param' with 1 parameter and get return value
+   qx::QxClassX::invokeStatic("person", "myStaticMethodWith1Param", "19", (& returnValue));
+   double dValue = boost::any_cast<double>(returnValue);
+
+

+
+

Cr�er une instance C++ + dynamiquement

+
+ Le moteur d'introspection de la biblioth�que QxOrm permet de cr�er dynamiquement des instances + de classe (module + QxFactory, mod�le de conception fabrique ou design pattern factory) avec les m�thodes + suivantes : +
    +
  • qx::create(const + QString & sKey) : cr�ation d'une instance de type sKey sous la forme qx::any (contenant un pointeur intelligent de type + std::shared_ptr, alias de boost::shared_ptr par d�faut) ; +
  • +
  • qx::create_nude_ptr<T>(const QString & sKey) : cr�ation d'une + instance de type sKey sous la forme d'un pointeur nu de type T * (attention + � lib�rer la m�moire de ce pointeur pour �viter les fuites m�moire) ;
  • +
  • qx::create_void_ptr(const QString & sKey) : cr�ation d'une instance + de type sKey sous la forme d'un pointeur nu de type void * (attention � + lib�rer la m�moire de ce pointeur pour �viter les fuites m�moire).
  • +
+ Par exemple : le module QxService de la biblioth�que QxOrm + utilise ce m�canisme pour cr�er dynamiquement les instances de classe de service pour ex�cuter + les routines c�t� serveur : +

+ + + + + + + +
+
   qx::service::IxService * ptr = qx::create_nude_ptr<qx::service::IxService>(m_sServiceName);   
+
+

+
+

Parcourir la liste des + classes/propri�t�s enregistr�es dans le contexte QxOrm

+
+ Voici un exemple d'utilisation du moteur d'introspection de la biblioth�que QxOrm : comment + lister toutes les classes, propri�t�s et m�thodes enregistr�es dans le contexte QxOrm ?
+
+ + + + + + + +
+
QString QxClassX::dumpAllClasses()
+{
+   QxClassX::registerAllClasses();
+   QxCollection<QString, IxClass *> * pAllClasses = QxClassX::getAllClasses();
+   if (! pAllClasses) { qAssert(false); return ""; }
+
+   QString sDump;
+   long lCount = pAllClasses->count();
+   qDebug("[QxOrm] start dump all registered classes (%ld)", lCount);
+   _foreach(IxClass * pClass, (* pAllClasses))
+   { if (pClass) { sDump += pClass->dumpClass(); } }
+   qDebug("[QxOrm] %s", "end dump all registered classes");
+
+   return sDump;
+}
+
+QString IxClass::dumpClass() const
+{
+   QString sDump;
+   sDump += "-- class '" + m_sKey + "' (name '" + m_sName + "', ";
+   sDump += "description '" + m_sDescription + "', version '" + QString::number(m_lVersion) + "', ";
+   sDump += "base class '" + (getBaseClass() ? getBaseClass()->getKey() : "") + "')\n";
+
+   long lCount = (m_pDataMemberX ? m_pDataMemberX->count() : 0);
+   sDump += "\t* list of registered properties (" + QString::number(lCount) + ")\n";
+   if (m_pDataMemberX)
+   {
+      IxDataMember * pId = this->getId();
+      for (long l = 0; l < lCount; l++)
+      {
+         IxDataMember * p = m_pDataMemberX->get(l); if (! p) { continue; }
+         IxSqlRelation * pRelation = p->getSqlRelation();
+         QString sInfos = p->getKey() + ((p == pId) ? QString(" (id)") : QString());
+         sInfos += (pRelation ? (QString(" (") + pRelation->getDescription() + QString(")")) : QString());
+         sDump += "\t\t" + sInfos + "\n";
+      }
+   }
+
+   lCount = (m_pFctMemberX ? m_pFctMemberX->count() : 0);
+   sDump += "\t* list of registered functions (" + QString::number(lCount) + ")\n";
+   if (m_pFctMemberX)
+   {
+      _foreach_if(IxFunction_ptr p, (* m_pFctMemberX), (p))
+      { QString sKey = p->getKey(); sDump += "\t\t" + sKey + "\n"; }
+   }
+
+   qDebug("%s", qPrintable(sDump));
+   return sDump;
+}
+
+
+ Si on utilise la m�thode qx::QxClassX::dumpAllClasses() avec le tutoriel qxBlog, voici le r�sultat obtenu :
+
+ + + + + + + +
+
[QxOrm] start dump all registered classes (4)
+-- class 'author' (name 'author', description '', version '0', base class '')
+	* list of registered properties (5)
+		author_id (id)
+		name
+		birthdate
+		sex
+		list_blog (relation one-to-many)
+	* list of registered functions (1)
+		age
+
+-- class 'blog' (name 'blog', description '', version '0', base class '')
+	* list of registered properties (6)
+		blog_id (id)
+		blog_text
+		date_creation
+		author_id (relation many-to-one)
+		list_comment (relation one-to-many)
+		list_category (relation many-to-many)
+	* list of registered functions (0)
+
+-- class 'comment' (name 'comment', description '', version '0', base class '')
+	* list of registered properties (4)
+		comment_id (id)
+		comment_text
+		date_creation
+		blog_id (relation many-to-one)
+	* list of registered functions (0)
+
+-- class 'category' (name 'category', description '', version '0', base class '')
+	* list of registered properties (4)
+		category_id (id)
+		name
+		description
+		list_blog (relation many-to-many)
+	* list of registered functions (0)
+
+[QxOrm] end dump all registered classes
+
+
+
+
+ +

Services : transf�rer la + couche de donn�es persistante sur le r�seau (module QxService)

+
+ Le module QxService de + la biblioth�que QxOrm permet de cr�er rapidement un serveur d'applications C++ + performant (notion de services avec demande du client et r�ponse du serveur). + Un tutoriel est disponible sur + le site QxOrm afin de pr�senter un exemple d'utilisation du module QxService. + Le module QxService est bas� + sur le moteur d'introspection ainsi que le moteur de + s�rialisation de la biblioth�que QxOrm afin de transf�rer la couche de donn�es persistante + sur le r�seau et ex�cuter automatiquement les routines c�t� serveur. +

+ Remarque : pour activer le module QxService, il faut d�finir l'option de compilation + _QX_ENABLE_QT_NETWORK dans le fichier de configuration QxOrm.pri (ou QxOrm.cmake). + Cette option de compilation ajoute une d�pendance au binaire QtNetwork fourni avec la + biblioth�que Qt. +

+ Autre remarque : l'application QxEntityEditor est livr�e avec le plugin + QxEECppServicesExport : ce plugin g�n�re automatiquement le code source n�cessaire pour + transf�rer l'ensemble des entit�s d'un projet sur le r�seau. + Une liste de m�thodes client/serveur est g�n�r�e automatiquement : +
    +
  • count() : requ�te client/serveur pour compter le nombre d'�l�ments (avec possibilit� + d'utiliser un filtre SQL) ;
  • +
  • fetchById() : requ�te client/serveur pour alimenter les propri�t�s d'une entit� en + fonction de son identifiant ;
  • +
  • fetchAll() : requ�te client/serveur pour alimenter les propri�t�s de toutes les + entit�s d'une table ;
  • +
  • fetchByQuery() : requ�te client/serveur pour alimenter les propri�t�s des entit�s + filtr�es par une requ�te SQL ;
  • +
  • insert() : requ�te client/serveur pour ins�rer les donn�es d'une entit� ;
  • +
  • update() : requ�te client/serveur pour mettre � jour les donn�es d'une entit� ;
  • +
  • save() : requ�te client/serveur pour sauvegarder les donn�es d'une entit� (insertion + ou mise � jour) ;
  • +
  • deleteById() : requ�te client/serveur pour supprimer une entit� en fonction de son + identifiant ;
  • +
  • deleteAll() : requ�te client/serveur pour supprimer tous les �l�ments de la table + mapp�e � une entit� ;
  • +
  • deleteByQuery() : requ�te client/serveur pour supprimer tous les �l�ments en fonction + d'une requ�te SQL ;
  • +
  • destroyById() : requ�te client/serveur pour supprimer une entit� en fonction de son + identifiant (avec prise en compte de la suppression logique) ; +
  • +
  • destroyAll() : requ�te client/serveur pour supprimer tous les �l�ments de la table + mapp�e � une entit� (avec prise en compte de la suppression + logique) ;
  • +
  • destroyByQuery() : requ�te client/serveur pour supprimer tous les �l�ments en + fonction d'une requ�te SQL (avec prise en compte de la suppression + logique) ;
  • +
  • executeQuery() : requ�te client/serveur pour ex�cuter une + requ�te SQL personnalis�e ou proc�dure stock�e ;
  • +
  • exist() : requ�te client/serveur pour tester l'existence d'une entit� en fonction de + son identifiant ;
  • +
  • isValid() : requ�te client/serveur pour tester la validit� d'une entit� (module QxValidator).
  • +
+ Il est possible d'ajouter de nouveaux services ou de personnaliser les services g�n�r�s + automatiquement par l'application QxEntityEditor. +

+ L'objectif de ce chapite est de pr�senter les concepts � mettre en oeuvre pour utiliser le module + QxService : + +
+

Param�tres + d'entr�e/sortie d'un service (requ�te/r�ponse)

+
+ Chaque fonction publi�e par un service dispose de param�tres d'entr�e (demande du client) et de + param�tres de sortie (r�ponse du serveur). + Ces param�tres d'entr�e/sortie doivent h�riter de l'interface qx::service::IxParameter et doivent �tre enregistr�es dans le contexte + QxOrm (par la fonction void qx::register_class<T>). +

+ Par exemple : voici un exemple de param�tres d'entr�e/sortie g�n�r�s automatiquement par + l'application QxEntityEditor bas� sur la classe blog du tutoriel qxBlog : +

+ * Fichier blog.services.gen.h :
+ + + + + + + +
+
namespace services {
+
+typedef boost::shared_ptr<blog> blog_ptr;
+typedef qx::QxCollection<long, blog_ptr> list_of_blog;
+typedef boost::shared_ptr<list_of_blog> list_of_blog_ptr;
+
+/* -- Service Input Parameters -- */
+
+class QXBLOG_SERVICES_EXPORT blog_input : public qx::service::IxParameter
+{
+
+public:
+
+   blog_input();
+   virtual ~blog_input();
+
+   long id;                   //!< Id to fetch or delete
+   blog_ptr instance;         //!< Single instance to fetch, insert, update, delete or validate
+   list_of_blog_ptr list;     //!< List of instances to fetch, insert, update, delete or validate
+   qx_query query;            //!< Query to execute when fetching, updating or deleting
+   QStringList columns;       //!< List of columns to fetch or update
+   QStringList relations;     //!< List of relations to fetch
+
+};
+
+typedef boost::shared_ptr<services::blog_input> blog_input_ptr;
+
+/* -- Service Output Parameters -- */
+
+class QXBLOG_SERVICES_EXPORT blog_output : public qx::service::IxParameter
+{
+
+public:
+
+   blog_output();
+   virtual ~blog_output();
+
+   blog_ptr instance;            //!< Single instance from server
+   list_of_blog_ptr list;        //!< List of instances from server
+   QSqlError error;              //!< If a SQL error occurred, this output parameter is not empty
+   qx::QxInvalidValueX invalid;  //!< Check if a single instance (or a list of instances) is valid
+   qx_query query;               //!< Query which contains all results
+   long count;                   //!< Count how many items in database using a query or not
+   qx_bool exist;                //!< Check if a single instance (or a list of instances) exist in database
+
+};
+
+typedef boost::shared_ptr<services::blog_output> blog_output_ptr;
+
+} // namespace services
+
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_input, qx::service::IxParameter, 0, services_blog_input)
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_output, qx::service::IxParameter, 0, services_blog_output)
+
+
+ * Fichier blog.services.gen.cpp :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_input, services_blog_input)
+QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_output, services_blog_output)
+
+namespace qx {
+
+template <>
+void register_class(QxClass<services::blog_input> & t)
+{
+   t.data(& services::blog_input::id, "id");
+   t.data(& services::blog_input::instance, "instance");
+   t.data(& services::blog_input::list, "list");
+   t.data(& services::blog_input::query, "query");
+   t.data(& services::blog_input::columns, "columns");
+   t.data(& services::blog_input::relations, "relations");
+}
+
+template <>
+void register_class(QxClass<services::blog_output> & t)
+{
+   t.data(& services::blog_output::instance, "instance");
+   t.data(& services::blog_output::list, "list");
+   t.data(& services::blog_output::error, "error");
+   t.data(& services::blog_output::invalid, "invalid");
+   t.data(& services::blog_output::query, "query");
+   t.data(& services::blog_output::count, "count");
+   t.data(& services::blog_output::exist, "exist");
+}
+
+} // namespace qx
+
+

+ Remarque : comme on peut le constater sur l'exemple ci-dessus, les param�tres + d'entr�e/sortie peuvent contenir des types complexes (des collections, des pointeurs, etc...). + Il est donc possible et tr�s simple de transf�rer des structures complexes sur le r�seau avec le + module QxService. +

+
+

D�finir les fonctions + publi�es par un service

+
+ Chaque service enregistr� dans le module QxService publie une liste de fonctions accessibles c�t� client (requ�tes + client/serveur). + Les services doivent h�riter de la classe de base qx::service::QxService<INPUT, OUTPUT> (les param�tres template + INPUT et OUTPUT correspondant aux param�tres + d'entr�e/sortie) et doivent �tre enregistr�s dans le contexte QxOrm (par la fonction + void qx::register_class<T>). +

+ Par exemple : voici un exemple de service g�n�r� automatiquement par l'application + QxEntityEditor bas� sur la classe blog du tutoriel qxBlog : +

+ * Fichier blog.services.gen.h :
+ + + + + + + +
+
namespace services {
+
+/* -- Service Definition -- */
+
+typedef qx::service::QxService< blog_input, blog_output > blog_base_class;
+class QXBLOG_SERVICES_EXPORT blog_services : public blog_base_class
+{
+
+   QX_REGISTER_FRIEND_CLASS(services::blog_services)
+
+public:
+
+   blog_services();
+   virtual ~blog_services();
+
+protected:
+
+   void fetchById_();
+   void fetchAll_();
+   void fetchByQuery_();
+
+   void insert_();
+   void update_();
+   void save_();
+   void deleteById_();
+   void deleteAll_();
+   void deleteByQuery_();
+   void destroyById_();
+   void destroyAll_();
+   void destroyByQuery_();
+
+   void executeQuery_();
+   void callQuery_();
+   void exist_();
+   void count_();
+   void isValid_();
+
+#ifdef _QXBLOG_SERVICES_MODE_CLIENT
+
+public:
+
+   blog_ptr fetchById(long id, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchById(blog_ptr & p, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchById(list_of_blog_ptr & lst, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchAll(list_of_blog_ptr & lst, const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError fetchByQuery(const qx_query & query, list_of_blog_ptr & lst, const QStringList & columns = QStringList(),
+                                       const QStringList & relations = QStringList());
+
+   QSqlError insert(blog_ptr & p, const QStringList & relations = QStringList());
+   QSqlError insert(list_of_blog_ptr & lst, const QStringList & relations = QStringList());
+   QSqlError update(blog_ptr & p, const qx_query & query = qx_query(),
+                              const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError update(list_of_blog_ptr & lst, const qx_query & query = qx_query(),
+                              const QStringList & columns = QStringList(), const QStringList & relations = QStringList());
+   QSqlError save(blog_ptr & p, const QStringList & relations = QStringList());
+   QSqlError save(list_of_blog_ptr & lst, const QStringList & relations = QStringList());
+
+   QSqlError deleteById(long id);
+   QSqlError deleteById(blog_ptr & p);
+   QSqlError deleteById(list_of_blog_ptr & lst);
+   QSqlError deleteAll();
+   QSqlError deleteByQuery(const qx_query & query);
+   QSqlError destroyById(long id);
+   QSqlError destroyById(blog_ptr & p);
+   QSqlError destroyById(list_of_blog_ptr & lst);
+   QSqlError destroyAll();
+   QSqlError destroyByQuery(const qx_query & query);
+
+   QSqlError executeQuery(qx_query & query, blog_ptr & p);
+   QSqlError executeQuery(qx_query & query, list_of_blog_ptr & lst);
+   QSqlError callQuery(qx_query & query);
+   qx_bool exist(blog_ptr & p);
+   qx_bool exist(list_of_blog_ptr & lst);
+   QSqlError count(long & lCount, const qx_query & query = qx_query());
+   qx::QxInvalidValueX isValid(blog_ptr & p);
+   qx::QxInvalidValueX isValid(list_of_blog_ptr & lst);
+
+#endif // _QXBLOG_SERVICES_MODE_CLIENT
+
+};
+
+typedef boost::shared_ptr<services::blog_services> blog_services_ptr;
+
+} // namespace services
+
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QXBLOG_SERVICES(services::blog_services, qx::service::IxService, 0, services_blog_services)
+
+
+ * Fichier blog.services.gen.cpp :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QXBLOG_SERVICES(services::blog_services, services_blog_services)
+
+namespace qx {
+
+template <>
+void register_class(QxClass<services::blog_services> & t)
+{
+   t.fct_0<void>(& services::blog_services::fetchById_, "fetchById");
+   t.fct_0<void>(& services::blog_services::fetchAll_, "fetchAll");
+   t.fct_0<void>(& services::blog_services::fetchByQuery_, "fetchByQuery");
+
+   t.fct_0<void>(& services::blog_services::insert_, "insert");
+   t.fct_0<void>(& services::blog_services::update_, "update");
+   t.fct_0<void>(& services::blog_services::save_, "save");
+   t.fct_0<void>(& services::blog_services::deleteById_, "deleteById");
+   t.fct_0<void>(& services::blog_services::deleteAll_, "deleteAll");
+   t.fct_0<void>(& services::blog_services::deleteByQuery_, "deleteByQuery");
+   t.fct_0<void>(& services::blog_services::destroyById_, "destroyById");
+   t.fct_0<void>(& services::blog_services::destroyAll_, "destroyAll");
+   t.fct_0<void>(& services::blog_services::destroyByQuery_, "destroyByQuery");
+
+   t.fct_0<void>(& services::blog_services::executeQuery_, "executeQuery");
+   t.fct_0<void>(& services::blog_services::callQuery_, "callQuery");
+   t.fct_0<void>(& services::blog_services::exist_, "exist");
+   t.fct_0<void>(& services::blog_services::count_, "count");
+   t.fct_0<void>(& services::blog_services::isValid_, "isValid");
+}
+
+} // namespace qx
+
+// Then there is the implementation of all functions provided by the service...
+
+

+ Remarque : une fois d�finies dans le contexte QxOrm, le client peut appeler les fonctions + publi�es par le service : les routines c�t� serveur sont alors ex�cut�es automatiquement. + La s�rialisation des donn�es ainsi que la gestion de la couche r�seau pour le transfert des + donn�es sont g�r�es de mani�re transparente par le module QxService. +

+
+

Liste des options + disponibles c�t� serveur

+
+ Le serveur d'application C++ bas� sur le module QxService dispose de + plusieurs param�tres accessibles par la classe singleton qx::service::QxConnect : +
    +
  • setPort() : port d'�coute pour recevoir les requ�tes du client et envoyer les + r�ponses du serveur ;
  • +
  • setThreadCount() : nombre de threads disponibles c�t� serveur pour traiter les + demandes du client ;
  • +
  • setSerializationType() : type de s�rialisation utilis� + pour envoyer les r�ponses du serveur ;
  • +
  • setCompressData() : permet de d�finir si les donn�es renvoy�es par le serveur sont + compress�es ou non ;
  • +
  • setEncryptData() : permet de d�finir si les donn�es renvoy�es par le serveur sont + crypt�es ou non (avec possibilit� de renseigner une cl� de cryptage).
  • +
+
+
+

Param�trage de la + connexion c�t� client

+
+ La couche cliente bas�e sur le module QxService dispose de plusieurs param�tres accessibles par la classe + singleton qx::service::QxConnect : +
    +
  • setIp() : adresse IP du serveur d'application C++ ;
  • +
  • setPort() : port utilis� par le serveur d'application C++ ;
  • +
  • setSerializationType() : type de s�rialisation utilis� + par la couche cliente pour envoyer les requ�tes du client au serveur ;
  • +
  • setCompressData() : permet de d�finir si les donn�es envoy�es au serveur sont + compress�es ou non ;
  • +
  • setEncryptData() : permet de d�finir si les donn�es envoy�es au serveur sont + crypt�es ou non (avec possibilit� de renseigner une cl� de cryptage).
  • +
+
+
+

Gestion de + l'authentification dans un service

+
+ Il est classique d'impl�menter un contr�le au niveau du serveur pour v�rifier l'utilisateur + connect� � la couche cliente. + L'interface qx::service::IxService (classe de base de tous les services enregistr�s + par le module QxService) + fournit des m�thodes virtuelles qui peuvent �tre surcharg�es pour g�rer cette probl�matique : +
    +
  • onBeforeProcess() : m�thode virtuelle appel�e syst�matiquement avant ex�cution de + la routine serveur ;
  • +
  • onAfterProcess() : m�thode virtuelle appel�e syst�matiquement apr�s ex�cution de + la routine serveur.
  • +
+
+ Par exemple : voici une classe de base nomm�e ParameterAuthentication qui peut + �tre utilis�e par tous les param�tres d'entr�e/sortie, cette classe fournit 3 propri�t�s + login, password et token : +

+ * Fichier ParameterAuthentication.h :
+ + + + + + + +
+
class MY_DLL_EXPORT ParameterAuthentication : public qx::service::IxParameter
+{
+ 
+public:
+ 
+   ParameterAuthentication();
+   virtual ~ParameterAuthentication();
+ 
+   QString login;
+   QString password;
+   QString token;
+   // etc..., put here all properties required by the authentication process
+ 
+};
+ 
+typedef boost::shared_ptr<ParameterAuthentication> ParameterAuthentication_ptr;
+ 
+QX_REGISTER_COMPLEX_CLASS_NAME_HPP_MY_DLL(ParameterAuthentication, qx::service::IxParameter, 0, ParameterAuthentication)
+
+
+ * Fichier ParameterAuthentication.cpp :
+ + + + + + + +
+
QX_REGISTER_COMPLEX_CLASS_NAME_CPP_MY_DLL(ParameterAuthentication, ParameterAuthentication)
+ 
+namespace qx {
+ 
+template <>
+void register_class(QxClass<ParameterAuthentication> & t)
+{
+   t.data(& ParameterAuthentication::login, "login");
+   t.data(& ParameterAuthentication::password, "password");
+   t.data(& ParameterAuthentication::token, "token");
+}
+ 
+} // namespace qx
+
+

+ Maintenant que l'on dispose d'une classe de base pour nos param�tres + (ParameterAuthentication), nous allons cr�er une classe de base utilis�e par tous nos + services nomm�e ServiceAuthentication<INPUT, OUTPUT>. + Cette classe de base des services va surcharger la m�thode virtuelle onBeforeProcess() + afin de g�rer l'authentification avant ex�cution de la routine serveur : +

+ * Fichier ServiceAuthentication.h :
+ + + + + + + +
+
#include "ParameterAuthentication.h"
+ 
+template <class INPUT, class OUTPUT>
+class ServiceAuthentication : public qx::service::QxService<INPUT, OUTPUT>
+{
+ 
+public:
+ 
+   ServiceAuthentication(const QString & sServiceName) : qx::service::QxService<INPUT, OUTPUT>(sServiceName) { ; }
+   virtual ~ServiceAuthentication() { ; }
+ 
+   virtual void onBeforeProcess()
+   {
+      // Here you can implement your own authentication control (checking login/password for example)
+      // You can get input authentication parameters like this :
+      ParameterAuthentication_ptr pParams = getInputParameter();
+      pParams->login, pParams->password, etc...
+ 
+      // If authentication is not valid, then you can throw an exception (and stop process before executing service function)
+      throw qx::exception("Authentication error !");
+   }
+ 
+};
+
+

+ A pr�sent, nous disposons des classes de base ParameterAuthentication et + ServiceAuthentication<INPUT, OUTPUT> : toutes les classes de param�tres et toutes + les classes de services doivent h�riter de ces classes de base pour g�rer automatiquement + l'authentification, et retourner une erreur au client si les param�tres de l'utilisateur ne sont + pas valides. +

+ Remarque : de la m�me fa�on que pour g�rer l'authentification, il est possible de mettre + en place des logs automatiques en surchargeant les m�thodes virtuelles onBeforeProcess() + et onAfterProcess(). +

+
+

Requ�tes client/serveur + asynchrones

+
+ Par d�faut, les requ�tes client/serveur sont synchrones : ce qui signifie que la couche cliente + attend la r�ponse du serveur pour continuer son ex�cution. + Dans une interface graphique utilisateur (GUI), une requ�te client/serveur bloque + l'application (freeze) si elle est ex�cut�e dans le thread principal : si le serveur met + du temps pour renvoyer sa r�ponse, l'utilisateur peut alors penser qu'il s'agit d'un crash de + l'application. + La module QxService + propose une solution simple pour effectuer des requ�tes asynchrones (qui ne bloquent donc pas + l'interface graphique de l'utilisateur) gr�ce � la classe qx::service::QxClientAsync. +

+ La classe qx::service::QxClientAsync utilise le moteur + d'introspection de la biblioth�que QxOrm ainsi que le m�canisme SIGNAL-SLOT de + Qt. + Elle prend en param�tre : +
    +
  • une instance de service ;
  • +
  • les param�tres d'entr�e/sortie du service ;
  • +
  • le nom de la routine serveur � ex�cuter (sous forme de chaine de caract�res) ;
  • +
  • une fonction � appeler une fois que la transaction est termin�e (connexion � l'�v�nement + signal finished()). +
  • +
+
+ Voici l'exemple issu du tutoriel qxClientServer qui + ex�cute une routine serveur de mani�re asynchrone : +

+ + + + + + + +
+
void main_dlg::onClickBtnDateTimeAsync()
+{
+   if (m_pDateTimeAsync) { qDebug("[QxOrm] '%s' transaction is already running", "server_infos::get_current_date_time"); return; }
+
+   // Cr�ation d'une instance de service et appel � la m�thode pour recevoir la date-heure courante du serveur (mode asynchrone)
+   server_infos_ptr service = server_infos_ptr(new server_infos());
+   m_pDateTimeAsync.reset(new qx::service::QxClientAsync());
+   QObject::connect(m_pDateTimeAsync.get(), SIGNAL(finished()), this, SLOT(onDateTimeAsyncFinished()));
+   m_pDateTimeAsync->setService(service, "get_current_date_time");
+   m_pDateTimeAsync->start();
+}
+
+void main_dlg::onDateTimeAsyncFinished()
+{
+   if (! m_pDateTimeAsync || ! m_pDateTimeAsync->getService()) { return; }
+   updateLastTransactionLog(m_pDateTimeAsync->getService()->getTransaction());
+   m_pDateTimeAsync.reset();
+}
+
+

+ Remarque : l'exemple ci-dessus montre comment effectuer une requ�te asynchrone avec les + actions suivantes : +
    +
  • cr�ation d'une instance d'un service (de type server_infos_ptr pour cet exemple) ; +
  • +
  • cr�ation d'une instance de type qx::service::QxClientAsync ;
  • +
  • connexion � l'�v�nement finished (pour indiquer qu'une r�ponse du serveur vient + d'arriver) ;
  • +
  • passage de l'instance du service et de la m�thode � appeler (sous forme de chaine de + caract�res) � l'objet qx::service::QxClientAsync ;
  • +
  • d�marrage de la transaction avec l'appel de la m�thode start().
  • +
+
+
+
+ +

Moteur mod�le/vue (module + QxModelView)

+
+ Le module QxModelView permet d'utiliser le moteur model/view de Qt avec + toutes les classes enregistr�es dans le contexte QxOrm : +
    +
  • QML : toute propri�t� enregistr�e dans le contexte QxOrm est + accessible en QML : le module QxModelView permet ainsi de faciliter l'int�raction entre QML + et les bases de donn�es ;
  • +
  • Qt widgets : utilisation de QTableView ou QListView + par exemple pour afficher/modifier le contenu d'une table de la base de donn�es.
  • +
+ L'interface qx::IxModel + propose une base commune pour tous les mod�les li�s aux classes persistantes d�clar�es dans le + contexte QxOrm. + Les m�thodes de cette classe pr�fix�es par 'qx' appellent les fonctions du namespace qx::dao et + communiquent donc directement avec la base de donn�es. + L'interface qx::IxModel + fournit �galement des m�thodes d�finies Q_INVOKABLE et sont donc accessibles directement en + QML : +
    +
  • qxCount_() : compte le nombre d'�l�ments dans la table de la base de donn�es associ�e + au mod�le (avec possibilit� d'indiquer un filtre SQL) ;
  • +
  • qxFetchById_() : alimente le mod�le en fonction de l'identifiant pass� en param�tre ; +
  • +
  • qxFetchAll_() : alimente le mod�le avec tous les �l�ments contenus dans la table de + la base de donn�es associ�e au mod�le ;
  • +
  • qxFetchByQuery_() : alimente le mod�le avec les �l�ments de la table de la base de + donn�es associ�e au mod�le en fonction d'une requ�te SQL ;
  • +
  • qxFetchRow_() : alimente (met � jour) une ligne du mod�le (chaque ligne du mod�le + dispose de son propre identifiant de base de donn�es) ;
  • +
  • qxInsert_() : ins�re l'int�gralit� du mod�le en base de donn�es ;
  • +
  • qxInsertRow_() : ins�re une ligne du mod�le en base de donn�es ;
  • +
  • qxUpdate_() : met � jour l'int�gralit� du mod�le en base de donn�es ;
  • +
  • qxUpdateRow_() : met � jour une ligne du mod�le en base de donn�es ;
  • +
  • qxSave_() : sauvegarde l'int�gralit� du mod�le en base de donn�es (insertion ou mise + � jour) ;
  • +
  • qxSaveRow_() : sauvegarde une ligne du mod�le en base de donn�es (insertion ou mise � + jour) ;
  • +
  • qxDeleteById_() : supprime un �l�ment de la base de donn�es en fonction de + l'identifiant pass� en param�tre ;
  • +
  • qxDeleteAll_() : supprime tous les �l�ments de la table de la base de donn�es + associ�e au mod�le ;
  • +
  • qxDeleteByQuery_() : supprime les �l�ments de la table de la base de donn�es associ�e + au mod�le en fonction d'une requ�te SQL ;
  • +
  • qxDeleteRow_() : supprime une ligne du mod�le de la base de donn�es (chaque ligne du + mod�le dispose de son propre identifiant de base de donn�es) ;
  • +
  • qxDestroyById_() : supprime un �l�ment de la base de donn�es en fonction de + l'identifiant pass� en param�tre (avec prise en compte de la + suppression logique) ;
  • +
  • qxDestroyAll_() : supprime tous les �l�ments de la table de la base de donn�es + associ�e au mod�le (avec prise en compte de la suppression + logique) ;
  • +
  • qxDestroyByQuery_() : supprime les �l�ments de la table de la base de donn�es + associ�e au mod�le en fonction d'une requ�te SQL (avec prise en compte de la suppression logique) ;
  • +
  • qxDestroyRow_() : supprime une ligne du mod�le de la base de donn�es (chaque ligne du + mod�le dispose de son propre identifiant de base de donn�es), avec prise en compte de la suppression logique ;
  • +
  • qxExecuteQuery_() : alimente le mod�le en fonction d'une requ�te SQL personnalis�e ou proc�dure stock�e ;
  • +
  • qxExist_() : teste l'existence d'un �l�ment en fonction de l'identifiant pass� en + param�tre ;
  • +
  • qxValidate_() : teste la validit� de l'int�gralit� du mod�le (module QxValidator) ;
  • +
  • qxValidateRow_() : teste la validit� d'une ligne du mod�le (module QxValidator).
  • +
+
+ Remarque : le projet de test qxBlogModelView pr�sent dans le dossier ./test/ + du package QxOrm montre comment cr�er rapidement un mod�le et l'associer au moteur + model/view de Qt (d'abord dans un widget Qt, puis dans une vue QML). +

+

D�finir un mod�le + "simple" (sans relation)

+
+ Toute classe enregistr�e dans le contexte QxOrm peut �tre utilis�e en tant que mod�le afin + d'alimenter des vues. + La classe de base qx::IxModel des mod�les QxOrm h�rite de la classe Qt QAbstractItemModel : + les mod�les QxOrm sont donc enti�rement compatibles avec le moteur model/view de Qt. +

+ Une seule ligne de code est suffisante pour instancier un mod�le QxOrm : +

+ + + + + + + +
+
   qx::IxModel * pModel = new qx::QxModel<MyClass>();   
+
+
+ Remarque : le mod�le cr�� avec cette ligne de code expose automatiquement toutes les + propri�t�s enregistr�es dans le contexte QxOrm au moteur model/view. +

+
+

Mod�les avec relations + (notion de mod�les imbriqu�s)

+
+ Adapter les relations entre classe (1-n, n-1 ou n-n) au moteur model/view + de Qt est complexe : la solution propos�e par la biblioth�que QxOrm est l'utilisation de mod�les imbriqu�s. + Pour plus de d�tails sur la notion de mod�les imbriqu�s, un tutoriel est disponible sur le site developpez.com. +

+ Pour utiliser les relations (1-n, n-1 ou n-n) avec le module QxModelView, il + est important de comprendre qu'il peut y avoir une hi�rarchie entre mod�les (un mod�le + parent peut avoir plusieurs mod�les enfants associ�s, c'est la notion de mod�les imbriqu�s). +

+ Afin de pouvoir travailler avec des relations (mod�les imbriqu�s), il est n�cessaire de cr�er + des classes mod�les qui h�ritent de : qx::QxModel<T>. + Ainsi, toutes les propri�t�s simples (non relation) sont automatiquement expos�es aux vues + (gr�ce � la classe de base), il reste � �crire uniquement les accesseurs pour acc�der aux + relations. + L'application QxEntityEditor est livr�e avec le plugin QxEECppModelViewExport : + ce plugin g�n�re automatiquement le code source pour pouvoir travailler avec des mod�les + imbriqu�s. +

+ Voici un exemple de code g�n�r� par l'application QxEntityEditor afin de cr�er un mod�le + bas� sur la classe blog (voir le tutoriel + qxBlog pour plus de d�tails). + La classe blog dispose de 3 relations : author (n-1), list_of_comment (1-n) + et list_of_category (n-n) : +

+ * Fichier blog.model_view.gen.h :
+ + + + + + + +
+
namespace model_view {
+
+typedef qx::QxModel<blog> blog_model_base_class;
+
+class QXBLOG_MODEL_VIEW_EXPORT blog_model : public blog_model_base_class
+{
+
+   Q_OBJECT
+
+public:
+
+   blog_model(QObject * parent = 0);
+   blog_model(qx::IxModel * other, QObject * parent);
+   virtual ~blog_model();
+
+   Q_INVOKABLE QObject * author(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+   Q_INVOKABLE QObject * list_of_comment(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+   Q_INVOKABLE QObject * list_of_category(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString());
+
+   /* List of properties exposed by the model (3) :
+      - blog_id
+      - title
+      - text
+   */
+
+protected:
+
+   virtual void syncNestedModel(int row, const QStringList & relation);
+   virtual void syncAllNestedModel(const QStringList & relation);
+
+};
+
+} // namespace model_view
+
+
+ * Fichier blog.model_view.gen.cpp :
+
+
namespace model_view {
+
+blog_model::blog_model(QObject * parent /* = 0 */) : blog_model_base_class(parent) { ; }
+
+blog_model::blog_model(qx::IxModel * other, QObject * parent) : blog_model_base_class(other, parent) { ; }
+
+blog_model::~blog_model() { ; }
+
+QObject * blog_model::author(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "author";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_author value = ptr->getauthor();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getauthor();
+      ptr->setauthor(value);
+   }
+
+   model_view::author_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "author", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+QObject * blog_model::list_of_comment(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "list_of_comment";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_list_of_comment value = ptr->getlist_of_comment();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getlist_of_comment();
+      ptr->setlist_of_comment(value);
+   }
+
+   model_view::comment_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "list_of_comment", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+QObject * blog_model::list_of_category(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */)
+{
+   QString sRelation = "list_of_category";
+   qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation));
+   if (pChild) { return static_cast<QObject *>(pChild); }
+
+   if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { qAssert(false); return NULL; }
+   long id = ptr->getblog_id();
+   blog::type_list_of_category value = ptr->getlist_of_category();
+
+   if (bLoadFromDatabase)
+   {
+      if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; }
+      else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; }
+      blog tmp;
+      tmp.setblog_id(id);
+      this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp);
+      if (this->m_lastError.isValid()) { return NULL; }
+      value = tmp.getlist_of_category();
+      ptr->setlist_of_category(value);
+   }
+
+   model_view::category_model * pNewChild = NULL;
+   pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild);
+   if (pChild) { this->insertChild(row, "list_of_category", pChild); }
+   return static_cast<QObject *>(pChild);
+}
+
+void blog_model::syncNestedModel(int row, const QStringList & relation)
+{
+   Q_UNUSED(relation);
+   qx::IxModel * pNestedModel = NULL;
+   if ((row < 0) || (row >= this->m_model.count())) { return; }
+   blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row);
+   if (! ptr) { return; }
+
+   pNestedModel = this->getChild(row, "author");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_author value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setauthor(value);
+   }
+
+   pNestedModel = this->getChild(row, "list_of_comment");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_list_of_comment value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setlist_of_comment(value);
+   }
+
+   pNestedModel = this->getChild(row, "list_of_category");
+   if (pNestedModel)
+   {
+      this->syncNestedModelRecursive(pNestedModel, relation);
+      blog::type_list_of_category value;
+      qx::model_view::sync_nested_model(pNestedModel, value);
+      ptr->setlist_of_category(value);
+   }
+}
+
+void blog_model::syncAllNestedModel(const QStringList & relation)
+{
+   if (this->m_lstChild.count() <= 0) { return; }
+   for (long l = 0; l < this->m_model.count(); l++)
+   { this->syncNestedModel(static_cast<int>(l), relation); }
+}
+
+} // namespace model_view
+
+

+ Remarque : comme on peut le constater sur l'exemple ci-dessus, le code source � �crire + pour travailler avec des mod�les imbriqu�s est verbeux. + Afin de travailler avec les relations, il est donc fortement recommand� d'utiliser + l'application QxEntityEditor afin de g�n�rer le code source automatiquement. +

+
+

Int�raction avec les vues + QML

+
+ Voici un exemple en QML (en Qt5, le module QxModelView + �tant �galement compatible avec Qt4) qui utilise la table 'author' d�finie dans le tutoriel qxBlog (le code source de cet + exemple QML est disponible dans le projet de test qxBlogModelView pr�sent dans le package + QxOrm) :
+
+ + + + + + + +
+
// Create a model and fetch all data from database
+qx::IxModel * pModel = new qx::QxModel<author>();
+pModel->qxFetchAll();
+
+// Associate the model to a QML view and display it
+QQuickView qmlView;
+qmlView.rootContext()->setContextProperty("myModel", pModel);
+qmlView.setSource(QUrl("qrc:/documents/main.qml"));
+qmlView.show();
+
+
+ Et voici le contenu du fichier 'main.qml' :
+
+ + + + + + + +
+
import QtQuick 2.1
+import QtQuick.Controls 1.0
+
+Item {
+   width: 400
+   height: 300
+   Row {
+      height: 20
+      spacing: 20
+      Button {
+         text: "Clear"
+         onClicked: myModel.clear()
+      }
+      Button {
+         text: "Fetch All"
+         onClicked: myModel.qxFetchAll_()
+      }
+      Button {
+         text: "Save"
+         onClicked: myModel.qxSave_()
+      }
+   }
+   ListView {
+      y: 30
+      height: 270
+      model: myModel
+      delegate: Row {
+         height: 20
+         spacing: 10
+         Text { text: "id: " + author_id }
+         TextField {
+            text: name
+            onTextChanged: name = text
+         }
+      }
+   }
+}
+
+
+ Ce qui donne le r�sultat suivant � l'ex�cution :
+
+ qx_model_view_02
+
+ Remarque : comme on peut le constater dans le fichier 'main.qml', les propri�t�s + 'author_id' et 'name' du mod�le 'author' (variable myModel) sont + accessibles automatiquement en lecture/�criture (car elles ont �t� enregistr�es dans le contexte + QxOrm).
+ De plus, l'interface qx::IxModel propose une liste de m�thodes accessibles en QML (utilisation + de Q_INVOKABLE) pour communiquer directement avec la base de donn�es : ainsi, le bouton + 'Save' de l'�cran ci-dessus enregistre le mod�le en base de donn�es depuis QML. +

+ Autre remarque : un plugin de l'application QxEntityEditor + permet de g�n�rer automatiquement le code des mod�les pour la gestion des relations. Il + est ainsi possible de travailler avec des mod�les imbriqu�s (pour plus de d�tails sur la notion de mod�les + imbriqu�s, rendez-vous sur ce tutoriel du site developpez.com). +

+
+

Int�raction avec les vues + QtWidget

+
+ Voici un exemple de cr�ation d'un mod�le pour afficher/modifier les donn�es de la table + 'author' (voir le tutoriel qxBlog + pour la d�finition de la classe 'author') dans un QTableView (le code source + de cet exemple est disponible dans le projet de test qxBlogModelView pr�sent dans le + package QxOrm) :
+
+ + + + + + + +
+
   // Create a model and fetch all data from database
+   qx::IxModel * pModel = new qx::QxModel<author>();
+   pModel->qxFetchAll();
+
+   // Associate the model to a QTableView and display it   
+   QTableView tableView;
+   tableView.setModel(pModel);
+   tableView.show();
+
+
+ Ce qui donne le r�sultat suivant � l'ex�cution :
+
+ qx_model_view_01
+
+ Remarque : Qt propose par d�faut plusieurs vues QtWidget qui peuvent �tre mapp�es + sur un mod�le, par exemple : QListView, QTableView, QTreeView. + Il est �galement possible d'utiliser la classe QDataWidgetMapper + pour cr�er ses propres formulaires bas�s sur des mod�les (un tutoriel est disponible sur le site developpez.com). +

+
+

Connexion d'un mod�le au + module QxService

+
+ Le module QxModelView + fournit la classe template : qx::QxModelService<T, S> (qui h�rite de : qx::QxModel<T> + >> qx::IxModel + >> QAbstractItemModel). + Cette classe dispose de 2 param�tres template : +
    +
  • T : classe enregistr�e dans le contexte QxOrm dont toutes les propri�t�s sont + expos�es au moteur + model/view de Qt ;
  • +
  • S : classe de services du module QxService pour + acc�der/enregistrer les donn�es du mod�le (requ�tes client/serveur).
  • +
+ Les donn�es propos�es par le mod�le sont ainsi issues de requ�tes client/serveur gr�ce au module QxService (elles ne proviennent pas directement de la base de + donn�es). + La classe de services S doit proposer les m�thodes suivantes : +
    +
  • count() : requ�te client/serveur pour compter le nombre d'�l�ments (avec + possibilit� d'utiliser un filtre SQL) ;
  • +
  • fetchById() : requ�te client/serveur pour alimenter les propri�t�s du mod�le en + fonction de son identifiant ;
  • +
  • fetchAll() : requ�te client/serveur pour alimenter les propri�t�s du mod�le qui + contiendra tous les �l�ments d'une table ;
  • +
  • fetchByQuery() : requ�te client/serveur pour alimenter les propri�t�s du mod�le + qui contiendra les �l�ments filtr�s par une requ�te SQL ;
  • +
  • insert() : requ�te client/serveur pour ins�rer les donn�es du mod�le ;
  • +
  • update() : requ�te client/serveur pour mettre � jour les donn�es du mod�le ;
  • +
  • save() : requ�te client/serveur pour sauvegarder les donn�es du mod�le (insertion + ou mise � jour) ;
  • +
  • deleteById() : requ�te client/serveur pour supprimer un mod�le en fonction de son + identifiant ;
  • +
  • deleteAll() : requ�te client/serveur pour supprimer tous les �l�ments de la table + mapp�e au mod�le ;
  • +
  • deleteByQuery() : requ�te client/serveur pour supprimer tous les �l�ments en + fonction d'une requ�te SQL ;
  • +
  • destroyById() : requ�te client/serveur pour supprimer un mod�le en fonction de son + identifiant (avec prise en compte de la suppression logique) ; +
  • +
  • destroyAll() : requ�te client/serveur pour supprimer tous les �l�ments de la table + mapp�e au mod�le (avec prise en compte de la suppression + logique) ;
  • +
  • destroyByQuery() : requ�te client/serveur pour supprimer tous les �l�ments en + fonction d'une requ�te SQL (avec prise en compte de la suppression + logique) ;
  • +
  • executeQuery() : requ�te client/serveur pour ex�cuter une + requ�te SQL personnalis�e ou proc�dure stock�e ;
  • +
  • exist() : requ�te client/serveur pour tester l'existence du mod�le en fonction de + son identifiant ;
  • +
  • isValid() : requ�te client/serveur pour tester la validit� du mod�le (module QxValidator).
  • +
+
+ Remarque : l'application QxEntityEditor est livr�e avec les plugins + QxEECppServicesExport et QxEECppModelViewExport : ces plugins g�n�rent + automatiquement tout le code source n�cessaire pour travailler avec des mod�les qui utilisent le + module QxService. + Afin de travailler avec la classe qx::QxModelService<T, S>, il est donc fortement recommand� + d'utiliser l'application QxEntityEditor afin de g�n�rer le code source automatiquement. +

+
+
+ +

QxOrm et MongoDB (C++ ODM + Object Document Mapper)

+
+ En plus des bases de donn�es relationnelles classiques (MySQL, PostgreSQL, SQLite, Oracle, + Microsoft SQLServer, MariaDB, etc...), la biblioth�que QxOrm supporte �galement la base de donn�es MongoDB. +

+ D�finition du site Wikipedia : + MongoDB est un syst�me de gestion de base de donn�es orient�e documents, r�partissable sur un + nombre quelconque d'ordinateurs et ne n�cessitant pas de sch�ma pr�d�fini des donn�es. + Il fait partie de la mouvance NoSQL. +

+ La base de donn�es MongoDB pr�sente de nombreux avantages par rapport � une base de donn�es + relationnelle classique (liste non exhaustive) : +
    +
  • Aucun sch�ma � d�finir : il est inutile d'avoir � maintenir des tables et colonnes + (donc fini les scripts complexes pour migrer la base de donn�es d'une version � une autre). + Les Collections MongoDB peuvent contenir des Documents avec diff�rents champs, + diff�rentes tailles, etc... Concernant QxOrm, �a signifie que vous pouvez faire �voluer vos + classes C++ sans vous soucier d'un sch�ma DDL � maintenir d'une version � une autre (convient + parfaitement dans un environnement de d�veloppement AGILE par exemple) ;
  • +
  • Les donn�es sont stock�es dans un format BSON (correspond � du JSON) : facile � lire + m�me avec des structures de donn�es complexes ;
  • +
  • Moteur de requ�tes (JSON) tr�s puissant avec possibilit� de positionner des index sur + n'importe qu'elle propri�t� d'un Document ;
  • +
  • La base de donn�es est gratuite, et propose un support pour les professionnels + ;
  • +
  • Depuis la version 3.6 de MongoDB : le moteur de requ�tes permet de cr�er des + jointures (entre Documents) de mani�re �quivalente � une base de donn�es + relationnelle classique. +
  • +
+
+ L'utilisation de la biblioth�que QxOrm avec MongoDB est tr�s proche des bases de donn�es + relationnelles classiques. + Toutes les fonctionnalit�s de la biblioth�que QxOrm sont support�es avec MongoDB : donc tout ce qui + se trouve dans ce manuel utilisateur est disponible avec une base de donn�es MongoDB. + Les principales diff�rences � prendre en compte sont : + +
+ Remarque : le package QxOrm fournit un projet de test nomm� qxBlogMongoDB (dans le + dossier ./test/). + Ce projet montre comment se connecter � une base de donn�es MongoDB avec la biblioth�que QxOrm. +

+

Pr�-requis : driver + libmongoc et libbson

+
+ Le module QtSql fourni par + le framework Qt sur lequel est bas� la biblioth�que QxOrm ne propose pas de connecteur � une + base de donn�es MongoDB. + La biblioth�que QxOrm a donc besoin de 2 d�pendances suppl�mentaires pour se connecter � une + base MongoDB : + +
+ Un guide + d'installation est disponible pour installer ces 2 biblioth�ques sur votre environnement + de d�veloppement. +

+
+

Param�trage du fichier + QxOrm.pri (ou QxOrm.cmake)

+
+ Une fois que les biblioth�ques libmongoc et libbson sont correctement install�es + sur votre environnement de d�veloppement, il est n�cessaire de param�trer le fichier de + configuration QxOrm.pri (ou QxOrm.cmake) en activant l'option de compilation + _QX_ENABLE_MONGODB. +

+ + + + + + + +
+
#######################################
+# MongoDB Driver Library Dependencies #
+#######################################
+
+# If you enable _QX_ENABLE_MONGODB option, then QxOrm library will be able to use mongoc driver to store all QxOrm registered classes in a MongoDB database
+# When _QX_ENABLE_MONGODB compilation option is defined, you must provide following paths to manage mongoc library dependencies :
+#  - a BSON_INCLUDE environment variable to define where bson library source code is located (or a QX_BSON_INCLUDE_PATH qmake variable)
+#  - a MONGOC_INCLUDE environment variable to define where mongoc library source code is located (or a QX_MONGOC_INCLUDE_PATH qmake variable)
+#  - a BSON_LIB environment variable to define where bson library is located (or a QX_BSON_LIB_PATH qmake variable)
+#  - a MONGOC_LIB environment variable to define where mongoc library is located (or a QX_MONGOC_LIB_PATH qmake variable)
+
+

+ Remarque : une fois l'option de compilation _QX_ENABLE_MONGODB activ�e, il est + possible de compiler et ex�cuter le projet de test qxBlogMongoDB du dossier + ./test/ afin de valider l'environnement de d�veloppement. +

+
+

Connexion � la base de + donn�es MongoDB

+
+ Voici un exemple de param�trage pour se connecter � une base de donn�es MongoDB : +

+ + + + + + + +
+
// Parameters to connect to MongoDB database
+qx::QxSqlDatabase * pDatabase = qx::QxSqlDatabase::getSingleton();
+pDatabase->setDriverName("QXMONGODB");
+pDatabase->setDatabaseName("qxBlog");
+pDatabase->setHostName("localhost");
+pDatabase->setPort(27017);
+pDatabase->setUserName("");
+pDatabase->setPassword("");
+
+

+
+

D�finition d'une classe + persistante MongoDB (Collection) dans le contexte QxOrm (mapping)

+
+ D�clarer une classe persistante MongoDB dans le contexte QxOrm est �quivalent � d�clarer une classe persistante pour une base de donn�es relationnelle + classique. + Voici un exemple du projet de test qxBlogMongoDB : +

+ Fichier blog.h : + + + + + + + +
+
#ifndef _QX_BLOG_BLOG_H_
+#define _QX_BLOG_BLOG_H_
+
+#include "author.h"
+#include "comment.h"
+#include "category.h"
+
+class QX_BLOG_DLL_EXPORT blog
+{
+public:
+// -- properties
+   QString        m_id;
+   QString        m_text;
+   QDateTime      m_dt_creation;
+   author_ptr     m_author;
+   list_comment   m_commentX;
+   list_category  m_categoryX;
+// -- contructor, virtual destructor
+   blog() { ; }
+   virtual ~blog() { ; }
+};
+
+QX_REGISTER_PRIMARY_KEY(blog, QString)
+QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)
+
+typedef std::shared_ptr<blog> blog_ptr;
+typedef std::vector<blog_ptr> list_blog;
+
+#endif // _QX_BLOG_BLOG_H_
+
+
+ Fichier blog.cpp : + + + + + + + +
+
#include "../include/precompiled.h"
+#include "../include/blog.h"
+#include <QxOrm_Impl.h>
+
+QX_REGISTER_CPP_QX_BLOG(blog)
+
+namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   t.id(& blog::m_id, "blog_id");
+
+   t.data(& blog::m_text, "blog_text");
+   t.data(& blog::m_dt_creation, "date_creation");
+   t.data(& blog::m_categoryX, "list_category"); // Embedded relationship
+
+   t.relationManyToOne(& blog::m_author, "author_id"); // Referenced relationship
+   t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); // Referenced relationship
+}}
+
+
+ Remarque : l'exemple ci-dessus montre comment d�finir : + +
+

Gestion des cl�s + primaires ObjectId

+
+ Comme indiqu� en jaune dans l'exemple pr�c�dent, il est conseill� de d�finir en C++ une cl� + primaire de type QString. + Il n'y a pas de notion de cl� num�rique auto-incr�ment�e : MongoDB + utilise un type ObjectId qui peut �tre mapp� en C++ avec QString et g�n�r� + automatiquement (il est �galement possible de d�finir son propre type C++ pour mapper un + ObjectId MongoDB). +

+
+
+

Ins�rer une instance C++ + (Document) dans la base de donn�es MongoDB (INSERT)

+
+ Voici un exemple d'insertion de document avec g�n�ration automatique de la cl� primaire (de type + MongoDB + ObjectId) : +

+ + + + + + + +
+
// Insert one author without id
+author_ptr author_1 = std::make_shared<author>();
+author_1->m_name = "author_1";
+author_1->m_sex = author::male;
+author_1->m_birthdate = QDate(1998, 07, 12);
+daoError = qx::dao::insert(author_1);
+
+

+ Voici un exemple d'insertion de document avec une cl� primaire personnalis�e : +

+ + + + + + + +
+
// Insert one author with a custom id
+author_ptr author_2 = std::make_shared<author>();
+author_2->m_id = "my_custom_id_author_2";
+author_2->m_name = "author_2";
+author_2->m_sex = author::female;
+author_2->m_birthdate = QDate(2003, 02, 28);
+daoError = qx::dao::insert(author_2);
+
+

+

Ins�rer une liste + d'instances C++ (plusieurs Documents) dans la base de donn�es MongoDB (INSERT)

+
+ Voici un exemple d'insertion de plusieurs documents dans la base de donn�es MongoDB : +

+ + + + + + + +
+
// Insert many authors with/without ids
+QList<author> authorX;
+author author_3; author_3.m_name = "author_3"; author_3.m_sex = author::female; author_3.m_birthdate = QDate(1968, 05, 01);
+author author_4; author_4.m_id = "my_custom_id_author_4"; author_4.m_name = "author_4"; author_4.m_sex = author::male;
+author author_5; author_5.m_name = "author_5"; author_5.m_sex = author::female; author_5.m_birthdate = QDate(1978, 03, 03);
+authorX.append(author_3); authorX.append(author_4); authorX.append(author_5);
+daoError = qx::dao::insert(authorX);
+
+

+ Remarque : QxOrm supporte plusieurs types C++ de listes / + collections. +

+
+
+

Mettre � jour une + instance C++ (Document) dans la base de donn�es MongoDB (UPDATE)

+
+ Voici un exemple de mise � jour d'un document dans la base MongoDB : +

+ + + + + + + +
+
// Update one author
+author author_4;
+author_4.m_id = "my_custom_id_author_4";
+author_4.m_name = "author_4_modified";
+daoError = qx::dao::update(author_4);
+
+

+

Mettre � jour une + liste d'instances C++ (plusieurs Documents) dans la base de donn�es MongoDB (UPDATE) +

+
+ Voici un exemple de mise � jour de plusieurs documents dans la base MongoDB : +

+ + + + + + + +
+
// Update many authors
+QList<author> authorX;
+author_3.m_name = "author_3_modified_twice"; authorX.append(author_3);
+author_2->m_name = "author_2_modified"; authorX.append(* author_2);
+author_1->m_name = "author_1_modified"; authorX.append(* author_1);
+daoError = qx::dao::update(authorX);
+
+

+ Remarque : QxOrm supporte plusieurs types C++ de listes / + collections. +

+
+
+

Supprimer une instance + C++ (Document) de la base de donn�es MongoDB (DELETE)

+
+ Voici un exemple de suppression d'un document de la base MongoDB : +

+ + + + + + + +
+
// Delete one author by id
+author_ptr pAuthor = std::make_shared<author>();
+pAuthor->m_id = "my_custom_id_author_4";
+daoError = qx::dao::delete_by_id(pAuthor);
+
+

+

Supprimer une liste + d'instances C++ (plusieurs Documents) de la base de donn�es MongoDB (DELETE)

+
+ Voici un exemple de suppression de plusieurs documents de la base MongoDB par identifiant + (cl� primaire) : +

+ + + + + + + +
+
// Delete many authors by id
+QList<author> authorX;
+author_3.m_id = "id_author_3"; authorX.append(author_3);
+author_2->m_id = "id_author_2"; authorX.append(* author_2);
+author_1->m_id = "id_author_1"; authorX.append(* author_1);
+daoError = qx::dao::delete_by_id(authorX);
+
+

+ Voici un exemple de suppression de plusieurs documents de la base MongoDB par requ�te JSON : +

+ + + + + + + +
+
// Delete authors by query (all male)
+qx_query query{ { "sex", author::male } };
+daoError = qx::dao::delete_by_query<author>(query);
+
+

+ Pour supprimer tous les documents de la Collection author : +

+ + + + + + + +
+
// Delete all authors
+daoError = qx::dao::delete_all<author>();
+
+

+ Remarque : QxOrm supporte plusieurs types C++ de listes / + collections. +

+
+
+

R�cup�rer une instance + C++ (Document) de la base de donn�es MongoDB (FETCH)

+
+ Voici un exemple pour r�cup�rer (FETCH) un document de la base MongoDB par identifiant (cl� + primaire) : +

+ + + + + + + +
+
// Fetch one author by id
+author_ptr pAuthor = std::make_shared<author>();
+pAuthor->m_id = "my_custom_id_author_2";
+daoError = qx::dao::fetch_by_id(pAuthor);
+
+

+

R�cup�rer une liste + d'instances C++ (plusieurs Documents) de la base de donn�es MongoDB (FETCH)

+
+ Voici un exemple pour r�cup�rer (FETCH) plusieurs documents de la base MongoDB par + identifiant (cl� primaire) : +

+ + + + + + + +
+
// Fetch many authors by id
+QList<author> authorX;
+author_3.m_id = "id_author_3"; authorX.append(author_3);
+author_2->m_id = "id_author_2"; authorX.append(* author_2);
+author_1->m_id = "id_author_1"; authorX.append(* author_1);
+daoError = qx::dao::fetch_by_id(authorX);
+
+

+ Voici un exemple pour r�cup�rer (FETCH) plusieurs documents de la base MongoDB par requ�te JSON : +

+ + + + + + + +
+
// Fetch many authors by query (only female)
+list_author list_of_female_author;
+qx_query query{ { "sex", author::female } };
+daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+
+

+ Voici un exemple pour r�cup�rer (FETCH) tous les documents de la Collection author de + la base MongoDB : +

+ + + + + + + +
+
// Fetch all authors
+list_author allAuthors;
+daoError = qx::dao::fetch_all(allAuthors);
+
+

+ Voici un exemple pour r�cup�rer (FETCH) tous les documents de la Collection author de + la base MongoDB (en s�lectionnant les propri�t�s/colonnes � r�cup�rer) : +

+ + + + + + + +
+
// Fetch all authors (with only 'date_creation' and 'name' properties)
+list_author allAuthors;
+QStringList columns = QStringList() << "date_creation" << "name";
+daoError = qx::dao::fetch_all(allAuthors, NULL, columns);
+
+

+ Remarque : QxOrm supporte plusieurs types C++ de listes / + collections. +

+
+
+

Requ�tes JSON

+
+ La principale diff�rence entre une base de donn�es relationnelle classique et MongoDB est la + fa�on de requ�ter les donn�es : � la place du SQL, MongoDB propose un moteur de + requ�te JSON. +

+

Utilisation de la + classe qx::QxSqlQuery (ou son alias qx_query)

+
+ La classe qx::QxSqlQuery (ou son alias qx_query) utilis�e pour + construire du SQL classique est �galement compatible pour construire des requ�tes JSON + MongoDB. + Cette classe utilise la fonctionnalit� C++11 std::initializer_list afin d'�crire les + requ�tes en C++ avec une syntaxe proche du JSON (il est �galement possible d'�crire la + requ�te sous forme de cha�ne de caract�res). + Par exemple : +

+ + + + + + + +
+
// Fetch many authors by query (only female)
+list_author list_of_female_author;
+qx_query query { { "sex", author::female } };
+daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+
+

+
+

Utiliser le moteur + d'aggregation MongoDB

+
+ La base de donn�es MongoDB fournit �galement un puissant moteur + d'aggregation qui �tend encore plus les possibilit�s pour requ�ter les donn�es. + Voici comment utiliser ce moteur d'aggregation avec la classe qx::QxSqlQuery (ou son alias qx_query), le 1er param�tre du + constructeur doit �tre �gal � aggregate : +

+ + + + + + + +
+
// Fetch by query using MongoDB aggregation framework (only female)
+list_author list_of_female_author;
+qx_query queryAggregate("aggregate",
+               "[ { \"$match\" : { \"sex\" : " + QString::number(static_cast<int>(author::female)) + " } } ]");
+daoError = qx::dao::fetch_by_query(queryAggregate, list_of_female_author);
+
+

+
+

Ajouter des + propri�t�s � la requ�te de type : 'sort', 'limit', 'skip', etc...

+
+ Il est souvent n�cessaire de limiter les donn�es, ou bien de les trier par exemple. + Pour effectuer ces op�rations, la base de donn�es MongoDB utilise la notion de projection. + Voici un exemple d'utilisation avec la classe qx::QxSqlQuery (ou son + alias qx_query), avec une QStringList en constructeur (ou bien 2�me param�tre std::initializer_list) : +

+ + + + + + + +
+
// Fetch by query (only female) adding 'sort', 'limit', 'skip', etc... commands (see second query QStringList parameter)
+list_of_female_author.clear();
+qx_query queryOpts(QStringList() << "{ \"sex\" : " + QString::number(static_cast(author::female)) + " }"
+                              << "{ \"sort\" : { \"sex\" : -1 }, \"limit\" : 2 }");
+daoError = qx::dao::fetch_by_query(queryOpts, list_of_female_author);
+
+

+
+

Ex�cuter une requ�te + personnalis�e

+
+ Il est possible d'ex�cuter une requ�te personnalis�e avec la fonction + qx::dao::call_query(). + Le r�sultat de la requ�te peut �tre facilement convertie en QVariantMap ou bien + QList<QVariantMap> (si la requ�te retourne un curseur) afin de faciliter la + lecture des r�sultats de la requ�te personnalis�e. + Voici quelques exemples d'appels de requ�tes personnalis�es : +

+ + + + + + + +
+
// Drop database
+qx_query dropDB("{ \"dropDatabase\" : 1 }");
+QSqlError daoError = qx::dao::call_query(dropDB);
+
+

+ + + + + + + +
+
// Call a custom query and get JSON response as QVariantMap
+qx_query customQuery("{ \"find\": \"author\", \"filter\": { } }");
+daoError = qx::dao::call_query(customQuery); qAssert(! daoError.isValid());
+QString responseCustomQuery = customQuery.response().toString();
+QVariantMap responseCustomQueryAsJson;
+qx::serialization::json::from_string(responseCustomQueryAsJson, responseCustomQuery);
+
+

+ + + + + + + +
+
// Call a custom query with cursor and get JSON response as QList<QVariantMap>
+qx_query customQueryCursor("cursor", "{ \"find\": \"author\", \"filter\": { } }");
+daoError = qx::dao::call_query(customQueryCursor); qAssert(! daoError.isValid());
+QString responseCustomQueryCursor = customQueryCursor.response().toString();
+QList<QVariantMap> responseCustomQueryCursorAsJson;
+qx::serialization::json::from_string(responseCustomQueryCursorAsJson, responseCustomQueryCursor);
+
+

+
+
+

Moteur de relations + (n�cessite une version MongoDB 3.6 ou +)

+
+ Le moteur de relations de la biblioth�que QxOrm est compatible avec la + base de donn�es MongoDB (version 3.6 minimale). + QxOrm est donc capable de r�cup�rer les donn�es d'un Document sur plusieurs Collections en une + seule requ�te. +

+ Voici un exemple pour r�cup�rer un Document et toutes ses relations sur 1 niveau de profondeur + (parent > enfants) : +

+ + + + + + + +
+
// Fetch blog with all relations : 'author', 'comment' and 'category' (MongoDB version 3.6+ is required for relationships)
+blog_ptr blog = std::make_shared<blog>();
+blog->m_id = "id_blog_1";
+daoError = qx::dao::fetch_by_id_with_all_relation(blog);
+
+

+ Voici un exemple pour r�cup�rer un Document et toutes ses relations sur 4 niveaux de profondeur + (utilisation de la syntaxe *->*->*->*) : +

+ + + + + + + +
+
// Fetch blog with many relations using "*->*->*->*" (4 levels of relationships)
+blog_ptr blog = std::make_shared<blog>();
+blog->m_id = "id_blog_1";
+daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog);
+
+

+ Voici un exemple pour r�cup�rer un Document en s�lectionnant les relations et propri�t�s � + alimenter (utilisation de la syntaxe { <col_1>, <col_2>, etc... }) : +

+ + + + + + + +
+
// Fetch relations defining fields to fetch with syntax { col_1, col_2, etc... }
+list_blog lstBlogComplexRelation;
+QStringList relations = QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *";
+daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation);
+
+

+ Voici un exemple pour r�cup�rer un Document en s�lectionnant les relations et les propri�t�s � + ne pas alimenter (utilisation de la syntaxe -{ <col_1>, <col_2>, etc... }) : +

+ + + + + + + +
+
// Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... }
+list_blog lstBlogComplexRelation2;
+QStringList relations = QStringList() << "-{ blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *";
+daoError = qx::dao::fetch_all_with_relation(relations, lstBlogComplexRelation2);
+
+

+

Relations : Embedded + vs Referenced

+
+ Un des points forts de la base de donn�es MongoDB est de pouvoir stocker des structures + complexes de donn�es (on n'est pas limit� � une structure en tableau table/colonne des bases + de donn�es relationnelles classiques). + Un Document MongoDB peut donc contenir un objet et plusieurs sous-objets (notion de + hi�rarchie dans la structure du Document). + Inclure un sous-objet dans un m�me Document pr�sente des avantages (aucune jointure par + exemple, donc plus rapide � r�cup�rer) et inconv�nients (un m�me objet peut �tre dupliqu� + plusieurs fois dans la base). + Il est donc important de r�fl�chir sur la strat�gie � adopter pour stocker les donn�es. +

+ La biblioth�que QxOrm supporte les 2 fa�ons de proc�der : +
    +
  • Embedded relation : le sous-objet est inclu dans le Document ;
  • +
  • Referenced relation : cr�� une jointure comme dans une base de donn�es + relationnelle classique.
  • +
+
+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   t.id(& blog::m_id, "blog_id");
+
+   t.data(& blog::m_text, "blog_text");
+   t.data(& blog::m_dt_creation, "date_creation");
+   t.data(& blog::m_categoryX, "list_category"); // Embedded relationship
+
+   t.relationManyToOne(& blog::m_author, "author_id"); // Referenced relationship
+   t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); // Referenced relationship
+}}
+
+

+
+
+

Cr�ation automatique des + index

+
+ La biblioth�que QxOrm fournit une m�thode pour g�n�rer automatiquement les index (cette fonction + peut �tre appel�e en d�but de programme, par exemple dans le main) : +
    +
  • les index li�s aux relations entre les Collections (pour optimiser les jointures) ;
  • +
  • les index d�finis par la m�thode qx::IxDataMember::setIndex() (dans la fonction + qx::register_class()). +
  • +
+
+ + + + + + + +
+
// To optimize queries : create automatically indexes based on relationships and properties marked as 'index'
+daoError = qx::dao::mongodb::QxMongoDB_Helper::autoCreateIndexes(true);
+
+

+
+
+ +

Serveur web HTTP/HTTPS + (module QxHttpServer)

+
+ La biblioth�que QxOrm fournit un serveur web compatible HTTP 1.1 autonome (aucune n�cessit� + d'installer une application tierce comme Apache ou Nginx), + performant (multi-thread) et simple d'utilisation : il s'agit du module QxHttpServer (bas� + sur le module QxService). +

+ Le module QxHttpServer supporte de nombreuses fonctionnalit�s : + + Combin� avec le module QxRestApi (qui propose une API JSON pour requ�ter + les donn�es persistantes), le module QxHttpServer est particuli�rement adapt� pour + d�velopper des applications web modernes. + Par exemple, des applications web de type SPA (Single-Page + Applications) avec les c�l�bres frameworks Javascript comme AngularJS, React, Meteor.js, + etc... +

+ Remarque : pour activer le module QxHttpServer, il faut d�finir l'option de + compilation _QX_ENABLE_QT_NETWORK dans le fichier de configuration QxOrm.pri (ou QxOrm.cmake). + Cette option de compilation ajoute une d�pendance au binaire QtNetwork fourni avec la + biblioth�que Qt. +

+ Autre remarque : le package QxOrm est livr� avec le projet de test + qxBlogRestApi. + Ce projet de test est une application web avec de nombreux exemples pour requ�ter les donn�es + persistantes depuis une page web (HTML et Javascript). +

+

Hello World !

+
+ Voici le code source d'une application web bas�e sur le module QxHttpServer (cette + application renvoie Hello World ! au navigateur web client) : +

+ + + + + + + +
+
#include <QtCore/qcoreapplication.h>
+#include <QxOrm.h>
+
+int main(int argc, char * argv[])
+{
+   QCoreApplication app(argc, argv);
+
+   // HTTP server settings
+   qx::service::QxConnect * serverSettings = qx::service::QxConnect::getSingleton();
+   serverSettings->setPort(9642); // HTTP server listening port
+   serverSettings->setKeepAlive(5000); // Keep-alive connection with client during 5s, then socket is disconnected and thread becomes available for other clients
+   serverSettings->setThreadCount(50); // Number of threads waiting for client's requests,
+                                                           // which means also how many requests can be handled simultaneously (in parallel) by HTTP server
+
+   // Create a QxOrm HTTP server instance
+   qx::QxHttpServer httpServer;
+
+   // Define all HTTP server routes (dispatcher) to handle requests
+   // Each callback is executed in a dedicated thread, so QxOrm HTTP server can handle several requests in parallel
+   httpServer.dispatch("GET", "/", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+      response.data() = "Hello World !";
+   });
+
+   // Start HTTP server
+   httpServer.startServer();
+
+   // Start event loop
+   return app.exec();
+}
+
+

+ R�sultat : ouvrir un navigateur web (Chrome, Firefox, Safari, Internet Explorer, Opera, + etc...) et aller � l'adresse http://localhost:9642/, l'�cran suivant doit + apparaitre : +

+ QxHttpServer Hello World ! +

+
+

Param�trage du serveur + web HTTP

+
+ Les param�tres du serveur web HTTP sont accessibles avec la classe singleton qx::service::QxConnect : +
    +
  • setPort() : port d'�coute du serveur web (un serveur web classique �coute sur le + port 80 mais vous pouvez d�finir une autre valeur) ;
  • +
  • setThreadCount() : nombre de threads utilis�s par le serveur web pour traiter les + requ�tes HTTP (nombre de connexions clientes simultan�es) ;
  • +
  • setMaxWait() : temps d'attente maximum en milli-secondes (par exemple lecture ou + �criture sur la socket), la valeur -1 signifie attendre ind�finiment ;
  • +
  • setCompressData() : si le client HTTP supporte la compression GZIP, alors les + r�ponses de type texte (fichier HTML / Javascript / CSS, flux JSON, etc...) seront + compress�s au format GZIP ;
  • +
  • setKeepAlive() : la socket avec le client reste connect�e pendant le laps de temps + d�fini par cette fonction (en milli-secondes), la valeur -1 signifie ne jamais se + d�connecter ;
  • +
  • setSessionTimeOut() : indique le temps d'attente (en milli-secondes) avant de + d�truire une session (stockage par client c�t� serveur) non + utilis�e.
  • +
+
+

Connexions s�curis�es + SSL/TLS

+
+ La classe singleton qx::service::QxConnect fournit �galement des param�tres pour g�rer les + connexions s�curis�es HTTPS (SSL et/ou TLS).
+ Voici un exemple de param�trage de connexions s�curis�es avec certificat serveur et autorit� + de certification (voir le projet de test + qxBlogRestApi pour tester ce code) : +

+ + + + + + + +
+
// Certificates created with this tutorial : https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/
+QFile::copy(":/documents/cert_qxorm_ca.pem", appPath.filePath("files/cert_qxorm_ca.pem"));
+QFile::copy(":/documents/cert_qxorm_server.crt", appPath.filePath("files/cert_qxorm_server.crt"));
+QFile::copy(":/documents/cert_qxorm_server.key", appPath.filePath("files/cert_qxorm_server.key"));
+
+QFile fileCertCA(appPath.filePath("files/cert_qxorm_ca.pem"));
+fileCertCA.open(QIODevice::ReadOnly);
+QList<QSslCertificate> certCA; certCA << QSslCertificate(fileCertCA.readAll());
+
+QFile fileCertServerPublic(appPath.filePath("files/cert_qxorm_server.crt"));
+fileCertServerPublic.open(QIODevice::ReadOnly);
+QSslCertificate certServerPublic(fileCertServerPublic.readAll());
+
+QFile fileCertServerPrivate(appPath.filePath("files/cert_qxorm_server.key"));
+fileCertServerPrivate.open(QIODevice::ReadOnly);
+QSslKey certServerPrivate(fileCertServerPrivate.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "qxorm");
+
+qx::service::QxConnect * serverSettings = qx::service::QxConnect::getSingleton();
+serverSettings->setSSLEnabled(true);
+serverSettings->setSSLCACertificates(certCA);
+serverSettings->setSSLLocalCertificate(certServerPublic);
+serverSettings->setSSLPrivateKey(certServerPrivate);
+
+
+

+ Remarque : par d�faut, toutes les erreurs SSL sont ignor�es (erreurs souvent li�es � + des probl�mes de certificats). + Pour adapter votre serveur web � vos normes de s�curit�, vous pouvez utiliser les fonctions + suivantes (classe singleton qx::service::QxConnect) : + +
+
+
+

Routage des URL (d�finir + les endpoints / dispatcher)

+
+ Le module QxHttpServer fournit un moteur de routage des URL (dispatcher) pour + d�finir les fonctions (ou lambda) � ex�cuter en fonction des param�tres de la requ�te HTTP + (m�thode HTTP GET, POST, DELETE, etc... + URL demand�e).
+ Les fonctions (ou lambda) doivent avoir cette signature : + void myRequestHandler(qx::QxHttpRequest & request, qx::QxHttpResponse & response); + +

+ La classe qx::QxHttpServer (ou son alias qx_http_server) dispose des m�thodes suivantes : +
    +
  • setCustomRequestHandler() : d�fini une fonction (ou lambda) ex�cut�e si aucune + autre fonction n'a �t� trouv�e par le dispatcher ;
  • +
  • dispatch() : le 1er param�tre correspond � la m�thode HTTP (GET, POST, DELETE, + etc...), le 2�me param�tre correspond � l'URL demand�e (ou son pattern), le 3�me + param�tre correpond � la fonction (ou lambda) � ex�cuter ;
  • +
  • beforeDispatching() : fonction (ou lambda) ex�cut�e avant de traiter la requ�te + HTTP (peut �tre utile par exemple pour tracer des logs, ou bien mettre en place un syst�me + d'authentification) ;
  • +
  • afterDispatching() : fonction (ou lambda) ex�cut�e apr�s le traitement de la + requ�te HTTP (peut �tre utile par exemple pour tracer des logs) ;
  • +
  • clearDispatcher() : n�ttoie toutes les r�gles de routage (seule la fonction ou + lambda d�finie par setCustomRequestHandler() sera ex�cut�e).
  • +
+ Remarque : le dispatcher est thread-safe, vous pouvez donc red�finir les r�gles de + routage des URL m�me si le serveur web est en cours d'ex�cution. +

+ Autre remarque : chaque fonction (ou lambda) est + ex�cut�e dans son propre thread + . + Le serveur web HTTP fourni par la biblioth�que QxOrm peut donc g�rer plusieurs requ�tes HTTP + simultan�ment. +

+ Exemple n�1 : cette r�gle de routage intercepte toutes les requ�tes de type GET + dont l'URL commence par /files/, et renvoie comme r�ponse le contenu d'un fichier + statique stock� sur le serveur (QDir::currentPath() indique le r�pertoire parent du + stockage des fichiers statiques, et 5000 correspond � la taille pour l'envoi des fichiers + par bloc / chunked response, ce dernier param�tre �tant optionnel) : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/files/*", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseStaticFile(request, response, QDir::currentPath(), 5000);
+});
+
+

+ Exemple n�2 : cette r�gle de routage intercepte toutes les requ�tes de type POST + dont l'URL est /qx, et utilise le module QxRestApi (qui propose + une API JSON pour requ�ter les donn�es persistantes). + Ces 2 exemples (avec l'exemple n�1 qui renvoie des fichiers statiques) sont suffisants pour + d�marrer une application web de type SPA (Single-Page Applications) avec les c�l�bres + frameworks Javascript comme AngularJS, React, Meteor.js, etc... +

+ + + + + + + +
+
httpServer.dispatch("POST", "/qx", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseQxRestApi(request, response);
+});
+
+

+ Exemple n�3 : cette r�gle de routage intercepte toutes les requ�tes de type GET + dont l'URL est /test_big_json, et construit une r�ponse de type JSON contenant un tableau + de 10000 �l�ments : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/test_big_json", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   // To compare with this benchmark : https://blog.binaryspaceship.com/2017/cpp-rest-api-frameworks-benchmark/
+   // This is more a JSON benchmark than HTTP server benchmark (RapidJSON is faster than Qt QJson engine)
+   QJsonArray arr; Q_UNUSED(request);
+   for (int i = 0; i < 10000; ++i)
+   {
+      QJsonObject item;
+      item.insert("id", QString::number(i));
+      item.insert("name", QString("Hello World"));
+      item.insert("type", QString("application"));
+      arr.append(item);
+   }
+   QJsonDocument doc(arr);
+   response.headers().insert("Content-Type", "application/json; charset=utf-8");
+   response.data() = doc.toJson(QJsonDocument::Compact);
+});
+
+

+ Remarque : l'ordre dans lequel est appel� les diff�rentes fonctions dispatch() est + important. + Le 1er �l�ment trouv� par le dispatcher correspondant � l'URL demand�e est ex�cut� (et ignore + les �l�ments suivants). + Il est donc indispensable de d�finir en 1er les URL les plus sp�cifiques, jusqu'aux URL les plus + g�n�riques (par exemple, le pattern correspondant � toutes les URL est /*). +

+

Routage dynamique des + URL

+
+ Le dispatcher du module QxHttpServer supporte �galement la notion de routage dynamique + des URL.
+ Il est possible de d�finir des variables au niveau de l'URL � router avec la syntaxe : <var_name:var_type> (var_type + �tant optionnel, et peut prendre comme valeur : int, long, float, double, string). +

+ Le routage dynamique est particuli�rement utile pour mettre en place une API REST.
+ Par exemple, le pattern /blog/<blog_id:int> associ� � la m�thode HTTP GET + peut �tre utilis� pour r�cup�rer les donn�es d'un blog en fonction de son identifiant de type + num�rique (fetch_by_id). +

+ Il faut voir l'URL comme une liste de segments dont le s�parateur est le caract�re + /.
+ Le dispatcher v�rifie que chaque segment de l'URL demand�e correspond au pattern utilis� afin + de valider une fonction (ou lambda) � ex�cuter.
+ Pour r�cup�rer les valeurs des param�tres de l'URL, il faut utiliser : request.dispatchParams().value("var_name") + (retourne un QVariant). +

+ Exemple : la r�gle de routage suivante intercepte toutes les requ�tes de type + GET dont l'URL commence /params/, suivi par un segment qui sera associ� � la + variable var1, suivi par un segment de type num�rique associ� � la variable + var2. + Elle construit une r�ponse qui renvoie la valeur des 2 param�tres var1 et var2. + Si le navigateur web appelle l'URL /params/abc/123/ alors la fonction (ou lambda) sera + ex�cut�e, par contre si le navigateur web appelle l'URL /params/abc/def/ alors la + fonction (ou lambda) ne sera pas ex�cut�e (car def n'est pas num�rique) et cherchera + un autre �l�ment du dispatcher : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/params/<var1>/<var2:int>", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   response.data() = "Test URL dispatch parameters :\r\n";
+   response.data() += " - var1 = " + request.dispatchParams().value("var1").toByteArray() + "\r\n";
+   response.data() += " - var2 = " + request.dispatchParams().value("var2").toByteArray() + "\r\n";
+});
+
+

+ Remarque : il est �galement possible de d�finir une expression r�guli�re pour router + les URL avec la syntaxe : + <var_name:{my_reg_exp}> + . +

+
+
+

R�cup�rer les param�tres + de la requ�te HTTP

+
+ La classe qx::QxHttpRequest (ou son alias qx_http_request) contient tous les param�tres d'appel de la + requ�te HTTP : +
    +
  • QUrl & url() : URL demand�e par le navigateur web client ;
  • +
  • QString & command() : m�thode HTTP utilis�e par le navigateur web client (GET, + POST, PUT, DELETE, etc...) ;
  • +
  • QString & version() : version HTTP fournie par le navigateur web client (en + g�n�ral HTTP/1.1) ;
  • +
  • QByteArray & data() : contenu de la requ�te HTTP ;
  • +
  • QByteArray header(const QByteArray & key) : permet de r�cup�rer la valeur d'un + en-t�te HTTP fourni par le navigateur web client (par exemple : + request.header("Accept-Encoding")) ; +
  • +
  • QxHttpCookie cookie(const QByteArray & name) : permet de r�cup�rer la valeur d'un + cookie HTTP fourni par le navigateur web client ; +
  • +
  • QString param(const QString & key) : permet de r�cup�rer la valeur d'un param�tre + de la requ�te HTTP (fourni soit dans l'URL, soit dans le contenu si l'en-t�te HTTP + 'content-type' est 'application/x-www-form-urlencoded') ; +
  • +
  • QHash<QString, QVariant> & dispatchParams() : liste des param�tres + dynamiques de l'URL calcul�s par le routage/dispatcher ;
  • +
  • QString & sourceAddress() : adresse IP du navigateur web client ;
  • +
  • long & sourcePort() : port utilis� par le navigateur web client ;
  • +
  • QString guid() : identifiant unique de la requ�te HTTP � usage interne uniquement + (peut �tre utilis� pour tracer des logs par exemple).
  • +
+
+
+

G�n�rer la r�ponse + HTTP

+
+ La classe qx::QxHttpResponse (ou son alias qx_http_response) permet de g�n�rer la r�ponse HTTP avec les + m�thodes suivantes : +
    +
  • int & status() : code retour de la r�ponse HTTP (par d�faut 200) ;
  • +
  • QByteArray & data() : contenu de la r�ponse HTTP ;
  • +
  • QByteArray header(const QByteArray & key) : renseigne un en-t�te HTTP � envoyer au + navigateur web client (par d�faut, les en-t�tes suivants sont cr��s : Server, + Date, Content-Type et Connection) ; +
  • +
  • QxHttpCookie cookie(const QByteArray & name) : renseigne un cookie HTTP � envoyer au navigateur web client ;
  • +
  • qx_bool writeChunked(const QByteArray & data) : permet d'envoyer le contenu de la r�ponse par bloc (chunked responses).
  • +
+
+
+

Sessions (stockage par + client c�t� serveur)

+
+ Les sessions HTTP sont un m�canisme c�t� serveur web permettant de stocker des donn�es + sp�cifiques � un client. + Ces donn�es sont accessibles pendant un laps de temps pour toutes les requ�tes envoy�es par le + client. + Lors du 1er acc�s � une session pour un client, un cookie HTTP + contenant un identifiant unique est g�n�r� et associ� automatiquement � la r�ponse HTTP. + Par la suite, toutes les requ�tes HTTP envoy�es par le client contiendront automatiquement un cookie HTTP avec l'identifiant unique calcul� pr�c�demment. + Lorsqu'une session n'est plus utilis�e pendant un certain laps de temps, alors elle est d�truite + automatiquement. +

+ La classe qx::QxHttpSession (ou son alias qx_http_session) repr�sente une session HTTP c�t� serveur.
+ Une session est accessible avec le singleton qx::QxHttpSessionManager : +

+ + + + + + + +
+
httpServer.dispatch("GET", "/", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   // If this is the first time to access to session, then a cookie is created automatically and attached to the response
+   // Then each request sent by web browser will contain a cookie with the session id
+   // The session expires on server side after qx::service::QxConnect::setSessionTimeOut() milliseconds
+   qx::QxHttpSession_ptr session = qx::QxHttpSessionManager::getSession(request, response);
+   if (session) { session->set("last_request_per_user", QDateTime::currentDateTime()); }
+});
+
+

+ Remarque : la classe qx::QxHttpSession contient une hash-map (QHash<QByteArray, + QVariant>) pouvant stocker n'importe quelle valeur. +

+ Autre remarque : la dur�e (en milli-secondes) pour supprimer une session non utilis�e est + param�tr�e par la m�thode : qx::service::QxConnect::setSessionTimeOut(). +

+
+

Cookies

+
+ Les cookies HTTP sont un + m�canisme d'�change de donn�es entre client HTTP et serveur HTTP.
+ Les cookies sont utilis�s par exemple pour : +
    +
  • g�rer les sessions HTTP ;
  • +
  • m�moriser l'information sur l'utilisateur d'un site, dans le but de lui montrer un + contenu appropri� dans le futur. Par exemple, un serveur web peut envoyer un cookie + contenant le dernier nom d'utilisateur utilis� pour se connecter � ce site web, afin que + ce nom d'utilisateur puisse �tre pr�-rempli lors des prochaines visites ;
  • +
  • voir Wikipedia pour + d'autres cas d'utilisation.
  • +
+
+ Les classes qx::QxHttpRequest et qx::QxHttpResponse disposent des m�thodes n�cessaires pour lire les + cookies envoy�s par le navigateur web client ou bien g�n�rer un cookie dans la r�ponse HTTP. + Par exemple : +

+ + + + + + + +
+
qx::QxHttpCookie cookie;
+cookie.name = "my_http_cookie";
+cookie.value = "my_value";
+response.cookies().insert(cookie.name, cookie);
+
+

+
+

Gestion des fichiers + statiques

+
+ La classe qx::QxHttpServer (ou son alias qx_http_server) dispose d'une m�thode statique permettant + d'envoyer au navigateur web client des fichiers stock�s sur le serveur (par exemple : fichiers + HTML, Javascript, CSS, images PNG, JPEG, vid�os, etc...). +

+ + + + + + + +
+
httpServer.dispatch("GET", "/files/*", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseStaticFile(request, response, QDir::currentPath(), 5000);
+});
+
+
+
    +
  • Le 3�me param�tre (dans l'exemple QDir::currentPath()) repr�sente le r�pertoire + parent o� sont stock�s les fichiers statiques sur le serveur web ;
  • +
  • Le 4�me param�tre (dans l'exemple 5000) est optionnel et correspond � la taille + pour l'envoi des fichiers par bloc (chunked response). Ce + param�tre peut �tre utile pour envoyer des fichiers volumineux (streaming).
  • +
+
+
+

Encodage de transfert en + bloc (chunked responses)

+
+ D�finition du + site Wikipedia : Chunked transfer encoding (ou Encodage de transfert en bloc) est un + m�canisme de transfert de donn�es de la version 1.1 du protocole Hypertext Transfer Protocol + (HTTP), qui permet � un serveur ou � un client de commencer � transmettre des donn�es par blocs + sans avoir � conna�tre � l'avance la taille totale des donn�es qui seront transmises. + Dans le protocole HTTP, l'en-t�te "Content-Length" peut remplacer la directive "Chunked transfer + encoding" d�crite ici. + La taille en octets de chaque bloc est envoy�e, sous forme de texte en hexadecimal, juste avant + le bloc lui-m�me afin que le serveur puisse dire au client quand il a fini de recevoir les + donn�es de ce bloc. + Le transfert total d'un fichier encod� par blocs se termine par un bloc final au contenu nul. +

+ L'introduction de l'encodage de transfert en bloc du protocole HTTP 1.1 a fourni un certain + nombre d'avantages : +
    +
  • Permettre � un serveur de maintenir une connexion HTTP persistante pour un contenu g�n�r� + dynamiquement.
  • +
  • Permettre � l'exp�diteur d'envoyer des en-t�tes suppl�mentaires apr�s le corps du + message. Sans l'encodage de transfert en bloc, l'exp�diteur devrait tamponner le contenu + jusqu'� ce qu'il soit compl�t� afin de calculer une valeur et l'envoyer avant le contenu. +
  • +
+
+ La classe qx::QxHttpResponse dispose de la m�thode qx_bool + writeChunked(const QByteArray & data). + Cette m�thode permet d'envoyer la r�ponse par bloc. + Elle est utilis�e par exemple pour envoyer des fichiers statiques + volumineux : +

+ + + + + + + +
+
while (! file.atEnd())
+{
+   if (! response.writeChunked(file.read(chunkedSize))) { return; }
+}
+
+

+ Remarque : le 1er appel de la m�thode response.writeChunked() d�clenche + automatiquement l'envoi de tous les en-t�tes HTTP de la r�ponse. + Il faut donc d�finir tous les en-t�tes de la r�ponse HTTP avant d'appeler + response.writeChunked() pour la 1�re fois. +

+
+

Requ�tes par les API JSON + (module QxRestApi)

+
+ Le module QxRestApi propose une API JSON g�n�rique pour requ�ter les + donn�es persistantes (op�rations CRUD, requ�tes complexes avec plusieurs niveaux de relations, + possibilit� de d�finir un format de sortie JSON, appels dynamiques � des fonctions natives C++, + validation d'instances, requ�tes personnalis�es � la base de donn�es). +

+ Ce manuel utilisateur dispose d'un chapitre entier d�di� au module + QxRestApi : il contient notamment de nombreux exemples d'utilisation. + En combinant le module QxRestApi et le module QxHttpServer : + vous avez tous les outils n�cessaires pour d�velopper des applications web modernes. + Par exemple, des applications web de type SPA + (Single-Page Applications) avec les c�l�bres frameworks Javascript comme AngularJS, React, Meteor.js, + etc... +

+ Remarque : le package QxOrm contient un projet de test + qxBlogRestApi. + Ce projet pr�sente la cr�ation d'un serveur web HTTP avec QxOrm, et �galement l'�criture de la + partie cliente en HTML + Javascript (avec utilisation de jQuery). +

+ Par exemple, voici la fonction Javascript utilis�e pour envoyer les requ�tes JSON (m�thode POST) + depuis le client (navigateur web) vers le serveur web HTTP QxOrm (toutes les requ�tes sont + envoy�es � la m�me adresse /qx) : +

+ + + + + + + +
+
function sendRequest(request) {
+   $.post("/qx", request, function(data, status, xhr) {
+      $("#txtResponse").val(JSON.stringify(data, null, 3));
+   }, "json").fail(function(error) {
+      alert("An error occurred sending request to QxOrm HTTP server : " + error);
+   });
+}
+
+

+ C�t� serveur, la r�ception et le traitement de ces requ�tes est tr�s simple : la classe qx::QxHttpServer (ou son alias qx_http_server) dispose de la m�thode statique + qx::QxHttpServer::buildResponseQxRestApi() : +

+ + + + + + + +
+
httpServer.dispatch("POST", "/qx", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) {
+   qx::QxHttpServer::buildResponseQxRestApi(request, response);
+});
+
+

+ Voici un exemple de requ�te JSON envoy�e par le navigateur web, elle r�cup�re la liste des tous + les blogs de la base de donn�es (fetch_all) : +

+
+
{
+   "request_id": "2b393e4c-a00c-45dc-a279-e9d76f1c55cf",
+   "action": "fetch_all",
+   "entity": "blog"
+}
+
+

+ Voici la r�ponse JSON renvoy�e par le serveur web HTTP contenant la liste de blogs : +

+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-03-27T20:51:23.107",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "2b393e4c-a00c-45dc-a279-e9d76f1c55cf"
+}
+
+

+
+

WebSocket

+
+ D�finition du site Wikipedia + : le protocole WebSocket vise � d�velopper un canal de communication full-duplex sur un + socket TCP pour les navigateurs et les serveurs web et permet : +
    +
  • la notification au client d'un changement d'�tat du serveur ;
  • +
  • l'envoi de donn�es en mode � pousser � (m�thode Push) du serveur vers le client (sans que + ce dernier ait � effectuer une requ�te).
  • +
+
+ La biblioth�que QxOrm est bas�e sur le framework Qt qui dispose d�j� d'une impl�mentation + WebSocket.
+ La mise en place d'un serveur web avec les WebSockets Qt est tr�s simple : il y a plusieurs exemples dans + la documentation Qt. +

+ Il est donc tout � fait possible d'impl�menter un serveur web avec : +
    +
  • un port d'�coute d�di� � toutes les connexions HTTP (utilisant le module + QxHttpServer) ; +
  • +
  • un autre port d'�coute d�di� � toutes les connexions WebSockets (utilisant le module QtWebSockets + fourni par Qt).
  • +
+
+ Remarque : une connexion WebSocket �tant g�n�ralement cr��e par le code Javascript du + navigateur web client, le fait d'avoir 2 ports ouverts sur le serveur web n'est pas un probl�me. +

+
+

Performance (test� avec + Apache Benchmark)

+
+ Voici les r�sultats d'un test de performance r�alis� avec les param�tres suivants : +
    +
  • Syst�me d'exploitation : Windows 2010 64bits ;
  • +
  • Processeur : Intel Core i7-6820HQ @ 2.70GHz (laptop) ;
  • +
  • Version Qt : 5.1.1 (en mode release) ;
  • +
  • Version QxOrm : 1.4.6 (compil� en mode release avec Visual Studio 2012, avec les + param�tres par d�faut, aucune optimisation particuli�re) ;
  • +
  • Serveur web HTTP : projet de test qxBlogRestApi ;
  • +
  • Outil de test : Apache Benchmark ;
  • +
  • Simulation de 20000 requ�tes avec 50 clients connect�s simultan�ment : ab -n 20000 + -c 50 -k http://localhost:9642/params/abc/123
  • +
+
+ Le r�sultat indique que le serveur web HTTP QxOrm peut g�rer plus de 12000 requ�tes par seconde : +

+ QxHttpServer performance +

+

Am�liorer les + performances avec epoll dispatcher sous Linux

+
+ Sous Linux, il est possible d'ameliorer significativement les performances du serveur web + HTTP en utilisant le m�canisme + epoll pour g�rer les socket. + Par d�faut, le framework Qt utilise un autre m�canisme (select) plus lent, mais donne + la possibilit� de d�finir une autre gestion d'�v�nements. + Plusieurs biblioth�ques existent, par exemple : + +
+ La classe qx::QxHttpServer (ou son alias qx_http_server) dispose de la m�thode suivante pour d�finir des + �v�nements bas�s sur epoll (� appeler avant le d�marrage du serveur web) : +

+ + + + + + + +
+
   httpServer.setEventDispatcher(new QEventDispatcherEpoll());   
+
+

+
+
+
+ +

API REST JSON (module + QxRestApi)

+
+ Le module QxRestApi est une API JSON pour g�rer (de fa�on g�n�rique) la couche de donn�es + persistantes (base de donn�es) ou appeler des fonctions natives C++ + (enregistr�es dans le contexte QxOrm). + Le module QxRestApi est bas� sur un m�canisme requ�te/r�ponse : envoi d'une requ�te au + format JSON et r�ception d'une r�ponse au format JSON. + Le module QxRestApi est particuli�rement adapt� pour d�velopper des services + REST. +

+ Le module QxRestApi supporte les fonctionnalit�s suivantes : +
    +
  • op�rations CRUD ;
  • +
  • requ�tes complexes avec plusieurs niveaux de relations ;
  • +
  • possibilit� de d�finir un format de sortie JSON ;
  • +
  • appels dynamiques � des fonctions natives C++ ;
  • +
  • validation d'instances ;
  • +
  • requ�tes personnalis�es � la base de donn�es ou proc�dures stock�es.
  • +
+
+

Principe de + fonctionnement

+
+ Le module QxRestApi est tr�s simple d'utilisation : la classe qx::QxRestApi + permet d'utiliser les API JSON avec une seule m�thode : processRequest().
+ Pr�requis : pour pouvoir utiliser le module QxRestApi, les classes enregistr�es + dans le contexte QxOrm doivent impl�menter l'interface qx::IxPersistable. +

+ La structure d'une requ�te JSON est g�n�rique et contient les �l�ments suivants : +

+
+
{
+   "request_id" : // [optional] unique identifier generated by client to associate response to request (if provided by caller, then the response will contain the same unique identifier)
+   "action" : // [required] what is the action to execute on the server
+   "entity" : // [optional or required depending on action] C++ class registered in QxOrm context
+   "data" : // [optional or required depending on action] data in JSON format needed to execute action
+   "columns" : // [optional] list of columns to fetch or update (if empty, means all columns)
+   "relations" : // [optional] list of relationships to fetch or save
+   "query" : // [optional or required depending on action] query to execute on database
+   "output_format" : // [optional] output fields for the response (filter), if empty then response will contain all fields
+   "fct" : // [required only with action 'call_entity_function'] used to call C++ native functions
+   "save_mode" : // [optional] used only with action 'save' to define insert or update or check both insert/update
+}
+
+

+ La r�ponse JSON contient les �l�ments suivants : +

+
+
{
+   "request_id" : // unique identifier generated by client's request (if any)
+   "data" : // contain the response data
+   "error" : // if an error occured, then contain a code and description of the error
+}
+
+

+

Cas d'utilisation +

+
+ Plusieurs langages de programmation supporte le JSON nativement (Javascript, PHP, Python, + etc...). + Le module QxRestApi permet ainsi une interop�rabilit� entre la biblioth�que QxOrm et + d'autres applications utilisant d'autres technologies (autre que C++/Qt par exemple). +

+ Le module QxRestApi peut �tre utilis� : + +
+
+
+

Projet de test + qxBlogRestApi (QML et serveur web HTTP)

+
+ Le package QxOrm est livr� avec un projet de test nomm� qxBlogRestApi (dans le dossier + ./test/qxBlogRestApi/).
+ Ce projet de test montre 2 cas d'utilisation du module QxRestApi : +
    +
  • La 1�re fen�tre correspond � une application QML + qui utilise le moteur JS int�gr� � QML pour requ�ter les donn�es persistantes ou + appeler des fonctions natives C++ : +

    QxHttpServer performance


    +
  • +
  • La 2�me fen�tre d�marre un serveur web HTTP + bas� sur le module QxHttpServer, puis ouvre le navigateur web par + d�faut � l'adresse correspondante (HTML + Javascript avec jQuery) : +

    QxHttpServer performance
    +
  • +
+
+ Ces 2 fen�tres sont d�velopp�es avec 2 technologies diff�rentes (QML versus HTML + Javascript), + mais proposent exactement les m�mes fonctionnalit�s : +
    +
  • En haut � gauche de l'�cran : zone permettant d'�crire la requ�te JSON � envoyer au + module QxRestApi ; +
  • +
  • Juste en dessous de la requ�te JSON : un bouton permettant d'envoyer la requ�te JSON au + module QxRestApi ; +
  • +
  • En bas � gauche de l'�cran : une liste d'exemples de requ�tes JSON pr�tes � �tre + ex�cut�es (un click dans cette liste alimente automatiquement la requ�te JSON � envoyer au + module QxRestApi) ; +
  • +
  • A droite de l'�cran : la r�ponse JSON fournie par le module QxRestApi apr�s + traitement de la requ�te.
  • +
+
+
+

R�cup�ration de donn�es + (fetch/count/exist)

+
+ Ce chapitre d�taille les diff�rentes m�thodes pour r�cup�rer les donn�es issues de la base de + donn�es : +
    +
  • R�cup�rer tous les �l�ments d'une table et �ventuellement les + relations associ�es (fetch_all) ;
  • +
  • R�cup�rer les donn�es d'un �l�ment d'une table en fonction de son identifiant unique (fetch_by_id) ;
  • +
  • R�cup�rer les �l�ments d'une table filtr�s par une requ�te (fetch_by_query) ;
  • +
  • Compter les �l�ments d'une table avec ou sans requ�te (count) + ;
  • +
  • Tester l'existence d'un ou plusieurs �l�ments d'une table en fonction de l'identifiant + (exist).
  • +
+
+

fetch_all

+
+ L'action fetch_all permet de r�cup�rer tous les �l�ments d'une table de la base + de donn�es (et �ventuellement les relations associ�es sur plusieurs + niveaux). +

+ -- Exemple n�1 -- r�cup�rer tous les + blogs (sous forme de liste) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "5e988bac-c812-4cb1-b0d8-6a2c9dc4478b",
+   "action": "fetch_all",
+   "entity": "blog"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "5e988bac-c812-4cb1-b0d8-6a2c9dc4478b"
+}
+
+

+ -- Exemple n�2 -- r�cup�rer tous les + blogs (sous forme de collection type hash-map avec cl�/valeur) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "ad400135-19fd-40e0-8034-201be6a2ff7a",
+   "action": "fetch_all",
+   "entity": "blog",
+   "data": [
+      {
+         "key": "",
+         "value": ""
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "key": 1,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 1,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 2,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 2,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 3,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 3,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      },
+      {
+         "key": 4,
+         "value": {
+            "author_id": {
+               "author_id": "author_id_2",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 4,
+            "blog_text": "blog property 'text' modified => blog is dirty !!!",
+            "date_creation": "2019-04-01T16:18:54",
+            "list_category": [],
+            "list_comment": []
+         }
+      }
+   ],
+   "request_id": "ad400135-19fd-40e0-8034-201be6a2ff7a"
+}
+
+

+ -- Exemple n�3 -- r�cup�rer tous les + blogs et toutes les relations associ�es sur 2 niveaux : +

+ Requ�te JSON :
+
+
{
+   "request_id": "cf9ea2a8-3e41-438f-9a48-bbc8593d2b99",
+   "action": "fetch_all",
+   "entity": "blog",
+   "relations": [
+      "*->*"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 1,
+               "value": {
+                  "category_id": 1,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 1,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 3,
+               "value": {
+                  "category_id": 3,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 1,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": [
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 1,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 3,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 5,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 7,
+               "comment_text": "comment_1 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 2,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 4,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 6,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               "comment_id": 8,
+               "comment_text": "comment_2 text",
+               "date_creation": "2019-04-01T16:18:54"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 4,
+               "value": {
+                  "category_id": 4,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 2,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 2,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 5,
+               "value": {
+                  "category_id": 5,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 2,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 2,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 6,
+               "value": {
+                  "category_id": 6,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 3,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 3,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 7,
+               "value": {
+                  "category_id": 7,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 3,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 3,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "list_blog": [
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 2,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 3,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               },
+               {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": null,
+                     "list_blog": [],
+                     "name": "",
+                     "sex": 2
+                  },
+                  "blog_id": 4,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [],
+                  "list_comment": []
+               }
+            ],
+            "name": "author name modified at index 1 => container is dirty !!!",
+            "sex": 1
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [
+            {
+               "key": 8,
+               "value": {
+                  "category_id": 8,
+                  "description": "desc_1",
+                  "list_blog": [
+                     {
+                        "key": 4,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 4,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_1"
+               }
+            },
+            {
+               "key": 9,
+               "value": {
+                  "category_id": 9,
+                  "description": "desc_3",
+                  "list_blog": [
+                     {
+                        "key": 4,
+                        "value": {
+                           "author_id": {
+                              "author_id": "author_id_2",
+                              "birthdate": null,
+                              "list_blog": [],
+                              "name": "",
+                              "sex": 2
+                           },
+                           "blog_id": 4,
+                           "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                           "date_creation": "2019-04-01T16:18:54",
+                           "list_category": [],
+                           "list_comment": []
+                        }
+                     }
+                  ],
+                  "name": "category_3"
+               }
+            }
+         ],
+         "list_comment": []
+      }
+   ],
+   "request_id": "cf9ea2a8-3e41-438f-9a48-bbc8593d2b99"
+}
+
+

+ -- Exemple n�4 -- r�cup�rer tous les + blogs et plusieurs relations associ�es en d�finissant un format de + sortie (toutes les propri�t�s ne feront pas partie de la r�ponse JSON) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "4c45fdf9-8001-4509-bb4b-ce27a4a8708a",
+   "action": "fetch_all",
+   "entity": "blog",
+   "relations": [
+      "<blog_alias> { blog_text }",
+      "author_id <author_alias> { name, birthdate }",
+      "list_comment <list_comment_alias> { comment_text } -> blog_id <blog_alias_2> -> * <..._my_alias_suffix>"
+   ],
+   "output_format": [
+      "{ blog_text }",
+      "author_id { name, birthdate }",
+      "list_comment { comment_text } -> blog_id -> *"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": [
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 1,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 3,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 5,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 7,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 2,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 4,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 6,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "blog_id": {
+                  "author_id": {
+                     "author_id": "author_id_2",
+                     "birthdate": "2019-04-01",
+                     "name": "author name modified at index 1 => container is dirty !!!",
+                     "sex": 1
+                  },
+                  "blog_id": 1,
+                  "blog_text": "blog property 'text' modified => blog is dirty !!!",
+                  "date_creation": "2019-04-01T16:18:54",
+                  "list_category": [
+                     {
+                        "key": 1,
+                        "value": {
+                           "category_id": 1,
+                           "description": "desc_1",
+                           "name": "category_1"
+                        }
+                     },
+                     {
+                        "key": 3,
+                        "value": {
+                           "category_id": 3,
+                           "description": "desc_3",
+                           "name": "category_3"
+                        }
+                     }
+                  ],
+                  "list_comment": [
+                     {
+                        "comment_id": 1,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 3,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 5,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 7,
+                        "comment_text": "comment_1 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 2,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 4,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 6,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     },
+                     {
+                        "comment_id": 8,
+                        "comment_text": "comment_2 text",
+                        "date_creation": "2019-04-01T16:18:54"
+                     }
+                  ]
+               },
+               "comment_id": 8,
+               "comment_text": "comment_2 text"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 4,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      }
+   ],
+   "request_id": "4c45fdf9-8001-4509-bb4b-ce27a4a8708a"
+}
+
+

+
+

fetch_by_id

+
+ L'action fetch_by_id permet de r�cup�rer les donn�es d'un �l�ment d'une table + en fonction de son identifiant unique. +

+ -- Exemple n�1 -- r�cup�rer les donn�es + du blog qui a pour identifiant unique 1 : +

+ Requ�te JSON :
+
+
{
+   "request_id": "4d6fbb9e-e088-482a-abfa-4e7ddee80569",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "author_id": {
+         "author_id": "author_id_2",
+         "birthdate": null,
+         "list_blog": [],
+         "name": "",
+         "sex": 2
+      },
+      "blog_id": 1,
+      "blog_text": "blog property 'text' modified => blog is dirty !!!",
+      "date_creation": "2019-04-01T16:18:54",
+      "list_category": [],
+      "list_comment": []
+   },
+   "request_id": "4d6fbb9e-e088-482a-abfa-4e7ddee80569"
+}
+
+

+ -- Exemple n�2 -- r�cup�re uniquement + quelques donn�es du blog qui a pour identifiant unique 1 (les autres donn�es font partie du + JSON mais avec une valeur vide ou null) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "72c9b362-d194-410e-98ed-23797a34318e",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   },
+   "columns": [
+      "blog_text",
+      "date_creation"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "author_id": null,
+      "blog_id": 1,
+      "blog_text": "blog property 'text' modified => blog is dirty !!!",
+      "date_creation": "2019-04-01T16:18:54",
+      "list_category": [],
+      "list_comment": []
+   },
+   "request_id": "72c9b362-d194-410e-98ed-23797a34318e"
+}
+
+

+ -- Exemple n�3 -- r�cup�re une liste de + blogs en fonction de leur identifiant : +

+ Requ�te JSON :
+
+
{
+   "request_id": "59c37f70-26ee-42e5-9177-b32c331adce1",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 2
+      },
+      {
+         "blog_id": 3
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": null,
+            "list_blog": [],
+            "name": "",
+            "sex": 2
+         },
+         "blog_id": 3,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "date_creation": "2019-04-01T16:18:54",
+         "list_category": [],
+         "list_comment": []
+      }
+   ],
+   "request_id": "59c37f70-26ee-42e5-9177-b32c331adce1"
+}
+
+

+ -- Exemple n�4 -- r�cup�re une liste de + blogs (avec quelques relations associ�es) en fonction de leur identifiant, et d�fini un + format de sortie (toutes les propri�t�s ne feront pas partie de la r�ponse JSON) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "325d64f4-29ac-47ab-9846-d6a71a9e9d73",
+   "action": "fetch_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 2
+      }
+   ],
+   "relations": [
+      "{ blog_text }",
+      "author_id <author_alias> { name, birthdate }",
+      "list_comment <list_comment_alias> { comment_text }"
+   ],
+   "output_format": [
+      "{ blog_text }",
+      "author_id { name, birthdate }",
+      "list_comment { comment_text }"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 1,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": [
+            {
+               "comment_id": 1,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 2,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 3,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 4,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 5,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 6,
+               "comment_text": "comment_2 text"
+            },
+            {
+               "comment_id": 7,
+               "comment_text": "comment_1 text"
+            },
+            {
+               "comment_id": 8,
+               "comment_text": "comment_2 text"
+            }
+         ]
+      },
+      {
+         "author_id": {
+            "author_id": "author_id_2",
+            "birthdate": "2019-04-01",
+            "name": "author name modified at index 1 => container is dirty !!!"
+         },
+         "blog_id": 2,
+         "blog_text": "blog property 'text' modified => blog is dirty !!!",
+         "list_comment": []
+      }
+   ],
+   "request_id": "325d64f4-29ac-47ab-9846-d6a71a9e9d73"
+}
+
+

+
+

fetch_by_query +

+
+ L'action fetch_by_query permet de r�cup�rer les �l�ments d'une table filtr�s par une requ�te. +

+ -- Exemple n�1 -- r�cup�re uniquement les + �l�ments de la table author dont le sexe est de type female (female == + enum dont la valeur est 1) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "c178194c-a76f-4a77-af12-2b97fc7078e4",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [],
+         "name": "author name modified at index 1 => container is dirty !!!",
+         "sex": 1
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3",
+         "sex": 1
+      }
+   ],
+   "request_id": "c178194c-a76f-4a77-af12-2b97fc7078e4"
+}
+
+

+ -- Exemple n�2 -- r�cup�re uniquement les + �l�ments de la table author (et toutes ses relations + associ�es) dont le sexe est de type female : +

+ Requ�te JSON :
+
+
{
+   "request_id": "84e2e13a-0bf9-4d78-b655-970568a97e4c",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1,
+            "type": "in"
+         }
+      ]
+   },
+   "relations": [
+      "*"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 1,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 2,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 3,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            },
+            {
+               "author_id": {
+                  "author_id": "author_id_2",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 4,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54",
+               "list_category": [],
+               "list_comment": []
+            }
+         ],
+         "name": "author name modified at index 1 => container is dirty !!!",
+         "sex": 1
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3",
+         "sex": 1
+      }
+   ],
+   "request_id": "84e2e13a-0bf9-4d78-b655-970568a97e4c"
+}
+
+

+ -- Exemple n�3 -- r�cup�re uniquement les + �l�ments de la table author (et toutes ses relations + associ�es) dont le sexe est de type female, et d�fini un format de sortie + (toutes les propri�t�s ne feront pas partie de la r�ponse JSON) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "c18b59e7-54f9-4a4f-843d-f0797f4fb676",
+   "action": "fetch_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1,
+            "type": "in"
+         }
+      ]
+   },
+   "relations": [
+      "*"
+   ],
+   "output_format": [
+      "{ birthdate, name }",
+      "list_blog { blog_text, date_creation }"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_2",
+         "birthdate": "2019-04-01",
+         "list_blog": [
+            {
+               "blog_id": 1,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 2,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 3,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            },
+            {
+               "blog_id": 4,
+               "blog_text": "blog property 'text' modified => blog is dirty !!!",
+               "date_creation": "2019-04-01T16:18:54"
+            }
+         ],
+         "name": "author name modified at index 1 => container is dirty !!!"
+      },
+      {
+         "author_id": "author_id_3",
+         "birthdate": "1998-03-06",
+         "list_blog": [],
+         "name": "author_3"
+      }
+   ],
+   "request_id": "c18b59e7-54f9-4a4f-843d-f0797f4fb676"
+}
+
+

+
+

count

+
+ L'action count permet de compter les �l�ments d'une table avec ou sans requ�te + (et avec ou sans relation). +

+ -- Exemple n�1 -- compter le nombre de + blogs dans la base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "1ef62fd7-d847-4d67-9fd0-0207af463aa4",
+   "action": "count",
+   "entity": "blog"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "count": 4
+   },
+   "request_id": "1ef62fd7-d847-4d67-9fd0-0207af463aa4"
+}
+
+

+ -- Exemple n�2 -- compter tous les + author dont le sexe est de type female : +

+ Requ�te JSON :
+
+
{
+   "request_id": "a80646d1-5a42-46fb-9306-3b91c7f594c8",
+   "action": "count",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "count": 2
+   },
+   "request_id": "a80646d1-5a42-46fb-9306-3b91c7f594c8"
+}
+
+

+ -- Exemple n�3 -- compter tous les blogs + dont l'author est de type female : +

+ Requ�te JSON :
+
+
{
+   "request_id": "6ef252f7-385c-465e-8304-b9afa9fea490",
+   "action": "count",
+   "entity": "blog",
+   "query": {
+      "sql": "WHERE author_alias.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   },
+   "relations": [
+      "author_id <author_alias> { sex }"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "count": 4
+   },
+   "request_id": "6ef252f7-385c-465e-8304-b9afa9fea490"
+}
+
+

+
+

exist

+
+ L'action exist permet de tester l'existence d'un ou plusieurs �l�ments d'une + table en fonction de l'identifiant. +

+ -- Exemple n�1 -- tester l'existence d'un + blog dont l'identifiant unique a pour valeur 1 : +

+ Requ�te JSON :
+
+
{
+   "request_id": "e8db33db-b249-4349-93fe-ad12e208520e",
+   "action": "exist",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "exist": true
+   },
+   "request_id": "e8db33db-b249-4349-93fe-ad12e208520e"
+}
+
+

+ -- Exemple n�2 -- tester l'existence de + plusieurs blogs : +

+ Requ�te JSON :
+
+
{
+   "request_id": "f2d6ca3f-36de-4920-8f4c-c04842603467",
+   "action": "exist",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 999
+      },
+      {
+         "blog_id": 3
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "exist": false
+   },
+   "request_id": "f2d6ca3f-36de-4920-8f4c-c04842603467"
+}
+
+

+ -- Exemple n�3 -- tester l'existence d'un + author : +

+ Requ�te JSON :
+
+
{
+   "request_id": "2c7df172-8010-4816-b8e1-3edbb0b0b90e",
+   "action": "exist",
+   "entity": "author",
+   "data": {
+      "author_id": "author_id_2"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "exist": true
+   },
+   "request_id": "2c7df172-8010-4816-b8e1-3edbb0b0b90e"
+}
+
+

+
+
+

Ajout de donn�es + (insert)

+
+ L'action insert permet d'ins�rer un ou plusieurs �l�ments dans la base de donn�es. + Les identifiants uniques g�n�r�s par la base de donn�es (par exemple identifiant + auto-incr�ment�) sont fournis dans la r�ponse JSON. +

+ -- Exemple n�1 -- ins�rer un blog dans la + base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "573e4940-607a-4037-8a09-11ec52deb21c",
+   "action": "insert",
+   "entity": "blog",
+   "data": {
+      "blog_text": "this is a new blog from QxOrm REST API !",
+      "date_creation": "2018-01-30T12:42:01",
+      "author_id": "author_id_2"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 5
+   },
+   "request_id": "573e4940-607a-4037-8a09-11ec52deb21c"
+}
+
+

+ -- Exemple n�2 -- ins�rer une liste de blogs + dans la base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "6ade2d01-086c-45d6-971b-b65e8836475f",
+   "action": "insert",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_text": "new blog from QxOrm REST API !",
+         "date_creation": "2018-01-30T12:42:01",
+         "author_id": "author_id_2"
+      },
+      {
+         "blog_text": "another blog from QxOrm REST API !",
+         "date_creation": "2016-06-12T08:33:12",
+         "author_id": "author_id_1"
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "blog_id": 6
+      },
+      {
+         "blog_id": 7
+      }
+   ],
+   "request_id": "6ade2d01-086c-45d6-971b-b65e8836475f"
+}
+
+

+ -- Exemple n�3 -- ins�rer un author + dans la base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57",
+   "action": "insert",
+   "entity": "author",
+   "data": {
+      "author_id": "author_id_from_rest_api",
+      "birthdate": "1978-05-11",
+      "name": "new author created by QxOrm REST API",
+      "sex": 1
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "author_id": "author_id_from_rest_api"
+   },
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57"
+}
+
+
+ Remarque : l'identifiant unique de la table author doit �tre fourni par l'appelant + (non auto-incr�ment�). + Si on rejoue une 2�me fois la m�me requ�te, on obtient l'erreur suivante : +
+
+
{
+   "error": {
+      "code": 19,
+      "desc": "Unable to fetch row\ncolumn author_id is not unique"
+   },
+   "request_id": "0cffa916-99f4-4395-bccd-02918a4b3c57"
+}
+
+

+
+

Mise � jour de donn�es + (update)

+
+ L'action update permet une mise � jour de un ou plusieurs �l�ments dans la base de + donn�es. +

+ -- Exemple n�1 -- mise � jour du blog avec + pour identifiant unique la valeur 1 : +

+ Requ�te JSON :
+
+
{
+   "request_id": "4fa24a7f-a3d8-4bbf-85c1-c86df83dec0b",
+   "action": "update",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": "author_id_1"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "4fa24a7f-a3d8-4bbf-85c1-c86df83dec0b"
+}
+
+

+ -- Exemple n�2 -- mise � jour uniquement de + certaines colonnes d'un blog : +

+ Requ�te JSON :
+
+
{
+   "request_id": "d0704db1-5c3a-48ad-b27e-14aa54ac0efb",
+   "action": "update",
+   "entity": "blog",
+   "data": {
+      "blog_id": 2,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33"
+   },
+   "columns": [
+      "blog_text",
+      "date_creation"
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 2
+   },
+   "request_id": "d0704db1-5c3a-48ad-b27e-14aa54ac0efb"
+}
+
+

+ -- Exemple n�3 -- mise � jour de plusieurs + author : +

+ Requ�te JSON :
+
+
{
+   "request_id": "26ec3a7b-cf2d-47f7-bab7-db303f15ee51",
+   "action": "update",
+   "entity": "author",
+   "data": [
+      {
+         "author_id": "author_id_from_rest_api",
+         "birthdate": "1992-11-03",
+         "name": "modify author from QxOrm REST API",
+         "sex": 0
+      },
+      {
+         "author_id": "author_id_1",
+         "birthdate": "1978-12-25",
+         "name": "modify another author from QxOrm REST API",
+         "sex": 2
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "author_id": "author_id_from_rest_api"
+      },
+      {
+         "author_id": "author_id_1"
+      }
+   ],
+   "request_id": "26ec3a7b-cf2d-47f7-bab7-db303f15ee51"
+}
+
+

+
+

Sauvegarde de donn�es + (save)

+
+ L'action save permet d'ins�rer ou mettre � jour (insert ou update) + un ou plusieurs �l�ments dans la base de donn�es. + En cas d'insertion, les identifiants uniques g�n�r�s par la base de donn�es (par exemple + identifiant auto-incr�ment�) sont fournis dans la r�ponse JSON. +

+ La requ�te JSON dispose d'un param�tre optionnel nomm� save_mode qui peut prendre les + valeurs suivantes : +
    +
  • check_insert_or_update : sauvegarde l'instance et les relations de fa�on r�cursive + (sur plusieurs niveaux) en v�rifiant pour chaque relation s'il faut faire un insert + ou update (m�thode pouvant �tre lente si beaucoup de relations � traiter) ;
  • +
  • insert_only : ins�re de fa�on r�cursive (sur plusieurs niveaux) l'instance et + toutes les relations associ�es ;
  • +
  • update_only : met � jour de fa�on r�cursive (sur plusieurs niveaux) l'instance et + toutes les relations associ�es.
  • +
+
+ -- Exemple n�1 -- sauvegarde (ins�re ou met + � jour suivant l'identifant unique) un blog dans la base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "ec3c71eb-5014-4b36-85a0-aeb7ae48a5e9",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "modify blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": "author_id_1"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "ec3c71eb-5014-4b36-85a0-aeb7ae48a5e9"
+}
+
+

+ -- Exemple n�2 -- sauvegarde (ins�re ou met + � jour suivant l'identifant unique) une liste de blogs dans la base de donn�es : +

+ Requ�te JSON :
+
+
{
+   "request_id": "dc7c804e-f95a-4a9b-a4e3-547adcacf090",
+   "action": "save",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 1,
+         "blog_text": "save blog from QxOrm REST API !",
+         "date_creation": "2018-01-30T12:42:01",
+         "author_id": "author_id_2"
+      },
+      {
+         "blog_text": "save another blog from QxOrm REST API !",
+         "date_creation": "2016-06-12T08:33:12",
+         "author_id": "author_id_1"
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "blog_id": 1
+      },
+      {
+         "blog_id": 5
+      }
+   ],
+   "request_id": "dc7c804e-f95a-4a9b-a4e3-547adcacf090"
+}
+
+

+ -- Exemple n�3 -- sauvegarde (ins�re ou met + � jour suivant l'identifant unique) un blog et toutes ses relations sur plusieurs niveaux (de + fa�on r�cursive) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "5b78e468-2fa3-4aeb-82ce-4d85408f5fa7",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_id": 1,
+      "blog_text": "save recursive blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": {
+         "author_id": "author_id_1",
+         "birthdate": "1965-07-21",
+         "name": "save recursive author from QxOrm REST API",
+         "sex": 0
+      }
+   },
+   "save_mode": "check_insert_or_update"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 1
+   },
+   "request_id": "5b78e468-2fa3-4aeb-82ce-4d85408f5fa7"
+}
+
+

+ -- Exemple n�4 -- ins�re (save_mode = + insert_only) un blog et toutes ses relations sur plusieurs niveaux (de fa�on r�cursive) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "ef147c62-74e0-4be2-a294-ffeb020d5304",
+   "action": "save",
+   "entity": "blog",
+   "data": {
+      "blog_text": "save recursive - new blog from QxOrm REST API",
+      "date_creation": "2013-11-25T09:56:33",
+      "author_id": {
+         "author_id": "author_id_save_recursive",
+         "birthdate": "1965-07-21",
+         "name": "save recursive (insert only) author from QxOrm REST API",
+         "sex": 0
+      }
+   },
+   "save_mode": "insert_only"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 7
+   },
+   "request_id": "ef147c62-74e0-4be2-a294-ffeb020d5304"
+}
+
+

+
+

Suppression de donn�es + (delete)

+
+ Ce chapitre d�taille les diff�rentes m�thodes pour supprimer des �l�ments de la base de donn�es + : + +
+ Remarque : la diff�rence entre delete et destroy est li�e � la suppression logique (soft delete) d'un �l�ment. +

+

delete_all / + destroy_all

+
+ Les actions delete_all et destroy_all permettent de supprimer + tous les �l�ments d'une table. + La diff�rence entre delete et destroy est li�e � la suppression logique (soft delete) d'un �l�ment. +

+ -- Exemple n�1 -- supprime tous les + �l�ments de la table comment : +

+ Requ�te JSON :
+
+
{
+   "request_id": "7b06b5c0-409f-4e0d-bfc4-acafbfe7e796",
+   "action": "delete_all",
+   "entity": "comment"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "deleted": true
+   },
+   "request_id": "7b06b5c0-409f-4e0d-bfc4-acafbfe7e796"
+}
+
+

+
+

delete_by_query / + destroy_by_query

+
+ Les actions delete_by_query et destroy_by_query permettent de + supprimer les �l�ments d'une table en fonction d'une requ�te. + La diff�rence entre delete et destroy est li�e � la suppression logique (soft delete) d'un �l�ment. +

+ -- Exemple n�1 -- supprime les �l�ments + de la table author qui ont un sexe de type female (female = enum de + valeur 1) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "169ff0be-6e49-457b-a99c-22bd7141dc02",
+   "action": "delete_by_query",
+   "entity": "author",
+   "query": {
+      "sql": "WHERE author.sex = :sex",
+      "params": [
+         {
+            "key": ":sex",
+            "value": 1
+         }
+      ]
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "deleted": true
+   },
+   "request_id": "169ff0be-6e49-457b-a99c-22bd7141dc02"
+}
+
+

+
+

delete_by_id / + destroy_by_id

+
+ Les actions delete_by_id et destroy_by_id permettent de supprimer + les �l�ments d'une table en fonction de leur identifiant unique. + La diff�rence entre delete et destroy est li�e � la suppression logique (soft delete) d'un �l�ment. +

+ -- Exemple n�1 -- supprime de la base de + donn�es le blog qui a pour identifiant unique la valeur 4 : +

+ Requ�te JSON :
+
+
{
+   "request_id": "80bff383-8ebd-4bde-bb42-37b6f67bc39f",
+   "action": "delete_by_id",
+   "entity": "blog",
+   "data": {
+      "blog_id": 4
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "blog_id": 4
+   },
+   "request_id": "80bff383-8ebd-4bde-bb42-37b6f67bc39f"
+}
+
+

+ -- Exemple n�2 -- supprime de la base de + donn�es les blogs qui ont pour identifiant unique les valeurs 2 et 3 : +

+ Requ�te JSON :
+
+
{
+   "request_id": "38020cb7-d725-4c0e-80a0-63db7569155e",
+   "action": "delete_by_id",
+   "entity": "blog",
+   "data": [
+      {
+         "blog_id": 3
+      },
+      {
+         "blog_id": 2
+      }
+   ]
+}
+
+ R�ponse JSON :
+
+
{
+   "data": [
+      {
+         "blog_id": 3
+      },
+      {
+         "blog_id": 2
+      }
+   ],
+   "request_id": "38020cb7-d725-4c0e-80a0-63db7569155e"
+}
+
+

+
+
+

Validation de donn�es + (validate)

+
+ L'action validate permet de valider les propri�t�s d'une instance (sans d�clencher + d'action sur la base de donn�es). + L'action validate appelle le module QxValidator de la + biblioth�que QxOrm. +

+ -- Exemple n�1 -- un blog doit + contenir du texte (propri�t� blog_text) pour pouvoir �tre sauvegard� dans la base de + donn�es. + La requ�te JSON suivante permet d'indiquer que l'instance est non valide avec un message + explicite : +

+ Requ�te JSON :
+
+
{
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba",
+   "action": "validate",
+   "entity": "blog",
+   "data": {
+      "blog_id": 9999,
+      "blog_text": ""
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "invalid_values": [
+         "blog",
+         [
+            {
+               "message": "'blog_text' property cannot be empty",
+               "path": "blog"
+            }
+         ]
+      ]
+   },
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba"
+}
+
+

+ -- Exemple n�2 -- en ajoutant une valeur � + la propri�t� blog_text, alors le blog devient valide (la r�ponse JSON dispose d'un + champ invalid_values qui vaut null) : +

+ Requ�te JSON :
+
+
{
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba",
+   "action": "validate",
+   "entity": "blog",
+   "data": {
+      "blog_id": 9999,
+      "blog_text": "my blog text !!!"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "invalid_values": null
+   },
+   "request_id": "92043c2b-4ba8-4583-8fad-c828251734ba"
+}
+
+

+
+

Appel RAW SQL ou + proc�dure stock�e

+
+ L'action call_custom_query permet d'appeler une requ�te SQL personnalis�e ou une + proc�dure stock�e. +

+ -- Exemple n�1 -- ins�re dans la base de + donn�es un nouveau author avec une requ�te SQL personnalis�e : +

+ Requ�te JSON :
+
+
{
+   "request_id": "ff2a2256-041d-4c5f-bd86-3745ce46ead8",
+   "action": "call_custom_query",
+   "query": {
+      "sql": "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)",
+      "params": [
+         {
+            "key": ":author_id",
+            "value": "author_id_custom_query"
+         },
+         {
+            "key": ":name",
+            "value": "new author inserted by custom query"
+         },
+         {
+            "key": ":birthdate",
+            "value": "20190215"
+         },
+         {
+            "key": ":sex",
+            "value": 2
+         }
+      ]
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "query_output": {
+         "distinct": false,
+         "list_values": {
+            ":author_id": [
+               "author_id_custom_query",
+               1
+            ],
+            ":birthdate": [
+               "20190215",
+               1
+            ],
+            ":name": [
+               "new author inserted by custom query",
+               1
+            ],
+            ":sex": [
+               2,
+               1
+            ]
+         },
+         "parenthesis_count": 0,
+         "query": [
+            "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)"
+         ],
+         "response": "",
+         "result_position_by_key": {},
+         "result_values": [],
+         "sql_element_index": 0,
+         "sql_element_list": [],
+         "sql_element_temp_type": 0,
+         "type": ""
+      }
+   },
+   "request_id": "ff2a2256-041d-4c5f-bd86-3745ce46ead8"
+}
+
+

+
+

Appel fonctions natives + C++

+
+ L'action call_entity_function permet d'appeler des fonctions natives C++ + enregistr�es dans le contexte QxOrm.
+ Pr�requis : la fonction native C++ doit �tre une fonction static avec pour + signature : + static QJsonValue myNativeCppFct(const QJsonValue & + request); + +

+ Voici un exemple d'enregistrement de fonction native C++ pouvant �tre appel�e par les API JSON + de la biblioth�que QxOrm : +

+ + + + + + + +
+
namespace qx {
+template <> void register_class(QxClass<blog> & t)
+{
+   // Register 'helloWorld()' static function in QxOrm context (can be called by QxRestApi JSON API module)
+   t.fctStatic_1<QJsonValue, const QJsonValue & >(& blog::helloWorld, "helloWorld");
+}}
+
+// 'helloWorld()' static function implementation
+QJsonValue blog::helloWorld(const QJsonValue & request)
+{
+   QJsonObject response;
+   response.insert("request", request);
+   response.insert("response", QString("Hello World !"));
+   return response;
+}
+
+

+ Voici comment appeler cette fonction helloWorld avec les API JSON en utilisant l'action + call_entity_function : +

+ Requ�te JSON :
+
+
{
+   "request_id": "ab1ba7d3-9f98-4b18-a310-a9c34498d043",
+   "action": "call_entity_function",
+   "entity": "blog",
+   "fct": "helloWorld",
+   "data": {
+      "param1": "test",
+      "param2": "static fct call"
+   }
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "request": {
+         "param1": "test",
+         "param2": "static fct call"
+      },
+      "response": "Hello World !"
+   },
+   "request_id": "ab1ba7d3-9f98-4b18-a310-a9c34498d043"
+}
+
+

+
+

Meta-data (structure des + classes C++ enregistr�es dans le contexte QxOrm)

+
+ L'action get_meta_data permet de r�cup�rer les m�ta-donn�es d'une ou de toutes les + entit�s enregistr�es dans le contexte QxOrm (structure des classes avec liste des propri�t�s et + relations). +

+ -- Exemple n�1 -- r�cup�re toutes les + m�ta-donn�es du projet d'exemple qxBlogRestApi : +

+ Requ�te JSON :
+
+
{
+   "request_id": "842ed7b5-9b94-455f-86dc-32992866b3d5",
+   "action": "get_meta_data",
+   "entity": "*"
+}
+
+ R�ponse JSON :
+
+
{
+   "data": {
+      "entities": [
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "author_id",
+               "type": "QString"
+            },
+            "key": "author",
+            "name": "author",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "name",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "birthdate",
+                  "type": "QDate"
+               },
+               {
+                  "description": "",
+                  "key": "sex",
+                  "type": "enum author::enum_sex *"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "list_blog",
+                  "target": "blog",
+                  "type": "std::vector<std::shared_ptr<blog>>",
+                  "type_relation": "relation one-to-many"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "blog_id",
+               "type": "long"
+            },
+            "key": "blog",
+            "name": "blog",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "blog_text",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "date_creation",
+                  "type": "QDateTime"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "author_id",
+                  "target": "author",
+                  "type": "std::shared_ptr<author>",
+                  "type_relation": "relation many-to-one"
+               },
+               {
+                  "description": "",
+                  "key": "list_comment",
+                  "target": "comment",
+                  "type": "QList<std::shared_ptr<comment>>",
+                  "type_relation": "relation one-to-many"
+               },
+               {
+                  "description": "",
+                  "key": "list_category",
+                  "target": "category",
+                  "type": "qx::QxCollection<long, QSharedPointer<category>>",
+                  "type_relation": "relation many-to-many"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "comment_id",
+               "type": "long"
+            },
+            "key": "comment",
+            "name": "comment",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "comment_text",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "date_creation",
+                  "type": "QDateTime"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "blog_id",
+                  "target": "blog",
+                  "type": "std::shared_ptr<blog>",
+                  "type_relation": "relation many-to-one"
+               }
+            ],
+            "version": 0
+         },
+         {
+            "base_entity": "",
+            "description": "",
+            "entity_id": {
+               "description": "",
+               "key": "category_id",
+               "type": "long"
+            },
+            "key": "category",
+            "name": "category",
+            "properties": [
+               {
+                  "description": "",
+                  "key": "name",
+                  "type": "QString"
+               },
+               {
+                  "description": "",
+                  "key": "description",
+                  "type": "QString"
+               }
+            ],
+            "relations": [
+               {
+                  "description": "",
+                  "key": "list_blog",
+                  "target": "blog",
+                  "type": "qx::QxCollection<long, std::shared_ptr<blog>>",
+                  "type_relation": "relation many-to-many"
+               }
+            ],
+            "version": 0
+         }
+      ]
+   },
+   "request_id": "842ed7b5-9b94-455f-86dc-32992866b3d5"
+}
+
+

+
+

Envoyer une liste de + requ�tes JSON

+
+ Afin de limiter le nombre de transactions entre le client et le serveur, il est possible + d'envoyer une liste de requ�tes JSON au module QxRestApi. + Chaque requ�te JSON de la liste peut disposer de son propre identifiant request_id (afin + d'associer une r�ponse JSON � la requ�te correspondante). + Lorsqu'une liste de requ�tes JSON est envoy�e au module QxRestApi, alors une transaction (commit/rollback) est automatiquement cr��e (ainsi en + cas d'erreur, tous les traitements sur la base de donn�es sont annul�s). +

+ -- Exemple n�1 -- envoi 4 requ�tes JSON au + module QxRestApi (1 requ�te pour r�cup�rer les m�ta-donn�es du + projet + 3 requ�tes fetch_all avec diff�rent niveau de + r�cup�ration des relations) : +

+ Requ�te JSON :
+
+
[
+   {
+      "request_id": "53c96a23-2566-4b3d-ae6c-bff634600e79",
+      "action": "get_meta_data",
+      "entity": "*"
+   },
+   {
+      "request_id": "56e3ca99-5c12-4aca-aa6c-7d0e43c1e636",
+      "action": "fetch_all",
+      "entity": "blog"
+   },
+   {
+      "request_id": "692968e4-8885-41ad-b918-6ce2791b3bb8",
+      "action": "fetch_all",
+      "entity": "blog",
+      "data": [
+         {
+            "key": "",
+            "value": ""
+         }
+      ]
+   },
+   {
+      "request_id": "4ffe38a6-d642-44b0-8be1-198e84256321",
+      "action": "fetch_all",
+      "entity": "blog",
+      "relations": [
+         "*->*"
+      ]
+   }
+]
+
+ R�ponse JSON :
+
+
[
+   {
+      "data": {
+         "entities": [
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "author_id",
+                  "type": "QString"
+               },
+               "key": "author",
+               "name": "author",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "name",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "birthdate",
+                     "type": "QDate"
+                  },
+                  {
+                     "description": "",
+                     "key": "sex",
+                     "type": "enum author::enum_sex *"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "list_blog",
+                     "target": "blog",
+                     "type": "std::vector<std::shared_ptr<blog>>",
+                     "type_relation": "relation one-to-many"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "blog_id",
+                  "type": "long"
+               },
+               "key": "blog",
+               "name": "blog",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "blog_text",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "date_creation",
+                     "type": "QDateTime"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "author_id",
+                     "target": "author",
+                     "type": "std::shared_ptr<author>",
+                     "type_relation": "relation many-to-one"
+                  },
+                  {
+                     "description": "",
+                     "key": "list_comment",
+                     "target": "comment",
+                     "type": "QList<std::shared_ptr<comment>>",
+                     "type_relation": "relation one-to-many"
+                  },
+                  {
+                     "description": "",
+                     "key": "list_category",
+                     "target": "category",
+                     "type": "qx::QxCollection<long, QSharedPointer<category>>",
+                     "type_relation": "relation many-to-many"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "comment_id",
+                  "type": "long"
+               },
+               "key": "comment",
+               "name": "comment",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "comment_text",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "date_creation",
+                     "type": "QDateTime"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "blog_id",
+                     "target": "blog",
+                     "type": "std::shared_ptr<blog>",
+                     "type_relation": "relation many-to-one"
+                  }
+               ],
+               "version": 0
+            },
+            {
+               "base_entity": "",
+               "description": "",
+               "entity_id": {
+                  "description": "",
+                  "key": "category_id",
+                  "type": "long"
+               },
+               "key": "category",
+               "name": "category",
+               "properties": [
+                  {
+                     "description": "",
+                     "key": "name",
+                     "type": "QString"
+                  },
+                  {
+                     "description": "",
+                     "key": "description",
+                     "type": "QString"
+                  }
+               ],
+               "relations": [
+                  {
+                     "description": "",
+                     "key": "list_blog",
+                     "target": "blog",
+                     "type": "qx::QxCollection<long, std::shared_ptr<blog>>",
+                     "type_relation": "relation many-to-many"
+                  }
+               ],
+               "version": 0
+            }
+         ]
+      },
+      "request_id": "53c96a23-2566-4b3d-ae6c-bff634600e79"
+   },
+   {
+      "data": [
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 1,
+            "blog_text": "save recursive blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 5,
+            "blog_text": "save another blog from QxOrm REST API !",
+            "date_creation": "2016-06-12T08:33:12",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 6,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 7,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         }
+      ],
+      "request_id": "56e3ca99-5c12-4aca-aa6c-7d0e43c1e636"
+   },
+   {
+      "data": [
+         {
+            "key": 1,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_1",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 1,
+               "blog_text": "save recursive blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 5,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_1",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 5,
+               "blog_text": "save another blog from QxOrm REST API !",
+               "date_creation": "2016-06-12T08:33:12",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 6,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_save_recursive",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 6,
+               "blog_text": "save recursive - new blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         },
+         {
+            "key": 7,
+            "value": {
+               "author_id": {
+                  "author_id": "author_id_save_recursive",
+                  "birthdate": null,
+                  "list_blog": [],
+                  "name": "",
+                  "sex": 2
+               },
+               "blog_id": 7,
+               "blog_text": "save recursive - new blog from QxOrm REST API",
+               "date_creation": "2013-11-25T09:56:33",
+               "list_category": [],
+               "list_comment": []
+            }
+         }
+      ],
+      "request_id": "692968e4-8885-41ad-b918-6ce2791b3bb8"
+   },
+   {
+      "data": [
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": "2019-04-02",
+               "list_blog": [
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 5,
+                     "blog_text": "save another blog from QxOrm REST API !",
+                     "date_creation": "2016-06-12T08:33:12",
+                     "list_category": [],
+                     "list_comment": []
+                  },
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 1,
+                     "blog_text": "save recursive blog from QxOrm REST API",
+                     "date_creation": "2013-11-25T09:56:33",
+                     "list_category": [],
+                     "list_comment": []
+                  }
+               ],
+               "name": "author_1",
+               "sex": 0
+            },
+            "blog_id": 1,
+            "blog_text": "save recursive blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_1",
+               "birthdate": "2019-04-02",
+               "list_blog": [
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 5,
+                     "blog_text": "save another blog from QxOrm REST API !",
+                     "date_creation": "2016-06-12T08:33:12",
+                     "list_category": [],
+                     "list_comment": []
+                  },
+                  {
+                     "author_id": {
+                        "author_id": "author_id_1",
+                        "birthdate": null,
+                        "list_blog": [],
+                        "name": "",
+                        "sex": 2
+                     },
+                     "blog_id": 1,
+                     "blog_text": "save recursive blog from QxOrm REST API",
+                     "date_creation": "2013-11-25T09:56:33",
+                     "list_category": [],
+                     "list_comment": []
+                  }
+               ],
+               "name": "author_1",
+               "sex": 0
+            },
+            "blog_id": 5,
+            "blog_text": "save another blog from QxOrm REST API !",
+            "date_creation": "2016-06-12T08:33:12",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 6,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         },
+         {
+            "author_id": {
+               "author_id": "author_id_save_recursive",
+               "birthdate": null,
+               "list_blog": [],
+               "name": "",
+               "sex": 2
+            },
+            "blog_id": 7,
+            "blog_text": "save recursive - new blog from QxOrm REST API",
+            "date_creation": "2013-11-25T09:56:33",
+            "list_category": [],
+            "list_comment": []
+         }
+      ],
+      "request_id": "4ffe38a6-d642-44b0-8be1-198e84256321"
+   }
+]
+
+

+
+
+ +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/manual_qxee.html b/doc/qxorm_fr/manual_qxee.html new file mode 100644 index 0000000..c8a0b16 --- /dev/null +++ b/doc/qxorm_fr/manual_qxee.html @@ -0,0 +1,5824 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic + editor (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Manuel d'utilisation de l'application + QxEntityEditor + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + + +
+ S�lection du manuel : + + Manuel QxOrm + Manuel QxEntityEditor +
+
+
+ + + + + + + + + +
+

Manuel d'utilisation de l'application QxEntityEditor - Table des + mati�res

+
+
    +
  1. + Introduction +
      +
    1. + QxEntityEditor : �diteur graphique pour la biblioth�que + QxOrm +
    2. +
    3. + T�l�chargement et installation +
    4. +
    5. + Vid�os de pr�sentation de l'application + QxEntityEditor +
    6. +
    +
  2. +
  3. + Pr�sentation g�n�rale +
      +
    1. + Vues de l'�cran principal de QxEntityEditor +
        +
      1. + Zoomer/d�zoomer le diagramme d'entit�s +
      2. +
      3. + Affichage en mode "splitter" +
      4. +
      +
    2. +
    3. + Param�trage de l'application QxEntityEditor +
    4. +
    5. + Enregistrer un code licence +
    6. +
    7. + Cr�er/ouvrir un projet *.qxee +
        +
      1. + Architecture d'un fichier projet *.qxee (base + de donn�es SQLite) +
      2. +
      +
    8. +
    9. + Param�trage d'un projet *.qxee +
    10. +
    11. + Gestion des entit�s +
        +
      1. + Cr�er une entit� +
      2. +
      3. + Modifier une entit� +
      4. +
      5. + Supprimer une entit� +
      6. +
      7. + Cloner une entit� +
      8. +
      9. + Param�tres d'une entit� +
      10. +
      11. + Couleur associ�e � une entit� +
      12. +
      +
    12. +
    13. + Gestion des propri�t�s associ�es � une entit� +
        +
      1. + Ajouter/modifier/supprimer une + propri�t� +
      2. +
      3. + Param�trage d�taill� d'une propri�t� +
      4. +
      +
    14. +
    15. + Gestion des relations entre entit�s +
        +
      1. + Ajouter/modifier/supprimer une + relation +
      2. +
      3. + Param�trage d�taill� d'une relation +
      4. +
      +
    16. +
    17. + Gestion des �num�rations +
        +
      1. + Ajouter/modifier/supprimer/cloner une + �num�ration +
      2. +
      3. + Param�tres d'une �num�ration +
      4. +
      5. + Couleur associ�e � une �num�ration +
      6. +
      +
    18. +
    19. + Gestion des espaces de nom (namespace) +
        +
      1. + Renommer un espace de nom +
      2. +
      3. + Gestion des couleurs d'un espace + de nom +
      4. +
      +
    20. +
    21. + Gestion des notes (ou post-it) +
        +
      1. + Ajouter/modifier/supprimer/cloner une + note +
      2. +
      3. + Couleur associ�e � une note +
      4. +
      +
    22. +
    23. + Organisation automatique du diagramme + d'entit�s +
    24. +
    25. + Historique d'un projet *.qxee +
    26. +
    27. + Aper�u du code C++ d'une entit�/�num�ration +
    28. +
    29. + Convention de nommage (snake_case, camelCase) +
    30. +
    31. + Liste des plugins disponibles +
    32. +
    +
  4. +
  5. + Plugins d'import +
      +
    1. + Importer un projet � partir d'un + r�pertoire associ� � un gestionnaire de code source (Git, Perforce, CVS, + etc.) +
    2. +
    3. + Importer un projet � partir d'un fichier texte au + format JSON +
    4. +
    5. + Importer � partir d'une base de donn�es MySQL ou + MariaDB +
    6. +
    7. + Importer � partir d'une base de donn�es + PostgreSQL +
    8. +
    9. + Importer � partir d'une base de donn�es + SQLite +
    10. +
    11. + Importer � partir d'une base de donn�es en + utilisant un driver ODBC (Oracle, MS SQL Server, etc.) +
    12. +
    +
  6. +
  7. + Plugins d'export +
      +
    1. + Exporter en projet C++ +
        +
      1. + Param�tres de l'export C++ +
      2. +
      3. + Pr�sentation du projet C++ + g�n�r� +
      4. +
      5. + Compilation du projet C++ + g�n�r� (par qmake ou cmake) +
      6. +
      7. + Exemple d'utilisation +
      8. +
      +
    2. +
    3. + Exporter en projet C++ de type + model/view +
        +
      1. + Param�tres de + l'export +
      2. +
      3. + Pr�sentation du + projet g�n�r� +
      4. +
      +
    4. +
    5. + Exporter en projet C++ de type + services +
        +
      1. + Param�tres de + l'export +
      2. +
      3. + Pr�sentation du projet + g�n�r� +
      4. +
      5. + Serveur + d'applications g�n�rique +
      6. +
      +
    6. +
    7. + Exporter le sch�ma de base de donn�es SQL + DDL +
    8. +
    9. + Imprimer le diagramme d'entit�s +
    10. +
    11. + Exporter le projet dans un + r�pertoire associ� � un gestionnaire de code source (Git, Perforce, CVS, + etc.) +
    12. +
    13. + Exporter le projet sous format XML ou JSON +
    14. +
    +
  8. +
  9. + Moteur Javascript pour personnaliser les exports +
      +
    1. + Architecture et fonctionnement du moteur de + personnalisation Javascript +
        +
      1. + Liste des param�tres d'appel du moteur + Javascript +
      2. +
      +
    2. +
    3. + Fonctions disponibles par Javascript +
        +
      1. + Obtenir les informations associ�es + � une entit� +
      2. +
      3. + Parcourir la liste des + propri�t�s d'une entit� +
      4. +
      5. + Obtenir les informations + associ�es � une propri�t� +
      6. +
      7. + Obtenir les informations associ�es � + une �num�ration +
      8. +
      9. + Acc�s aux m�ta-donn�es d'une + entit�/propri�t�/�num�ration +
      10. +
      11. + Acc�der aux variables + d'environnement +
      12. +
      13. + Gestion des fichiers : lecture et + �criture +
      14. +
      15. + Obtenir la liste des toutes les + entit�s/�num�rations d'un projet +
      16. +
      17. + R�cup�rer le param�trage de + l'application (niveau global, projet et plugin) +
      18. +
      +
    4. +
    5. + Ajout d'une action (placeholder) + personnalis�e dans le template d'export C++ +
    6. +
    7. + Exemple de script : ajout automatique + de la d�finition Q_PROPERTY sur les propri�t�s C++ g�n�r�es +
    8. +
    9. + Activation du d�bogueur Javascript int�gr� +
    10. +
    +
  10. +
  11. + Ex�cution de scripts personnalis�s avant/apr�s ex�cution + d'un plugin +
  12. +
  13. + Ex�cuter QxEntityEditor en ligne de commande +
  14. +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt + Ambassador Program + +
+
+
+
+ +

Introduction

+
+ L'objectif de ce manuel utilisateur est de pr�senter de mani�re structur�e l'ensemble des + fonctionnalit�s propos�es par l'application QxEntityEditor (�diteur graphique de la + biblioth�que QxOrm). + Ce manuel est destin� aux d�veloppeurs et architectes logiciel qui souhaitent g�rer une couche de + donn�es persistante en C++/Qt. + Des comp�tences techniques en C++ et base de donn�es sont requises pour la bonne compr�hension de + ce document. +

+ Remarque : un manuel utilisateur d�di� � la biblioth�que + QxOrm est �galement disponible. +

+

QxEntityEditor : �diteur + graphique pour la biblioth�que QxOrm

+
+ QxEntityEditor est un �diteur graphique pour la biblioth�que QxOrm : + QxEntityEditor permet de g�rer graphiquement le mod�le d'entit�s.
+ QxEntityEditor est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et + g�n�re du code natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu� + et mobile (Android, iOS, Windows Phone, Raspberry Pi, etc.).
+
+ QxEntityEditor est bas� sur un syst�me de plugins et propose diverses fonctionnalit�s + pour importer/exporter le mod�le de donn�es : + + + + + + + + + + + + + + + + + +
QxEntityEditor on Windows + QxEntityEditor on Linux + QxEntityEditor on Mac OS X +
QxEntityEditor on WindowsQxEntityEditor on LinuxQxEntityEditor on Mac OS X
+

+ QxEntityEditor est d�velopp� XDL Teamarty, Ing�nieur en d�veloppement logiciel depuis + 2003.
+

+
+

T�l�chargement + et installation

+
+ L'application QxEntityEditor peut �tre t�l�charg�e sur la page de + t�l�chargement du site QxOrm. + Plusieurs versions sont disponibles : +
    +
  • Windows (de Windows XP � Windows 10) en mode 32bits et 64bits ;
  • +
  • Linux (les distributions les plus populaires sont support�es, Ubuntu, Fedora, + etc...) en mode 32bits et 64bits ;
  • +
  • Mac OS X (64bits uniquement).
  • +
+ Pour Windows, QxEntityEditor est disponible avec un setup d'installation ou bien un fichier ZIP + portable.
+ Pour Linux et Mac OS X, QxEntityEditor est disponible uniquement en fichier ZIP portable.
+ Aucune d�pendance suppl�mentaire n'est requise, l'installation est tr�s simple : il suffit de + d�zipper le fichier t�l�charg� et de lancer l'ex�cutable QxEntityEditor. +

+
+

Vid�os de pr�sentation + de l'application QxEntityEditor

+
+ Voici une vid�o de + pr�sentation de l'application QxEntityEditor :
+
+
+
+ Cette vid�o pr�sente les �tapes suivantes : +
    +
  • T�l�charger et installer la biblioth�que QxOrm (10s) ;
  • +
  • T�l�charger et installer l'application QxEntityEditor (56s) ;
  • +
  • Cr�er un projet QxEntityEditor (1m 46s) ;
  • +
  • Exporter les entit�s vers un projet C++/Qt (8m 26s) ;
  • +
  • Exporter les entit�s vers un script DDL SQL de base de donn�es (10m 22s) ;
  • +
  • Cr�er une application client/serveur pour transf�rer son mod�le de donn�es sur le r�seau + (12m 31s) ; +
  • +
  • Exporter un projet QxEntityEditor vers un fichier XML ou JSON (17m 13s) ;
  • +
  • Ex�cuter QxEntityEditor en ligne de commande (sans IHM) (18m 07s).
  • +
+
+
+
+ Voici une autre vid�o de + l'application QxEntityEditor pour montrer comment importer une structure de base de + donn�es existante (projet MySQL Workbench) :
+
+
+
+ Cette vid�o pr�sente les �tapes suivantes : +
    +
  • Projet MySQL Workbench - exemple de base de donn�es Sakila (10s) ;
  • +
  • Cr�ation d'un DSN pour se connecter � MySQL par ODBC (46s) ;
  • +
  • Import de la structure de base de donn�es dans un projet QxEntityEditor (1m 15s) ; +
  • +
  • Export du projet QxEntityEditor vers un projet C++ Qt (3m 10s) ;
  • +
  • Compilation des classes g�n�r�es du projet C++ Qt (4m 22s).
  • +
+
+
+
+ +

Pr�sentation g�n�rale +

+
+ QxEntityEditor est un �diteur graphique permettant de g�rer : entit�s, propri�t�s, relations + entre entit�s, �num�rations, espaces de nom (namespace). + Pour faire le lien entre la base de donn�es et le code C++ : +
    +
  • une entit� correspond � une table c�t� base de donn�es, et � une classe c�t� code C++ ;
  • +
  • une propri�t� correspond � une colonne d'une table c�t� base de donn�es, et � une donn�e + membre d'une classe c�t� code C++ ;
  • +
  • une relation (1-n, n-1, 1-1 ou n-n) correspond � une liaison + entre 2 tables de la base de donn�es (cl� �trang�re), et � une liaison entre 2 classes C++ ; +
  • +
  • une �num�ration correspond � une liste de valeurs disponibles c�t� code C++ (pour le moment + pas de notion c�t� base de donn�es : converti en valeur num�rique) ;
  • +
  • un espace de nom (namespace) correspond � un sch�ma de base de donn�es, et un namespace o� + se trouve une classe c�t� code C++.
  • +
+
+

Vues de l'�cran principal + de QxEntityEditor

+
+ Voici une copie �cran pr�sentant les diff�rentes zones d'affichage de l'application + QxEntityEditor : +

+ All views +

+
    +
  • Zone 1 : menu principal et barre d'outils de l'application QxEntityEditor ==> + toutes les actions sont accessibles par ces boutons ;
  • +
  • Zone 2 : liste d�roulante permettant d'acc�der rapidement aux projets charg�s + r�cemment ;
  • +
  • Zone 3 : liste sous forme d'arbre (tree view) pr�sentant les �l�ments du projet + charg�s (entit�s, propri�t�s, relations, �num�rations, espaces de nom) ;
  • +
  • Zone 4 : vue "Navigator" permettant de se d�placer rapidement dans le + diagramme d'entit�s (particuli�rement utile pour des projets volumineux) ;
  • +
  • Zone 5 : diagramme d'entit�s affichant tous les �l�ments du projet dans un vue + graphique ;
  • +
  • Zone 6 : �cran de param�trage (sous forme d'onglets) des entit�s, propri�t�s, + relations, �num�rations + pr�visualisation du code C++ ;
  • +
  • Zone 7 : zoom sur le diagramme d'entit�s.
  • +
+
+

Zoomer/d�zoomer le + diagramme d'entit�s

+
+ Il est possible de zoomer/d�zoomer le diagramme d'entit�s : +
    +
  • par le menu principal : View >> Zoom view to XX% ;
  • +
  • par la petite fen�tre (slider) tout en bas � droite de l'�cran ;
  • +
  • par menu contextuel suite � un clic-droit sur le diagramme d'entit�s, sous menu : + View >> Zoom view to XX% ; +
  • +
  • en maintenant clic-gauche + molette de la souris sur le diagramme d'entit�s.
  • +
+
+ Zoom +

+
+

Affichage en mode + "splitter"

+
+ Le menu View >> Show/hide splitter mode permet de basculer l'affichage des + onglets des param�tres des entit�s, propri�t�s, relations, �num�rations + pr�visualisation du + code C++ : +
    +
  • sur la partie droite de l'�cran permettant d'avoir un acc�s rapide � la fois sur le + diagramme d'entit�s et le d�tails des param�tres de l'�l�ment s�lectionn� ;
  • +
  • masqu� sous forme d'oglets permettant d'afficher le diagramme d'entit�s en mode plein + �cran (valeur par d�faut).
  • +
+
+ Splitter mode +

+
+
+

Param�trage de + l'application QxEntityEditor

+
+ L'acc�s au param�trage global (pour tous les projets) de l'application QxEntityEditor se fait + par le menu principal Tools >> Global settings : +

+ Global settings +
+
    +
  • Champ � QxOrm library path � : chemin d'acc�s au r�pertoire de la biblioth�que + QxOrm. Ce param�tre est requis pour d�marrer un export C++ afin de trouver le fichier de + configuration QxOrm.pri (ou QxOrm.cmake). Il est possible de renseigner un + chemin absolu, ou bien d'indiquer une variable d'environnement, par exemple : + $$(QXORM_DIR) ; +
  • +
  • Champ � Auto load last opened project at startup � : d�marre QxEntityEditor en + chargeant automatiquement le dernier projet ouvert ;
  • +
  • Champ � Display property type in entities viewer � : affiche sur le diagramme + d'entit�s le type des propri�t�s ;
  • +
  • Champ � Use old style to draw relationships � : simplifie l'affichage des + relations (1-n, n-1, 1-1 ou n-n) ;
  • +
  • Champ � Disable undo/redo feature � : d�sactive la fonctionnalit� + undo/redo, peut �tre utile pour optimiser les performances sur des projets + volumineux ; +
  • +
  • Champs � Entity/Enum/Comment width � : permet de r�gler la largeur par d�faut des + �l�ments graphiques.
  • +
+
+
+

Enregistrer un code + licence

+
+ Sans cl� de licence valide, un projet QxEntityEditor est limit� � 5 entit�s par projet. + Afin de supprimer cette limitation, l'acc�s � l'enregistrement d'un code licence se fait par le + menu principal Help >> License information : +

+ License +

+ Il suffit d'entrer la cl� de license fournie dans le champ License key, puis d'appuyer + sur le bouton Save. + Un acc�s � internet est requis pour l'enregistrement d'une cl� de licence. + Si aucune erreur n'apparait, la cl� de licence est enregistr�e et l'application QxEntityEditor + peut alors �tre utilis�e sans aucune limitation jusqu'� la date indiqu�e dans le champ + Expiration date. +

+ Remarque : si une erreur de connexion internet apparait au moment de l'enregistrement, + vous pouvez essayer de cocher la case If you are behind a proxy.... +

+ Autre remarque : pour acqu�rir une cl� de licence valide, vous pouvez nous contacter � + l'adresse suivante : ic-east.com +

+
+

Cr�er/ouvrir un + projet *.qxee

+
+ La cr�ation d'un nouveau projet QxEntityEditor se fait par le menu principal File >> + New project : +

+ Project new +
+
    +
  • Champ � Project name � : nom du projet QxEntityEditor. Le fichier du nouveau + projet portera le m�me nom avec l'extension *.qxee ;
  • +
  • Champ � Project location � : chemin d'acc�s au fichier associ� au projet + QxEntityEditor. Il est possible d'utiliser le bouton "..." afin de s�lectionner le + r�pertoire de destination.
  • +
+
+ L'ouverture d'un projet QxEntityEditor se fait par le menu principal File >> Open + project : il suffit de s�lectionner un fichier projet avec l'extension *.qxee. + Sous la barre d'outils du menu principal, une liste des projets r�cents est disponible et permet + de basculer rapidement d'un projet � un autre : +

+ Project list +

+

Architecture d'un + fichier projet *.qxee (base de donn�es SQLite)

+
+ Un fichier projet *.qxee de l'application QxEntityEditor est une base de donn�es + SQLite.
+ Un m�me projet peut �tre partag� sur tous les environnements support�s par QxEntityEditor : + Windows, Linux et Mac OS X.
+ Un fichier projet *.qxee peut �tre ouvert par un outil de gestion de base de donn�es + SQLite : par exemple, le plugin gratuit de Firefox SQLite + Manager : +

+ Project database +

+ Remarque : en utilisant la fonctionnalit� Ex�cution de + scripts personnalis�s avant/apr�s ex�cution d'un plugin, il est possible par exemple + d'appliquer un script (.bat ou .sh) modifiant certaines donn�es du projet + SQLite *.qxee apr�s un import de base de donn�es par exemple. +

+
+
+

Param�trage d'un + projet *.qxee

+
+ Le param�trage d'un projet QxEntityEditor *.qxee se fait par le menu principal Tools + >> Project settings : +

+ Project settings tab 1 +

+
    +
  • Champ � Default entity namespace � : espace de nom par d�faut des entit�s � leur + cr�ation (il est possible de d�finir un autre espace de nom dans l'�cran de param�trage d'une entit�) ;
  • +
  • Champ � Table name prefix � : pr�fixe � appliquer sur la table associ�e � une + entit� ;
  • +
  • Champ � Table name suffix � : suffixe � appliquer sur la table associ�e � une + entit� ;
  • +
  • Champ � Primary key prefix � : pr�fixe par d�faut de la cl� primaire d'une entit� + ;
  • +
  • Champ � Primary key suffix � : suffixe par d�faut de la cl� primaire d'une entit� + ;
  • +
  • Champ � Default primary key type � : type C++ par d�faut pour les cl�s primaires ; +
  • +
  • Champ � Default property type � : type C++ par d�faut pour les propri�t�s des + entit�s.
  • +
+
+ Le 2�me onglet de l'�cran de param�trage d'un projet permet de g�rer les couleurs des diff�rents + �l�ments du diagramme d'entit�s au niveau projet : +

+ Project settings tab 2 +

+ Remarque : les couleurs des �l�ments du diagramme d'entit�s peuvent �tre g�r�es � + plusieurs niveaux (du niveau le plus global au plus sp�cifique) : + +
+
+

Gestion des entit�s

+
+ Une entit� dans l'application QxEntityEditor correspond � une table de la base de donn�es, et + correspond �galement � une classe (persistante et enregistr�e dans le contexte QxOrm) dans le + code C++. + L'application QxEntityEditor permet de cr�er, modifier, supprimer et cloner une entit�. +

+

Cr�er une + entit�

+
+ La cr�ation d'une nouvelle entit� se fait par : +
    +
  • Le menu principal : Actions >> New entity ;
  • +
  • Un menu contextuel sur clic-droit dans le diagramme d'entit�s : Entity >> New + entity ;
  • +
  • Le bouton Create a new entity sur l'�cran de param�trage d'une entit� lorsque + aucune entit� n'est s�lectionn�e.
  • +
+
+ Entity new +

+ Remarque : ces actions ouvrent l'�cran de param�trage d'une + entit� en mode cr�ation. L'entit� sera r�ellement cr��e et ajout�e au projet + *.qxee au moment de l'enregistrement de l'�cran de param�trage. +

+
+

Modifier une + entit�

+
+ La modification d'une entit� se fait par : +
    +
  • Le menu principal : Actions >> Modify entity ;
  • +
  • Un menu contextuel sur clic-droit dans le diagramme d'entit�s : Entity >> + Modify entity ;
  • +
  • Le double-clic sur le nom d'une entit� dans le diagramme.
  • +
+
+ Entity modify +

+ Remarque : ces actions ouvrent l'�cran de param�trage d'une + entit� en mode modification. Les modifications de l'entit� seront r�ellement + appliqu�es au projet *.qxee au moment de l'enregistrement de l'�cran de param�trage. +

+
+

Supprimer une + entit�

+
+ La suppression d'une (ou plusieurs) entit� se fait par : +
    +
  • Le menu principal : Actions >> Delete entity ;
  • +
  • Un menu contextuel sur clic-droit dans le diagramme d'entit�s : Entity >> + Delete entity ;
  • +
  • La touche "Suppr" du clavier lorsqu'une (ou plusieurs) entit� est s�lectionn�e. +
  • +
+
+ Entity delete +

+
+

Cloner une + entit�

+
+ Le clonage d'une entit� se fait par : +
    +
  • Le menu principal : Actions >> Clone entity ;
  • +
  • Un menu contextuel sur clic-droit dans le diagramme d'entit�s : Entity >> + Clone entity ;
  • +
+
+ Entity clone +

+ Remarque : une entit� clon�e dispose de toutes les propri�t�s de l'entit� source. Les + relations ne sont pas clon�es. +

+
+

Param�tres d'une + entit�

+
+ Les param�tres de l'entit� s�lectionn�e sont accessibles dans l'onglet de param�trage + Entity : +

+ Entity settings +

+ Cet �cran de param�trage est divis� en plusieurs sections : +

+ -- Section Entity information (version XX) : la version de l'entit� est + incr�ment�e � chaque historique de projet cr��. +
    +
  • Champ � Name � : nom de l'entit� et de la classe C++ g�n�r�e ;
  • +
  • Champ � Table name � : nom de la table en base de donn�es associ�e � l'entit� + (utilise le pr�fixe/suffixe par d�faut d�fini dans les + param�tres du projet) ;
  • +
  • Champ � Namespace � : espace de nom de l'entit� et de la classe C++ associ�e, + chaque sous-namespace doit �tre s�par� par ::, par exemple : + ns1::ns2::ns3 ; +
  • +
  • Champ � Description � : description de l'entit� (apparait dans le code C++ + g�n�r�) ;
  • +
  • Champ � Inherit from � : entit� parente (ou classe C++ de base) : l'entit� + fille r�cup�re automatiquement la cl� primaire et la liste des propri�t�s d�finies dans + l'entit� parente ;
  • +
  • Champ � Read only � : si coch�, alors entit� en lecture seule : la biblioth�que + QxOrm autorise uniquement des requ�tes SQL de type SELECT sur l'entit� (fonctions de r�cup�ration/fetch du namespace + qx::dao de QxOrm). Si coch�, alors les requ�tes SQL de type + INSERT, UPDATE et DELETE ne sont pas disponibles. Ce param�tre + peut par exemple �tre utilis� pour mapper une entit� � une vue (lecture seule) de la + base de donn�es ; +
  • +
  • Champ � Abstract � : une entit� abstraite n'a pas de table associ�e dans la + base de donn�es, et la classe C++ g�n�r�e ne peut pas �tre instanti�e (classe abstraite) : ce param�tre peut �tre utile + par exemple pour cr�er des entit�s parentes contenant une liste de propri�t�s communes + � toutes les autres entit�s ;
  • +
  • Champ � Soft delete column � : si vide, une suppression de l'entit� en base de + donn�es correspond � une suppression physique. Si non vide, ce champ correspond � la colonne en base de donn�es utilis�e pour + effectuer une suppression logique (conserve les informations de suppression et + l'entit� reste en base de donn�es).
  • +
  • Champ � Validator method name � : nom de la m�thode de validation (par exemple + IsValid) utilis�e pour valider une entit� avant insertion et modification en + base de donn�es. L'impl�mentation de la m�thode de validation est � la charge du + d�veloppeur dans son propre fichier source *.cpp : voir le module QxValidator de la biblioth�que QxOrm + pour plus de d�tails. +
  • +
+
+ -- Section Entity triggers : +
    +
  • Cases � cocher � Before fetch, After fetch, Before insert, etc... + � : si coch�(s), ajoute les d�finitions dans le code C++ des m�thodes + onBeforeFetch(), onAfterFetch(), onBeforeInsert(), etc... + L'impl�mentation des m�thodes de trigger est � la charge du d�veloppeur dans son propre + fichier source *.cpp : voir le manuel + utilisateur de la biblioth�que QxOrm pour plus de d�tails. +
  • +
+
+ -- Section Primary key property : d�finition rapide de la cl� primaire (un param�trage d�taill� de la cl� primaire de l'entit� est + disponible). + +
+ -- Section List of properties : d�finition rapide de la liste des propri�t�s + (un param�trage d�taill� des propri�t�s de l'entit� est + disponible). Cette liste peut �tre ordonn�e par les 2 boutons fl�che haut et + fl�che bas. +
    +
  • Colonne � Name � : nom de la propri�t� de l'entit�, et nom de la donn�e membre + associ�e dans le code C++ ;
  • +
  • Colonne � Type � : type C++ de la propri�t� (le type par d�faut peut �tre + d�fini dans les param�tres du projet) ;
  • +
  • Colonne � Decoration � : ajoute une d�coration au type C++ (par exemple boost::optional pour g�rer les valeurs + NULL) ;
  • +
  • Colonne � Collection � : si la propri�t� est une liste, alors d�fini le type de + liste C++ ;
  • +
  • Colonne � Default value � : valeur par d�faut de la propri�t� ;
  • +
  • Colonne � Index � : optimisation des requ�tes SQL de type SELECT pour + les recherches en base de donn�es ;
  • +
  • Colonne � Transient � : si coch�, alors la donn�e membre C++ n'est pas mapp�e � + une colonne de la base de donn�es (la propri�t� est enregistr�e dans le contexte QxOrm + mais n'est pas persistante) ;
  • +
  • Bouton � Delete � : supprime la propri�t� de la liste.
  • +
+
+ -- Section List of relationships : d�finition rapide de la liste des relations + (un param�trage d�taill� des relations de l'entit� est + disponible). Cette liste peut �tre ordonn�e par les 2 boutons fl�che haut et + fl�che bas. +
    +
  • Colonne � Name � : nom de la relation, et nom de la donn�e membre associ�e dans + le code C++ ;
  • +
  • Colonne � Target � : entit� cible ;
  • +
  • Colonne � n-1 � : type de relation many-to-one ;
  • +
  • Colonne � 1-n � : type de relation one-to-many ;
  • +
  • Colonne � n-n � : type de relation many-to-many ;
  • +
  • Colonne � 1-1 � : type de relation one-to-one ;
  • +
  • Colonne � Decoration � : ajoute une d�coration au type C++ (pour les relations, + la biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Colonne � Collection � : si le type de relation n�cessite une liste (1-n + et n-n), alors d�fini le type de liste C++ ;
  • +
  • Colonne � Foreign key � : cl� �trang�re de la relation : nom d'une propri�t� de + l'entit� cible ;
  • +
  • Bouton � Delete � : supprime la relation de la liste.
  • +
+
+ -- Section List of meta-data : les m�ta-donn�es permettent d'ajouter des + param�tres suppl�mentaires et sont accessibles dans le code C++ (moteur d'introspection de QxOrm) et le moteur Javascript de personnalisation des exports + de QxEntityEditor. +
    +
  • Colonne � Key � : cl� de la m�ta-donn�e ;
  • +
  • Colonne � Value � : valeur de la m�ta-donn�e ;
  • +
  • Bouton � Delete � : supprime la m�ta-donn�e de la liste.
  • +
+
+
+

Couleur + associ�e � une entit�

+
+ Les couleurs d'une entit� peuvent �tre modifi�es par le menu contextuel sur un clic-droit sur + une entit� Define entity colors : +

+ Entity colors +

+ Remarque : les couleurs des �l�ments du diagramme d'entit�s peuvent �tre g�r�es � + plusieurs niveaux (du niveau le plus global au plus sp�cifique) : + +
+
+
+

Gestion des propri�t�s + associ�es � une entit�

+
+ Une propri�t� dans l'application QxEntityEditor correspond � une colonne d'une table de la base + de donn�es, et correspond �galement � une donn�e membre d'une classe C++ (enregistr�e dans le + contexte QxOrm). + L'application QxEntityEditor permet de cr�er, modifier, supprimer et ordonner les propri�t�s + d'une entit�. +

+

Ajouter/modifier/supprimer une propri�t�

+
+ L'ajout et la suppression d'une propri�t� se fait depuis l'�cran de + param�trage d'une entit� : la section List of properties de cet �cran de + param�trage permet d'ajouter et supprimer des propri�t�s. + Il est �galement possible d'ordonner cette liste pour positionner les propri�t�s dans l'ordre + voulu. +

+ La modification d'une propri�t� est accessible par un bouton qui s'affiche sur le diagramme + d'entit�s lorsque la souris est positionn�e sur une propri�t� : +

+ Property settings access +

+
+

Param�trage + d�taill� d'une propri�t�

+
+ Les param�tres d�taill�s d'une propri�t� s�lectionn�e sont accessibles dans l'onglet de + param�trage Property : +

+ Property settings +

+ Cet �cran de param�trage est divis� en plusieurs sections : +

+ -- Section Property information (version XX) : la version de la propri�t� + d�pend du niveau d'historique du projet. +
    +
  • Champ � Name � : nom de la propri�t� de l'entit�, et nom de la donn�e membre + associ�e dans le code C++ ;
  • +
  • Champ � Column name � : nom de la colonne dans la base de donn�es (si vide, + alors Column name == Name) ;
  • +
  • Champ � Description � : description de la propri�t� (apparait dans le code C++ + g�n�r�) ;
  • +
  • Champ � Index � : optimisation des requ�tes SQL de type SELECT pour les + recherches en base de donn�es ;
  • +
  • Champ � Transient � : si coch�, alors la donn�e membre C++ n'est pas mapp�e � + une colonne de la base de donn�es (la propri�t� est enregistr�e dans le contexte QxOrm + mais n'est pas persistante) ;
  • +
  • Champ � Serializable � : si coch�, la propri�t� est prise en compte par le moteur de s�rialisation de la biblioth�que + QxOrm ;
  • +
  • Champ � Obsolete � : cocher cette option pour supprimer une propri�t� sans casser la compatibilit� ascendante du moteur de + s�rialisation de la biblioth�que QxOrm : la propri�t� devient priv�e sans + accesseur Get/Set.
  • +
+
+ -- Section Property type : +
    +
  • Champ � Type � : type C++ de la propri�t� (le type par d�faut peut �tre d�fini + dans les param�tres du projet) ; +
  • +
  • Champ � Decoration � : ajoute une d�coration au type C++ (par exemple boost::optional pour g�rer les valeurs + NULL) ;
  • +
  • Champ � Default value � : valeur par d�faut de la propri�t� ;
  • +
  • Champ � Collection � : si la propri�t� est une liste, alors d�fini le type de + liste C++.
  • +
+
+ -- Section Property validation : validation d'une propri�t� avant + insertion/modification en base de donn�es par le module + QxValidator de la biblioth�que QxOrm. +
    +
  • Champ � Min value � : valeur minimale autoris�e pour une propri�t� de type + num�rique ;
  • +
  • Champ � Max value � : valeur maximale autoris�e pour une propri�t� de type + num�rique ;
  • +
  • Champ � Min length � : longueur minimale autoris�e pour une propri�t� de type + chaine de caract�res ;
  • +
  • Champ � Max length � : longueur maximale autoris�e pour une propri�t� de type + chaine de caract�res ;
  • +
  • Champ � Regular expression � : expression r�guli�re utilis�e pour valider la + valeur d'une propri�t� ;
  • +
  • Champ � Not NULL � : v�rifie que la valeur + de la propri�t� n'est pas NULL ;
  • +
  • Champ � Unique � : valeur unique en base de donn�es : 2 lignes dans la table ne + peuvent avoir la m�me valeur sur la colonne associ�e � cette propri�t�.
  • +
+
+ -- Section Advanced : +
    +
  • Champ � Accessibility �, valeurs � public, protected ou + private � : une propri�t� public est accessible sans accesseur + Get/Set, une propri�t� protected est accessible uniquement par les + classes d�riv�es, une propri�t� private est accessible uniquement par les + accesseurs Get/Set ; +
  • +
  • Champ � SQL type � : la biblioth�que QxOrm associe automatiquement un type SQL en fonction du + type C++ de la propri�t�, il est possible de surcharger le type SQL par d�faut + avec ce param�tre ;
  • +
  • Champ � SQL alias � : force un alias sur cette colonne utilis� par la + biblioth�que QxOrm lors de la construction des requ�tes SQL ;
  • +
  • Champ � Format � : d�fini le format (syntaxe printf) de la propri�t� + pour le stockage en base de donn�es (peut �tre utile pour g�rer les dates et heures par + exemple) ;
  • +
  • Champ � Get/Set accessors � : si coch�, des accesseurs Get/Set seront + disponibles dans la classe C++ pour acc�der/modifier la valeur de la propri�t� ;
  • +
  • Champ � Read only � : si coch�, un seul accesseur Get est disponible + dans la classe C++, ce qui rend la propri�t� en lecture seule ;
  • +
  • Champ � Get method implementation � : permet de surcharger l'impl�mentation par + d�faut de la m�thode Get dans la classe C++ pour acc�der � la valeur de la + propri�t� ;
  • +
  • Champ � Set method implementation � : permet de surcharger l'impl�mentation par + d�faut de la m�thode Set dans la classe C++ pour modifier la valeur de la + propri�t�.
  • +
+
+ -- Section List of meta-data : les m�ta-donn�es permettent d'ajouter des + param�tres suppl�mentaires et sont accessibles dans le code C++ (moteur d'introspection de QxOrm) et le moteur Javascript de personnalisation des exports + de QxEntityEditor. +
    +
  • Colonne � Key � : cl� de la m�ta-donn�e ;
  • +
  • Colonne � Value � : valeur de la m�ta-donn�e ;
  • +
  • Bouton � Delete � : supprime la m�ta-donn�e de la liste.
  • +
+
+
+
+

Gestion des relations + entre entit�s

+
+ Une relation entre 2 entit�s (1-n, n-1, 1-1 ou n-n) dans + l'application QxEntityEditor permet de lier 2 tables dans la base de donn�es, et 2 classes dans + le code C++. + L'application QxEntityEditor permet de cr�er, modifier, supprimer et ordonner les relations + d'une entit�. +

+

Ajouter/modifier/supprimer une relation

+
+ L'ajout et la suppression d'une relation se fait depuis l'�cran de + param�trage d'une entit� : la section List of relationships de cet �cran de + param�trage permet d'ajouter et supprimer des relations. + Il est �galement possible d'ordonner cette liste pour positionner les relations dans l'ordre + voulu. +

+ La modification d'une relation est accessible par un bouton qui s'affiche sur le diagramme + d'entit�s lorsque la souris est positionn�e sur une relation : +

+ Relation settings access +

+
+

Param�trage + d�taill� d'une relation

+
+ Les param�tres d�taill�s d'une relation s�lectionn�e sont accessibles dans l'onglet de + param�trage Relationship : +

+ Relation settings +

+ Cet �cran de param�trage est divis� en plusieurs sections : +

+ -- Section Relationship information (version XX) : la version de la relation + d�pend du niveau d'historique du projet. +
    +
  • Champ � Name � : nom de la relation, et nom de la donn�e membre associ�e dans + le code C++ ;
  • +
  • Champ � Target � : entit� cible ;
  • +
  • Champ � Description � : description de la relation (apparait dans le code C++ + g�n�r�) ;
  • +
  • Champs � 1-n, n-1, 1-1 ou n-n � : type de relation, suivant le type s�lectionn� + certains param�tres sont actifs ou inactifs ;
  • +
  • Champ � Column name � : actif uniquement pour les relations de type n-1, + nom de la colonne dans la base de donn�es (si vide, alors Column name == + Name) ; +
  • +
  • Champ � Decoration � : ajoute une d�coration au type C++ (pour les relations, + la biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Champ � Collection � : si le type de relation n�cessite une liste (1-n + et n-n), alors d�fini le type de liste C++ ;
  • +
  • Champ � Foreign key � : cl� �trang�re de la relation : nom d'une propri�t� de + l'entit� cible ;
  • +
  • Champ � FK owner � : utilis� uniquement pour les relations de type n-n ; +
  • +
  • Champ � Extra-table � : utilis� uniquement pour les relations de type + n-n, correspond au nom de la table qui lie les 2 entit�s ; +
  • +
  • Champ � Index � : optimisation des requ�tes SQL de type SELECT pour les + recherches en base de donn�es ;
  • +
  • Champ � Serializable � : si coch�, la relation est prise en compte par le moteur de s�rialisation de la biblioth�que + QxOrm ;
  • +
  • Champ � Obsolete � : cocher cette option pour supprimer une relation sans casser la compatibilit� ascendante du moteur de + s�rialisation de la biblioth�que QxOrm : la relation devient priv�e sans + accesseur Get/Set.
  • +
+
+ -- Section Advanced : +
    +
  • Champ � Accessibility �, valeurs � public, protected ou + private � : une relation public est accessible sans accesseur + Get/Set, une relation protected est accessible uniquement par les classes + d�riv�es, une relation private est accessible uniquement par les accesseurs + Get/Set ; +
  • +
  • Champ � Get/Set accessors � : si coch�, des accesseurs Get/Set seront + disponibles dans la classe C++ pour acc�der/modifier la valeur de la relation ;
  • +
  • Champ � Read only � : si coch�, un seul accesseur Get est disponible + dans la classe C++, ce qui rend la relation en lecture seule ;
  • +
  • Champ � Get method implementation � : permet de surcharger l'impl�mentation par + d�faut de la m�thode Get dans la classe C++ pour acc�der � la valeur de la + relation ;
  • +
  • Champ � Set method implementation � : permet de surcharger l'impl�mentation par + d�faut de la m�thode Set dans la classe C++ pour modifier la valeur de la + relation.
  • +
+
+ -- Section List of meta-data : les m�ta-donn�es permettent d'ajouter des + param�tres suppl�mentaires et sont accessibles dans le code C++ (moteur d'introspection de QxOrm) et le moteur Javascript de personnalisation des exports + de QxEntityEditor. +
    +
  • Colonne � Key � : cl� de la m�ta-donn�e ;
  • +
  • Colonne � Value � : valeur de la m�ta-donn�e ;
  • +
  • Bouton � Delete � : supprime la m�ta-donn�e de la liste.
  • +
+
+
+
+

Gestion des �num�rations +

+
+ Une �num�ration dans l'application QxEntityEditor correspond � une liste de valeurs disponibles + c�t� code C++ (pour le moment pas de notion c�t� base de donn�es : converti en valeur + num�rique). + L'application QxEntityEditor permet de cr�er, modifier, supprimer et cloner une �num�ration. +

+

Ajouter/modifier/supprimer/cloner une �num�ration

+
+ L'ajout, la modification, la suppression et le clonage d'une �num�ration se fait de la m�me + fa�on que pour une entit�.
+ Une �num�ration dispose des m�mes menus qu'une entit�. +

+
+

Param�tres + d'une �num�ration

+
+ Les param�tres de l'�num�ration s�lectionn�e sont accessibles dans l'onglet de param�trage + Enumeration : +

+ Enumeration settings +

+ Cet �cran de param�trage est divis� en plusieurs sections : +

+ -- Section Enumeration information (version XX) : la version de l'�num�ration + est incr�ment�e � chaque historique de projet cr��. +
    +
  • Champ � Name � : nom de l'�num�ration et de la classe C++ g�n�r�e ;
  • +
  • Champ � Description � : description de l'�num�ration (apparait dans le code C++ + g�n�r�) ;
  • +
  • Champ � Namespace � : espace de nom de l'�num�ration et de la classe C++ + associ�e, chaque sous-namespace doit �tre s�par� par ::, par exemple : + ns1::ns2::ns3 ; +
  • +
  • Champ � Use Qt macro Q_ENUM � : utilise la macro Q_ENUM + fournie par Qt pour d�finir une �num�ration compatible avec le moteur + d'introspection de Qt ;
  • +
+
+ -- Section List of values : liste des valeurs de l'�num�ration. +
    +
  • Colonne � Key � : cl� associ� � la valeur ;
  • +
  • Colonne � Value � : valeur ;
  • +
  • Bouton � Delete � : supprime la valeur de la liste.
  • +
+
+ -- Section List of meta-data : les m�ta-donn�es permettent d'ajouter des + param�tres suppl�mentaires et sont accessibles dans le code C++ (moteur d'introspection de QxOrm) et le moteur Javascript de personnalisation des exports + de QxEntityEditor. +
    +
  • Colonne � Key � : cl� de la m�ta-donn�e ;
  • +
  • Colonne � Value � : valeur de la m�ta-donn�e ;
  • +
  • Bouton � Delete � : supprime la m�ta-donn�e de la liste.
  • +
+
+
+

Couleur associ�e � + une �num�ration

+
+ Les couleurs d'une �num�ration peuvent �tre modifi�es par le menu contextuel sur un + clic-droit sur une �num�ration Define enumeration colors : +

+ Enumeration colors +

+ Remarque : les couleurs des �l�ments du diagramme d'entit�s peuvent �tre g�r�es � + plusieurs niveaux (du niveau le plus global au plus sp�cifique) : + +
+
+
+

Gestion des espaces de nom + (namespace)

+
+ Un espace de nom (ou namespace) dans l'application QxEntityEditor permet de regrouper plusieurs + entit�s et �num�rations dans une m�me zone. + C�t� base de donn�es, un espace de nom repr�sente g�n�ralement un sch�ma. + C�t� code C++, un espace de nom regroupe plusieurs classes ou fonctions C++ dans une m�me zone. +

+ La notion d'espace de nom est utilis�e par la fonction : Organisation automatique du diagramme d'entit�s (permet + un regroupement automatique). +

+ La gestion des espaces de nom dans QxEntityEditor se fait depuis l'arborescence du projet : +

+ Namespace menu +

+

Renommer un + espace de nom

+
+ Pour renommer un espace de nom, il faut faire un clic-droit sur l'arborescence du projet, + puis menu contextuel Move entities to another namespace : +

+ Namespace rename +

+
+

Gestion des couleurs d'un espace de nom

+
+ Pour d�finir les couleurs des �l�ments d'un espace de nom, il faut faire un clic-droit sur + l'arborescence du projet, puis menu contextuel Define colors by namespace : +

+ Namespace colors +

+ La partie gauche de l'�cran liste tous les espaces de nom disponibles et d�finis dans le + projet.
+ La partie droite permet de d�finir les couleurs des �l�ments faisant partie de l'espace de + nom. + Il est �galement possible de d�finir une couleur de fond (de pr�f�rence, une couleur claire), + permettant de regrouper visuellement les �l�ments dans le diagramme d'entit�s. +

+ Remarque : les couleurs des �l�ments du diagramme d'entit�s peuvent �tre g�r�es � + plusieurs niveaux (du niveau le plus global au plus sp�cifique) : + +
+
+
+

Gestion des notes (ou + post-it)

+
+ Une note (ou post-it) dans l'application QxEntityEditor permet de coller une �tiquette dans le + diagramme d'entit�s pour fournir des informations sur le mod�le de donn�es ou le projet en + cours. + Cette note peut �tre positionn�e n'importe o� dans le diagramme d'entit�s. + Une note dispose d'un titre et d'un texte libre. Il est possible d'�crire du texte au format + HTML pour ajouter des couleurs, mettre en gras, en italique, etc... +

+ L'application QxEntityEditor permet de cr�er, modifier, supprimer et cloner une note. +

+ Post-it / comments +

+

Ajouter/modifier/supprimer/cloner une note

+
+ L'ajout, la modification, la suppression et le clonage d'une note se fait de la m�me fa�on + que pour une entit�.
+ Une note dispose des m�mes menus qu'une entit� (il suffit de + remplacer le terme entity par comment dans les menus). +

+
+

Couleur associ�e + � une note

+
+ Les couleurs d'une note peuvent �tre modifi�es par le menu contextuel sur un clic-droit sur + une note Define comment colors : +

+ Post-it colors +

+ Remarque : les couleurs des �l�ments du diagramme d'entit�s peuvent �tre g�r�es � + plusieurs niveaux (du niveau le plus global au plus sp�cifique) : + +
+
+
+

Organisation + automatique du diagramme d'entit�s

+
+ Une fonction permet de regrouper automatiquement les �l�ments du diagramme d'entit�s en fonction + des espaces de nom, et en fonction des relations entre entit�s : menu principal View >> + Organize diagram layout. + Cette fonction est particuli�rement utile pour organiser le diagramme d'entit�s apr�s un processus d'import par exemple. +

+ Organize diagram layout +

+
+

Historique d'un + projet *.qxee

+
+ Un projet QxEntityEditor peut �tre historis� : menu principal Actions >> Tag project + state. +

+ Chaque historique de projet fait �voluer les n� de version des diff�rents �l�ments du projet + (entit�s, propri�t�s, relations, etc...). + Ces n� de version sont utiles pour assurer une compatibilit� + ascendante avec le moteur de s�rialisation de la biblioth�que QxOrm. + L'historique de projet est �galement utilis� par l'export DDL de + sch�ma de base de donn�es : permet de suivre l'�volution du sch�ma de base de donn�es + (ajout d'une table, suppression d'une colonne, ajout d'un index, etc...). +

+ Tag project state tab 1 +

+ Le 1er onglet de l'�cran d'historique permet de poser une �tiquette (par exemple : date/heure, + num�ro de version du projet, etc...) et un commentaire en texte libre. +

+ Tag project state tab 2 +

+ Le 2�me onglet de l'�cran d'historique liste tous les historiques du projet, et permet de + r�cup�rer l'�tat d'un projet � un instant donn� sous plusieurs formats (XML, JSON ou bien + fichier projet *.qxee). +

+
+

Aper�u du code C++ + d'une entit�/�num�ration

+
+ Il est possible de pr�visualiser � tout moment le code C++ (fichier header *.h et fichier + source *.cpp) associ� � une entit� et une �num�ration (ce code C++ peut �tre g�n�r� par + le processus d'export C++). + Cette pr�visualisation est accessible en s�lectionnant un �l�ment dans le diagramme d'entit�s, + puis aller dans l'onglet C++ preview : +

+ C++ preview +

+
+

Convention de + nommage (snake_case, camelCase)

+
+ L'application QxEntityEditor fournit une fonction permettant d'appliquer rapidement une + convention de nommage sur tous les �l�ments du projet (entit�s, propri�t�s, relations, etc...). + Cette fonction conserve (ne casse pas) le mapping vers la base de donn�es. L'acc�s � cette + fonction se fait par le menu principal : Naming convention. + 3 styles de convention de nommage sont propos�s : snake_case, camelCase et + PascalCase. +

+ Naming convention +

+ Remarque : cette fonction peut �tre utile suite � un processus + d'import pour harmoniser le code C++ g�n�r�. +

+
+

Liste des plugins + disponibles

+
+ L'application QxEntityEditor est bas�e sur un syst�me de plugins pour g�rer les processus d'import/export. + Une liste des plugins disponibles avec les n� de version et une description de chaque plugin est + accessible depuis le menu principal : Help >> About plugins. +

+ List of plugins +

+
+
+ +

Plugins d'import

+
+ Tous les processus d'import de l'application QxEntityEditor sont accessibles depuis le menu + principal Import : +

+ Import plugins +

+

Importer + un projet � partir d'un r�pertoire associ� � un gestionnaire de code source (Git, Perforce, + CVS, etc.)

+
+ Un projet QxEntityEditor (fichier *.qxee) peut �tre g�r� par une �quipe de d�veloppeurs : + le code source d'un projet QxEntityEditor peut �tre export�/import� (manuellement ou en ligne de + commande) avec les plugins QxEESourceControlExport et QxEESourceControlImport.
+
+ Associ� � un gestionnaire de code source (Git, Perforce, CVS, etc.), ces 2 plugins permettent + ainsi : +
    +
  • plusieurs personnes peuvent travailler simultan�ment sur un m�me projet ;
  • +
  • un projet peut facilement �tre versionn� dans le gestionnaire de code source ;
  • +
  • chaque �l�ment d'un projet peut �tre compar� (diff�rence entre 2 versions d'une m�me + entit� par exemple).
  • +
+ Voici un exemple d'utilisation des plugins QxEESourceControlExport et QxEESourceControlImport, avec 2 d�veloppeurs + nomm�s 'dev A' et 'dev B' (l'exemple pouvant �tre �tendu � X d�veloppeurs) : +
    +
  • dev A et dev B travaillent sur un m�me projet QxEntityEditor (fichier *.qxee) ; +
  • +
  • dev A cr��/modifie/supprime certaines entit�s dans l'application QxEntityEditor ;
  • +
  • dev B cr��/modifie/supprime d'autres entit�s dans l'application QxEntityEditor ;
  • +
  • dev A et dev B exportent le projet *.qxee en utilisant le plugin QxEESourceControlExport (manuellement + ou en ligne de commande) ;
  • +
  • une fois le projet export� dans un r�pertoire, dev A et dev B enregistrent + (check-in ou submit) les fichiers JSON g�n�r�s dans le gestionnaire de code + source (Git, Perforce, CVS, etc.) sur leur propre branche de travail ;
  • +
  • depuis le gestionnaire de code source, dev A et dev B int�grent (merge ou + integrate) leur branche de travail sur la branche de d�veloppement DEV (ou MAIN ou + MASTER ou LATEST); Remarque : m�me si il y a des conflits � r�soudre, ils seront + simples � corriger car le format JSON est lisible facilement ; +
  • +
  • dev A et dev B peuvent � pr�sent obtenir la derni�re version des fichiers JSON (get + latest depuis le gestionnaire de code source) � partir de la branche DEV (ou MAIN + ou MASTER ou LATEST) : les fichiers JSON obtenus contiennent � la fois les + modifications de dev A et dev B ;
  • +
  • dev A et dev B peuvent importer ces fichiers JSON dans l'application QxEntityEditor en + utilisant le plugin d'import QxEESourceControlImport (manuellement ou + en ligne de commande).
  • +
+ Les param�tres du plugin d'import sont accessibles depuis le menu principal Import >> + Import from Source Control repository (Git, Perforce, CVS, etc.) : +

+ Source Control import plugin +

+ Le param�tre � renseigner correspond au fichier JSON pr�sent � la racine du r�pertoire o� a �t� export� le projet + *.qxee.
+ Ce fichier est nomm� <nom_du_projet>.qxee.export.json, par exemple pour le + projet de test qxBlog : qxBlog.qxee.export.json. +

+ Source Control output directory +

+ Attention : un import efface tous les �l�ments du projet courant (entit�s, propri�t�s, + relations, etc...). +

+ Remarque : il est possible de d�marrer QxEntityEditor en ligne de commande pour charger + automatiquement un r�pertoire associ� � un gestionnaire de code source au d�marrage de + l'application. +

+ Exemple de ligne de commande :
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlImport --QxEESourceControlImport_path="<path_to_the_root_source_control_json_file>"
+
+
+

+
+

Importer un projet � + partir d'un fichier texte au format JSON

+
+ + Remarque : + pour travailler avec un gestionnaire de code source (Git, Perforce, CVS, etc.), il est + conseill� d'utiliser les plugins QxEESourceControlExport et QxEESourceControlImport (au lieu de cr�er un + fichier unique).
+
+ Il est possible de g�rer un projet QxEntityEditor avec un fichier texte au format JSON : menu + principal Import >> Import from JSON file.
+ Pour connaitre la structure du fichier JSON � respecter, il est conseill� au pr�alable + d'effectuer un 1er export de projet au format JSON. +

+ Import JSON +

+ L'�cran d'import dispose d'un seul champ � renseigner : le fichier JSON � importer. +

+ Attention : un import JSON efface tous les �l�ments du projet courant (entit�s, + propri�t�s, relations, etc...). +

+ Remarque : il est possible de d�marrer QxEntityEditor en ligne de commande pour charger + automatiquement un fichier JSON au d�marrage de l'application. +

+ Exemple de ligne de commande :
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEEJsonImport --QxEEJsonImport_file="<path_to_your_json_file>"
+
+
+
+ Exemple de fichier JSON (pr�sent dans le dossier ./samples/qxBlog.json du package + QxEntityEditor) :
+
+
+{
+    "app_version": 0,
+    "description": "",
+    "dt_creation": "20131206221737",
+    "dt_modification": "20131206221737",
+    "id": 1,
+    "list_all_entities": [
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221810",
+            "dt_modification": "20140617214144",
+            "id": 1,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 1,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "author_id",
+                    "order_level": 0,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 1,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 1
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 2,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "firstname",
+                    "order_level": 1,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 2,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 2
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 3,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "lastname",
+                    "order_level": 2,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 3,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 3
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 4,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "birthdate",
+                    "order_level": 3,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 4,
+                        "list_meta_data": null,
+                        "primitive_type": "QDateTime",
+                        "property_id": {
+                            "id": 4
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 5,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "sex",
+                    "order_level": 4,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221810",
+                        "dt_modification": "20140617214144",
+                        "entity_id": null,
+                        "enumeration_id": {
+                            "id": 1
+                        },
+                        "id": 5,
+                        "list_meta_data": null,
+                        "primitive_type": "sex::enum_sex",
+                        "property_id": {
+                            "id": 5
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214144",
+                    "entity_id": {
+                        "id": 1
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 18,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_blog",
+                    "order_level": 17,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214144",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 18,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 18
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214144",
+                        "extra_table": "",
+                        "foreign_key": "author",
+                        "foreign_key_owner": "",
+                        "id": 2,
+                        "inverse_property_id": {
+                            "id": 15
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 18
+                        },
+                        "type_relation": "one-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "author",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221810",
+                "dt_modification": "20140617214144",
+                "entity_id": {
+                    "id": 1
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 1,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "author_id",
+                "order_level": 0,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221810",
+                    "dt_modification": "20140617214144",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 1,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 1
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_author",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206222031",
+            "dt_modification": "20140617214043",
+            "id": 4,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 12,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "blog_id",
+                    "order_level": 11,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 12,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 12
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 13,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "title",
+                    "order_level": 12,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 13,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 13
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 14,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "text",
+                    "order_level": 13,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 14,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 14
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 15,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "author",
+                    "order_level": 14,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 1
+                        },
+                        "enumeration_id": null,
+                        "id": 15,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 15
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "",
+                        "foreign_key": "",
+                        "foreign_key_owner": "",
+                        "id": 1,
+                        "inverse_property_id": {
+                            "id": 18
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 15
+                        },
+                        "type_relation": "many-to-one",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 16,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_comment",
+                    "order_level": 15,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 3
+                        },
+                        "enumeration_id": null,
+                        "id": 16,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 16
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "",
+                        "foreign_key": "blog_id",
+                        "foreign_key_owner": "",
+                        "id": 3,
+                        "inverse_property_id": {
+                            "id": 19
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 16
+                        },
+                        "type_relation": "one-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": {
+                        "id": 4
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 17,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_category",
+                    "order_level": 16,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "entity_id": {
+                            "id": 2
+                        },
+                        "enumeration_id": null,
+                        "id": 17,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 17
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214043",
+                        "extra_table": "t_qxee_blog_category",
+                        "foreign_key": "blog_id",
+                        "foreign_key_owner": "category_id",
+                        "id": 5,
+                        "inverse_property_id": {
+                            "id": 20
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 17
+                        },
+                        "type_relation": "many-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "blog",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206222031",
+                "dt_modification": "20140617214043",
+                "entity_id": {
+                    "id": 4
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 12,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "blog_id",
+                "order_level": 11,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214043",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 12,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 12
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_blog",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221933",
+            "dt_modification": "20140617214115",
+            "id": 2,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 6,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "category_id",
+                    "order_level": 5,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 6,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 6
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 7,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "name",
+                    "order_level": 6,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 7,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 7
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 8,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "description",
+                    "order_level": 7,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221933",
+                        "dt_modification": "20140617214115",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 8,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 8
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20140617214115",
+                    "entity_id": {
+                        "id": 2
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 20,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "list_of_blog",
+                    "order_level": 19,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214115",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 20,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 20
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20140617214115",
+                        "extra_table": "t_qxee_blog_category",
+                        "foreign_key": "category_id",
+                        "foreign_key_owner": "blog_id",
+                        "id": 6,
+                        "inverse_property_id": {
+                            "id": 17
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 20
+                        },
+                        "type_relation": "many-to-many",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "category",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221933",
+                "dt_modification": "20140617214115",
+                "entity_id": {
+                    "id": 2
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 6,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "category_id",
+                "order_level": 5,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221933",
+                    "dt_modification": "20140617214115",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 6,
+                    "list_meta_data": null,
+                    "primitive_type": "QString",
+                    "property_id": {
+                        "id": 6
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_category",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        },
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221951",
+            "dt_modification": "20131206221951",
+            "id": 3,
+            "is_abstract": false,
+            "is_read_only": false,
+            "key": "",
+            "list_functions": null,
+            "list_functions_static": null,
+            "list_meta_data": null,
+            "list_properties": [
+                {
+                    "accessibility": "protected",
+                    "allow_null": false,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 9,
+                    "is_index": true,
+                    "is_obsolete": false,
+                    "is_primary_key": true,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "comment_id",
+                    "order_level": 8,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 9,
+                        "list_meta_data": null,
+                        "primitive_type": "long",
+                        "property_id": {
+                            "id": 9
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 10,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "title",
+                    "order_level": 9,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 10,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 10
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 11,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "text",
+                    "order_level": 10,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "",
+                        "decoration": "",
+                        "default_value": "",
+                        "dt_creation": "20131206221951",
+                        "dt_modification": "20131206221951",
+                        "entity_id": null,
+                        "enumeration_id": null,
+                        "id": 11,
+                        "list_meta_data": null,
+                        "primitive_type": "QString",
+                        "property_id": {
+                            "id": 11
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": null,
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                },
+                {
+                    "accessibility": "protected",
+                    "allow_null": true,
+                    "app_version": 0,
+                    "column_name": "",
+                    "description": "",
+                    "dt_creation": "20131206222031",
+                    "dt_modification": "20131206222031",
+                    "entity_id": {
+                        "id": 3
+                    },
+                    "force_sql_alias": "",
+                    "force_sql_type": "",
+                    "format": "",
+                    "get_method": "",
+                    "id": 19,
+                    "is_index": false,
+                    "is_obsolete": false,
+                    "is_primary_key": false,
+                    "is_read_only": false,
+                    "is_serializable": true,
+                    "is_transient": false,
+                    "is_unique": false,
+                    "key": "",
+                    "list_meta_data": null,
+                    "max_length": "",
+                    "max_value": "",
+                    "min_length": "",
+                    "min_value": "",
+                    "name": "blog_id",
+                    "order_level": 18,
+                    "project_version": 0,
+                    "property_type_id": {
+                        "app_version": 0,
+                        "collection": "qx::QxCollection",
+                        "decoration": "boost::shared_ptr",
+                        "default_value": "",
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20131206222031",
+                        "entity_id": {
+                            "id": 4
+                        },
+                        "enumeration_id": null,
+                        "id": 19,
+                        "list_meta_data": null,
+                        "primitive_type": "",
+                        "property_id": {
+                            "id": 19
+                        },
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "qt_property": "",
+                    "reg_exp": "",
+                    "relation_id": {
+                        "app_version": 0,
+                        "dt_creation": "20131206222031",
+                        "dt_modification": "20131206222031",
+                        "extra_table": "",
+                        "foreign_key": "",
+                        "foreign_key_owner": "",
+                        "id": 4,
+                        "inverse_property_id": {
+                            "id": 16
+                        },
+                        "list_meta_data": null,
+                        "property_id": {
+                            "id": 19
+                        },
+                        "type_relation": "many-to-one",
+                        "user_id_creation": 0,
+                        "user_id_modification": 0
+                    },
+                    "set_method": "",
+                    "user_id_creation": 0,
+                    "user_id_modification": 0,
+                    "version": 0,
+                    "write_accessors": true
+                }
+            ],
+            "name": "comment",
+            "namespace": "",
+            "parent_id": null,
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "property_id": {
+                "accessibility": "protected",
+                "allow_null": false,
+                "app_version": 0,
+                "column_name": "",
+                "description": "",
+                "dt_creation": "20131206221951",
+                "dt_modification": "20131206221951",
+                "entity_id": {
+                    "id": 3
+                },
+                "force_sql_alias": "",
+                "force_sql_type": "",
+                "format": "",
+                "get_method": "",
+                "id": 9,
+                "is_index": true,
+                "is_obsolete": false,
+                "is_primary_key": true,
+                "is_read_only": false,
+                "is_serializable": true,
+                "is_transient": false,
+                "is_unique": false,
+                "key": "",
+                "list_meta_data": null,
+                "max_length": "",
+                "max_value": "",
+                "min_length": "",
+                "min_value": "",
+                "name": "comment_id",
+                "order_level": 8,
+                "project_version": 0,
+                "property_type_id": {
+                    "app_version": 0,
+                    "collection": "",
+                    "decoration": "",
+                    "default_value": "",
+                    "dt_creation": "20131206221951",
+                    "dt_modification": "20131206221951",
+                    "entity_id": null,
+                    "enumeration_id": null,
+                    "id": 9,
+                    "list_meta_data": null,
+                    "primitive_type": "long",
+                    "property_id": {
+                        "id": 9
+                    },
+                    "user_id_creation": 0,
+                    "user_id_modification": 0
+                },
+                "qt_property": "",
+                "reg_exp": "",
+                "relation_id": null,
+                "set_method": "",
+                "user_id_creation": 0,
+                "user_id_modification": 0,
+                "version": 0,
+                "write_accessors": true
+            },
+            "soft_delete_column": "",
+            "table_name": "t_comment",
+            "trigger_after_delete": false,
+            "trigger_after_fetch": false,
+            "trigger_after_insert": false,
+            "trigger_after_update": false,
+            "trigger_before_delete": false,
+            "trigger_before_fetch": false,
+            "trigger_before_insert": false,
+            "trigger_before_update": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "validator_method": "",
+            "version": 0
+        }
+    ],
+    "list_comments": [
+        {
+            "app_version": 0,
+            "comment_text": "- Design the entity model in few minutes\n\n- Generate C++ persistent classes automatically\n\n- Generate DDL SQL script automatically\n\n- Manage schema evolution for each project version\n\n- Compile C++ native code everywhere : Windows, Linux, MacOSX, Android, iOS, etc...\n\n- Transfer your data model over network and create quickly client/server applications",
+            "comment_text_html": false,
+            "comment_title": "qxBlog project",
+            "dt_creation": "20131206222130",
+            "dt_modification": "20140107093142",
+            "id": 1,
+            "list_meta_data": null,
+            "user_id_creation": 0,
+            "user_id_modification": 0
+        }
+    ],
+    "list_enumerations": [
+        {
+            "app_version": 0,
+            "description": "",
+            "dt_creation": "20131206221840",
+            "dt_modification": "20131210205552",
+            "id": 1,
+            "key": "",
+            "list_meta_data": null,
+            "list_of_key_value": {
+                "female": 2,
+                "male": 1,
+                "unknown": 3
+            },
+            "name": "sex",
+            "namespace": "",
+            "project_id": {
+                "id": 1
+            },
+            "project_version": 0,
+            "qt_enum": false,
+            "user_id_creation": 0,
+            "user_id_modification": 0,
+            "version": 0
+        }
+    ],
+    "list_groups": null,
+    "list_meta_data": null,
+    "list_namespaces": null,
+    "location": "C:/Temp/qxee",
+    "name": "qxBlog",
+    "project_guid": "{16335d56-73ac-48cf-8fcd-f74cc7d97201}",
+    "project_parameters": {
+        "app_version": 0,
+        "default_entity_namespace": "",
+        "default_primary_key_type": "long",
+        "default_property_type": "QString",
+        "dt_creation": "20131206221737",
+        "dt_modification": "20131206221737",
+        "id": 1,
+        "list_meta_data": null,
+        "lst_plugin_script": {
+        },
+        "primary_key_prefix": "",
+        "primary_key_suffix": "_id",
+        "project_id": {
+            "id": 1
+        },
+        "table_name_prefix": "t_",
+        "table_name_suffix": "",
+        "user_id_creation": 0,
+        "user_id_modification": 0
+    },
+    "user_id_creation": 0,
+    "user_id_modification": 0,
+    "version": 0
+}
+
+
+

+
+

Importer � partir + d'une base de donn�es MySQL ou MariaDB

+
+ L'import d'une base de donn�es MySQL (ou MariaDB) dans l'application QxEntityEditor se fait par + le menu principal : Import >> Import from MySQL (or MariaDB) database : +

+ Import MySQL or MariaDB +

+ Cet �cran d'import est divis� en plusieurs sections : +

+ -- Section MySQL (or MariaDB) database connection : +
    +
  • Champ � Database server address (IP) � : adresse IP ou nom du serveur MySQL ;
  • +
  • Champ � Database port � : n� de port pour se connecter � la base de donn�es MySQL + ;
  • +
  • Champ � Database name � : nom de la base de donn�es qu'on souhaite importer ;
  • +
  • Champ � Database login � : nom d'utilisateur pour se connecter � la base de + donn�es ;
  • +
  • Champ � Database password � : mot de passe pour se connecter � la base de donn�es + ;
  • +
  • Bouton � Connect to database � : d�marre la connexion � la base de donn�es : si + une erreur se produit, un message d'avertissement est affich�, sinon la liste des tables + de la base de donn�es apparait dans la section � Database items to import to + QxEntityEditor project �.
  • +
+
+ -- Section Import settings : +
    +
  • Champ � Namespace � : espace de nom utilis� pour regrouper + les entit�s import�es ;
  • +
  • Champ � Delete all entities in the namespace before importing � : supprime les + entit�s de l'espace de nom ci-dessus avant de d�marrer l'import des tables de la base de + donn�es ;
  • +
  • Champ � Import tables/columns comment to entities/properties description � : + importe les commentaires des tables et colonnes d�finis dans la base de donn�es ;
  • +
  • Champ � Add boost::optional<T> decoration if a column definition allows NULL + value � : ajoute automatiquement la d�coration + boost::optional pour g�rer la valeur NULL ;
  • +
  • Champ � Import columns default value � : importe les valeurs par d�faut d�finies + au niveau des colonnes de la base de donn�es ;
  • +
  • Champ � Organize diagram layout after import process � : d�marre automatiquement + une r�organisation du diagramme d'entit�s apr�s le + processus d'import. +
  • +
+
+ -- Section Relationship import settings : +
    +
  • Champ � Decoration � : d�coration par d�faut du type C++ (pour les relations, la + biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Champ � Collection � : si le type de relation n�cessite une liste (1-n et + n-n), alors d�fini le type de liste C++ par d�faut ; +
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor d�finit un + mapping par d�faut pour associer un type SQL � un type C++. + Il est possible d'utiliser cette liste pour surcharger le comportement par d�faut : +
    +
  • Colonne � SQL type � : type SQL � mapper. La recherche du type SQL n'est pas + sensible � la casse, et s'effectue sur les 1er caract�res : par exemple, mettre + varchar va mapper VARCHAR(255) ; +
  • +
  • Colonne � C++ type � : type C++ correspondant au type SQL ;
  • +
  • Bouton � Supprimer � : supprime une association type SQL / type C++.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : lorsque + QxEntityEditor est connect� � la base de donn�es, la liste de tous les �l�ments (tables, + colonnes, cl�s primaires, relations, vues, etc...) pouvant �tre import�s dans le projet + QxEntityEditor sont affich�s dans cette section. + Par d�faut, aucun �l�ment n'est s�lectionn�. + Il est possible de tout s�lectionner en 1 clic en cochant l'�l�ment racine de l'arborescence. + Il est �galement possible de s�lectionner uniquement les �l�ments appartenant � un sch�ma. + Une fois les �l�ments s�lectionn�s, le bouton � Ok � devient actif pour d�marrer le + processus d'import. +


+ Remarque : tous les param�tres d'import (connexion � la base de donn�es, param�tres + d'import et des relations, liste mapping type SQL / type C++, etc...) sont enregistr�s � la + fermeture de cette fen�tre d'import. + Tous les param�tres d'import sont automatiquement valoris�s � la r�-ouverture de la fen�tre + d'import. +

+ Autre remarque : une vid�o de QxEntityEditor est disponible + pour montrer un exemple d'import de la base de donn�es de test MySQL : sakila. +

+
+

Importer � + partir d'une base de donn�es PostgreSQL

+
+ L'import d'une base de donn�es PostgreSQL dans l'application QxEntityEditor se fait par le menu + principal : Import >> Import from PostgreSQL database : +

+ Import PostgreSQL +

+ Cet �cran d'import est divis� en plusieurs sections : +

+ -- Section PostgreSQL database connection : +
    +
  • Champ � Database server address (IP) � : adresse IP ou nom du serveur PostgreSQL ; +
  • +
  • Champ � Database port � : n� de port pour se connecter � la base de donn�es + PostgreSQL ;
  • +
  • Champ � Database name � : nom de la base de donn�es qu'on souhaite importer ;
  • +
  • Champ � Database login � : nom d'utilisateur pour se connecter � la base de + donn�es ;
  • +
  • Champ � Database password � : mot de passe pour se connecter � la base de donn�es + ;
  • +
  • Bouton � Connect to database � : d�marre la connexion � la base de donn�es : si + une erreur se produit, un message d'avertissement est affich�, sinon la liste des tables + de la base de donn�es apparait dans la section � Database items to import to + QxEntityEditor project �.
  • +
+
+ -- Section Import settings : +
    +
  • Champ � Namespace � : espace de nom utilis� pour regrouper + les entit�s import�es ;
  • +
  • Champ � Delete all entities in the namespace before importing � : supprime les + entit�s de l'espace de nom ci-dessus avant de d�marrer l'import des tables de la base de + donn�es ;
  • +
  • Champ � Import tables/columns comment to entities/properties description � : + importe les commentaires des tables et colonnes d�finis dans la base de donn�es ;
  • +
  • Champ � Add boost::optional<T> decoration if a column definition allows NULL + value � : ajoute automatiquement la d�coration + boost::optional pour g�rer la valeur NULL ;
  • +
  • Champ � Import columns default value � : importe les valeurs par d�faut d�finies + au niveau des colonnes de la base de donn�es ;
  • +
  • Champ � Organize diagram layout after import process � : d�marre automatiquement + une r�organisation du diagramme d'entit�s apr�s le + processus d'import. +
  • +
+
+ -- Section Relationship import settings : +
    +
  • Champ � Decoration � : d�coration par d�faut du type C++ (pour les relations, la + biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Champ � Collection � : si le type de relation n�cessite une liste (1-n et + n-n), alors d�fini le type de liste C++ par d�faut ; +
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor d�finit un + mapping par d�faut pour associer un type SQL � un type C++. + Il est possible d'utiliser cette liste pour surcharger le comportement par d�faut : +
    +
  • Colonne � SQL type � : type SQL � mapper. La recherche du type SQL n'est pas + sensible � la casse, et s'effectue sur les 1er caract�res : par exemple, mettre + varchar va mapper VARCHAR(255) ; +
  • +
  • Colonne � C++ type � : type C++ correspondant au type SQL ;
  • +
  • Bouton � Supprimer � : supprime une association type SQL / type C++.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : lorsque + QxEntityEditor est connect� � la base de donn�es, la liste de tous les �l�ments (tables, + colonnes, cl�s primaires, relations, vues, etc...) pouvant �tre import�s dans le projet + QxEntityEditor sont affich�s dans cette section. + Par d�faut, aucun �l�ment n'est s�lectionn�. + Il est possible de tout s�lectionner en 1 clic en cochant l'�l�ment racine de l'arborescence. + Il est �galement possible de s�lectionner uniquement les �l�ments appartenant � un sch�ma. + Une fois les �l�ments s�lectionn�s, le bouton � Ok � devient actif pour d�marrer le + processus d'import. +


+ Remarque : tous les param�tres d'import (connexion � la base de donn�es, param�tres + d'import et des relations, liste mapping type SQL / type C++, etc...) sont enregistr�s � la + fermeture de cette fen�tre d'import. + Tous les param�tres d'import sont automatiquement valoris�s � la r�-ouverture de la fen�tre + d'import. +

+ Autre remarque : une vid�o de QxEntityEditor est disponible + pour montrer un exemple d'import de la base de donn�es de test MySQL : sakila. +

+
+

Importer � partir + d'une base de donn�es SQLite

+
+ L'import d'une base de donn�es SQLite dans l'application QxEntityEditor se fait par le menu + principal : Import >> Import from SQLite database : +

+ Import SQLite +

+ Cet �cran d'import est divis� en plusieurs sections : +

+ -- Section Database connection : +
    +
  • Champ � Database path � : chemin d'acc�s au fichier base de donn�es SQLite ;
  • +
  • Bouton � Connect to database � : d�marre la connexion � la base de donn�es : si + une erreur se produit, un message d'avertissement est affich�, sinon la liste des tables + de la base de donn�es apparait dans la section � Database items to import to + QxEntityEditor project �.
  • +
+
+ -- Section Import settings : +
    +
  • Champ � Namespace � : espace de nom utilis� pour regrouper + les entit�s import�es ;
  • +
  • Champ � Delete all entities in the namespace before importing � : supprime les + entit�s de l'espace de nom ci-dessus avant de d�marrer l'import des tables de la base de + donn�es ;
  • +
  • Champ � Import tables/columns comment to entities/properties description � : + importe les commentaires des tables et colonnes d�finis dans la base de donn�es ;
  • +
  • Champ � Add boost::optional<T> decoration if a column definition allows NULL + value � : ajoute automatiquement la d�coration + boost::optional pour g�rer la valeur NULL ;
  • +
  • Champ � Import columns default value � : importe les valeurs par d�faut d�finies + au niveau des colonnes de la base de donn�es ;
  • +
  • Champ � Organize diagram layout after import process � : d�marre automatiquement + une r�organisation du diagramme d'entit�s apr�s le + processus d'import. +
  • +
+
+ -- Section Relationship import settings : +
    +
  • Champ � Decoration � : d�coration par d�faut du type C++ (pour les relations, la + biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Champ � Collection � : si le type de relation n�cessite une liste (1-n et + n-n), alors d�fini le type de liste C++ par d�faut ; +
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor d�finit un + mapping par d�faut pour associer un type SQL � un type C++. + Il est possible d'utiliser cette liste pour surcharger le comportement par d�faut : +
    +
  • Colonne � SQL type � : type SQL � mapper. La recherche du type SQL n'est pas + sensible � la casse, et s'effectue sur les 1er caract�res : par exemple, mettre + varchar va mapper VARCHAR(255) ; +
  • +
  • Colonne � C++ type � : type C++ correspondant au type SQL ;
  • +
  • Bouton � Supprimer � : supprime une association type SQL / type C++.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : lorsque + QxEntityEditor est connect� � la base de donn�es, la liste de tous les �l�ments (tables, + colonnes, cl�s primaires, relations, vues, etc...) pouvant �tre import�s dans le projet + QxEntityEditor sont affich�s dans cette section. + Par d�faut, aucun �l�ment n'est s�lectionn�. + Il est possible de tout s�lectionner en 1 clic en cochant l'�l�ment racine de l'arborescence. + Il est �galement possible de s�lectionner uniquement les �l�ments appartenant � un sch�ma. + Une fois les �l�ments s�lectionn�s, le bouton � Ok � devient actif pour d�marrer le + processus d'import. +


+ Remarque : tous les param�tres d'import (connexion � la base de donn�es, param�tres + d'import et des relations, liste mapping type SQL / type C++, etc...) sont enregistr�s � la + fermeture de cette fen�tre d'import. + Tous les param�tres d'import sont automatiquement valoris�s � la r�-ouverture de la fen�tre + d'import. +

+ Autre remarque : une vid�o de QxEntityEditor est disponible + pour montrer un exemple d'import de la base de donn�es de test MySQL : sakila. +

+
+

Importer � partir + d'une base de donn�es en utilisant un driver ODBC (Oracle, MS SQL Server, etc.)

+
+ L'application QxEntityEditor fournit un import g�n�rique de base de donn�es par connexion ODBC : + menu principal Import >> Import from database using ODBC driver. + Ce type d'import n�cessite de d�fnir un DSN (Data Source Name) dans l'environnement. + L'import par ODBC de l'application QxEntityEditor permet d'importer des bases de donn�es de type + : Oracle, Microsoft SQL Server, SQLite, MySQL/MariaDB, PostgreSQL, etc... +

+ Import ODBC +

+ Cet �cran d'import est divis� en plusieurs sections : +

+ -- Section Database connection : +
    +
  • Champ � DSN or connection string � : DSN (Data Source + Name) d�fini dans l'environnement permettant de se connecter � la base de donn�es + par ODBC ;
  • +
  • Champ � Login � : nom d'utilisateur pour se connecter � la base de donn�es + (optionnel suivant les DSN) ;
  • +
  • Champ � Password � : mot de passe pour se connecter � la base de donn�es + (optionnel suivant les DSN) ;
  • +
  • Champ � Database type � : type de base de donn�es : le type Generic permet + de se connecter � tous types de bases mais avec certaines limitations (pas de relation, + pas de cl� primaire sur plusieurs colonnes). Il est conseill� de s�lectionner le type r��l + de base de donn�es avant de d�marrer la connexion � la base (Oracle, Microsoft SQL Server, + SQLite, MySQL/MariaDB, PostgreSQL) ;
  • +
  • Bouton � Connect to database � : d�marre la connexion � la base de donn�es : si + une erreur se produit, un message d'avertissement est affich�, sinon la liste des tables + de la base de donn�es apparait dans la section � Database items to import to + QxEntityEditor project �.
  • +
+
+ -- Section Import settings : +
    +
  • Champ � Namespace � : espace de nom utilis� pour regrouper + les entit�s import�es ;
  • +
  • Champ � Delete all entities in the namespace before importing � : supprime les + entit�s de l'espace de nom ci-dessus avant de d�marrer l'import des tables de la base de + donn�es ;
  • +
  • Champ � Import tables/columns comment to entities/properties description � : + importe les commentaires des tables et colonnes d�finis dans la base de donn�es ;
  • +
  • Champ � Add boost::optional<T> decoration if a column definition allows NULL + value � : ajoute automatiquement la d�coration + boost::optional pour g�rer la valeur NULL ;
  • +
  • Champ � Import columns default value � : importe les valeurs par d�faut d�finies + au niveau des colonnes de la base de donn�es ;
  • +
  • Champ � Organize diagram layout after import process � : d�marre automatiquement + une r�organisation du diagramme d'entit�s apr�s le + processus d'import. +
  • +
+
+ -- Section Relationship import settings : +
    +
  • Champ � Decoration � : d�coration par d�faut du type C++ (pour les relations, la + biblioth�que QxOrm recommande l'utilisation de pointeurs intelligents : + boost::shared_ptr, std::shared_ptr ou QSharedPointer) ; +
  • +
  • Champ � Collection � : si le type de relation n�cessite une liste (1-n et + n-n), alors d�fini le type de liste C++ par d�faut ; +
  • +
+
+ -- Section Mapping database SQL type to C++ type : QxEntityEditor d�finit un + mapping par d�faut pour associer un type SQL � un type C++. + Il est possible d'utiliser cette liste pour surcharger le comportement par d�faut : +
    +
  • Colonne � SQL type � : type SQL � mapper. La recherche du type SQL n'est pas + sensible � la casse, et s'effectue sur les 1er caract�res : par exemple, mettre + varchar va mapper VARCHAR(255) ; +
  • +
  • Colonne � C++ type � : type C++ correspondant au type SQL ;
  • +
  • Bouton � Supprimer � : supprime une association type SQL / type C++.
  • +
+
+ -- Section Database items to import to QxEntityEditor project : lorsque + QxEntityEditor est connect� � la base de donn�es, la liste de tous les �l�ments (tables, + colonnes, cl�s primaires, relations, vues, etc...) pouvant �tre import�s dans le projet + QxEntityEditor sont affich�s dans cette section. + Par d�faut, aucun �l�ment n'est s�lectionn�. + Il est possible de tout s�lectionner en 1 clic en cochant l'�l�ment racine de l'arborescence. + Il est �galement possible de s�lectionner uniquement les �l�ments appartenant � un sch�ma. + Une fois les �l�ments s�lectionn�s, le bouton � Ok � devient actif pour d�marrer le + processus d'import. +


+ Remarque : tous les param�tres d'import (connexion � la base de donn�es, param�tres + d'import et des relations, liste mapping type SQL / type C++, etc...) sont enregistr�s � la + fermeture de cette fen�tre d'import. + Tous les param�tres d'import sont automatiquement valoris�s � la r�-ouverture de la fen�tre + d'import. +

+ Autre remarque : une vid�o de QxEntityEditor est disponible + pour montrer un exemple d'import de la base de donn�es de test MySQL : sakila. +

+
+
+ +

Plugins d'export

+
+ Tous les processus d'export de l'application QxEntityEditor sont accessibles depuis le menu + principal Export : +

+ Export plugins +

+

Exporter en + projet C++

+
+ L'export C++ g�n�re un projet complet C++ pr�t � �tre compil� (par qmake et/ou + cmake) et contenant toutes les entit�s/propri�t�s/relations/�num�rations enregistr�es + dans le contexte de la biblioth�que QxOrm. + Toutes les fonctionnalit�s de la biblioth�que QxOrm (persistance, s�rialisation, introspection, etc...) sont ainsi disponibles pour + l'ensemble du projet C++ g�n�r�. +

+

Param�tres de l'export C++

+
+ Les param�tres de l'export C++ sont accessibles par le menu principal : Tools >> + Export to C++ project (settings). + Cet �cran de param�trage apparait automatiquement au 1er export si aucun param�tre n'a �t� + enregistr� au niveau du projet. + Lorsqu'un export C++ a d�j� �t� r�alis�, alors cette fen�tre de param�trage est accessible + uniquement par le menu principal : Tools >> Export to C++ project (settings) : +

+ Export C++ +

+ Cet �cran d'export est divis� en plusieurs sections : +

+ -- Section C++ export settings : +
    +
  • Champ � C++ project location � : r�pertoire de destination qui contiendra tous les fichiers du projet C++ g�n�r�. Il + est possible de renseigner dans ce champ un chemin relatif par rapport au fichier + projet *.qxee ;
  • +
  • Option � Relative path to QxOrm library � : si coch�, le projet C++ r�f�rence + la biblioth�que QxOrm avec un chemin relatif, sinon la d�pendance � la biblioth�que + QxOrm est d�finie avec un chemin absolu. Il est conseill� d'utiliser une variable d'environnement dans les param�tres de + l'application QxEntityEditor (par exemple : $$(QXORM_DIR)) � la place de + cette option ;
  • +
  • Option � Generate a custom directory with custom files for each entity � : si + coch�, le projet C++ g�n�r� contient un fichier personnalis� par entit�. + Par d�faut, ces fichiers custom sont vides et ne seront jamais �cras�s par un nouvel + export C++. + Ces fichiers custom peuvent �tre utilis�s par exemple pour impl�menter les m�thodes de validation, ou bien les m�thodes de trigger.
  • +
  • Option � Generate all persistent classes using the PIMPL (Private Implementation) + idiom � : si coch�, toutes les classes C++ g�n�r�es et enregistr�es dans le + contexte QxOrm seront cod�es en utilisant le pattern + C++ PIMPL (ou d-pointer).
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : param�trage du moteur de personnalisation + de l'export. +
    +
  • Champ � Custom script file � : chemin d'acc�s au fichier Javascript permettant + de personnaliser l'export C++. Si vide, aucune + personnalisation n'est appliqu�e (export par d�faut). + Il est possible de renseigner dans ce champ un chemin relatif par rapport au fichier + projet *.qxee, par exemple ./my_script.js si le fichier + my_script.js se trouve dans le m�me r�pertoire que le fichier projet + *.qxee ; +
  • +
  • Bouton � Debug custom Javascript file � : si un fichier Javascript est d�fini, + un clic sur ce bouton d�clenchera le mode d�bogage + Javascript au prochain lancement d'export C++. + Au lieu d'utiliser ce bouton, il est �galement possible d'activer le mode d�bogage Javascript en maintenant la touche + SHIFT au moment de lancer un export C++. +
  • +
+
+ -- Section C++ template files : cette section d�finit le code C++ des entit�s + pour les fichiers Header *.h et Source *.cpp. + Le moteur d'export utilise des mots-cl� (placeholder sous la forme @@ACTION@@) + pour remplacer le code par la valeur correspondante. + Cette notion de placeholder est la base du moteur de + personnalisation Javascript. + Il est possible de renseigner des placeholder + personnalis�s en prefixant par @@CUSTOM_, par exemple : + @@CUSTOM_MY_ACTION@@. +
    +
  • Option � No inheritance � : si coch� (option par d�faut), la classe C++ n'a pas + d'h�ritage (aucune classe de base) ;
  • +
  • Option � qx::IxPersistable � : si coch�, chaque classe C++ g�n�r�e h�rite de l'interface qx::IxPersistable (fourni une + interface commune pour les actions de persistance � la base de donn�es). Cette option + rallonge les temps de compilation du projet C++ ;
  • +
  • Option � qx::IxPersistable + QObject � : si coch�, chaque classe C++ g�n�r�e + h�rite de l'interface qx::IxPersistable et de la classe Qt QObject. + Cette option rallonge les temps de compilation du projet C++ ;
  • +
  • Option � Custom � : si coch�, possibilit� de fournir son propre code C++ (il + est cependant conseill� de commencer � copier/coller Header *.h et + Source *.cpp d'une des 3 autres options pour r�cup�rer les + placeholder � utiliser). +
  • +
+
+
+

Pr�sentation du projet C++ g�n�r�

+
+ Le projet C++ g�n�r� dispose de l'arborescence suivante : +

+ Export C++ output +

+
    +
  • le dossier � bin � est vide par d�faut, et contiendra le binaire compil� + (*.dll sous Windows, *.so sous Linux, etc...) ;
  • +
  • le dossier � build � est vide par d�faut, il peut �tre utilis� pour produire + les fichiers CMake ;
  • +
  • le dossier � custom � est aliment� si l'option � Generate a custom directory with custom + files for each entity � est coch�. + Ces fichiers custom peuvent �tre utilis�s par exemple pour impl�menter les m�thodes de validation, ou bien les m�thodes de trigger ;
  • +
  • le dossier � include � contient les d�finitions de toutes les classes entit�s + et �num�rations du projet ;
  • +
  • le dossier � src � contient les impl�mentations de toutes les classes entit�s + et �num�rations du projet ;
  • +
  • le fichier � CMakeLists.txt � peut �tre utilis� pour compiler le projet C++ + avec CMake ;
  • +
  • les fichiers � *.gen.pri � et � *.gen.pro � peuvent �tre utilis�s pour + compiler le projet C++ avec qmake ;
  • +
+
+
+

Compilation du projet C++ g�n�r� (par qmake ou + cmake)

+
+ Le projet C++ g�n�r� peut �tre compil� avec CMake ou qmake.
+ La biblioth�que QxOrm dispose de certaines options de + compilation document�es dans les fichiers QxOrm.pri et QxOrm.cmake (il est possible de + conserver les options par d�faut).
+ Le manuel utilisateur de la biblioth�que QxOrm indique comment proc�der � la compilation du projet.
+ Un tutoriel est �galement disponible pour expliquer l'installation d'un environnement de d�veloppement sous Windows + avec MSVC.
+ Une fois le projet C++ compil� avec succ�s, le binaire est disponible dans le dossier � + bin � du projet export� (*.dll sous Windows, *.so sous Linux, etc...). +

+
+

Exemple d'utilisation

+
+ Le dossier ./samples/ du package QxEntityEditor fournit un projet de test : + qxBlog.qxee. + Ce projet de test peut �tre ouvert m�me avec une version de QxEntityEditor sans cl� de + licence active. + Une fois export� en projet C++, il est possible de compiler le projet afin d'obtenir une + biblioth�que partag�e qxBlog.dll (ou qxBlog.so sous Linux). + Cette biblioth�que partag�e poss�de toutes les entit�s et �num�rations du projet enregistr�es + dans le contexte QxOrm : toutes les fonctionnalit�s de la + biblioth�que QxOrm sont ainsi disponibles. +

+ Le dossier ./samples/ du package QxEntityEditor fournit �galement un projet d'exemple + d'utilisation du binaire compil� : qxBlogExec.zip. + Une fois d�zipp�, le fichier readme.txt � la racine contient les instructions + d'installation et compilation de ce projet d'exemple : +

+
+
+--------------------------------------------
+-- To build qxBlogExec project with qmake --
+--------------------------------------------
+
+1- Export the 'qxBlog.qxee' project as a C++ project with QxEntityEditor and build it
+2- Open the 'qxBlogExec.pro' file
+3- Replace '$$(QXORM_DIR)' by your QxOrm library installation path
+4- Replace 'C:/Temp/qxee/cpp/' by the path where you have exported the 'qxBlog.qxee' project as a C++ project
+5- run command line : qmake
+6- run command line : make debug (or make release)
+
+
+--------------------------------------------
+-- To build qxBlogExec project with CMake --
+--------------------------------------------
+
+1- Export the 'qxBlog.qxee' project as a C++ project with QxEntityEditor and build it
+2- Open the 'CMakeLists.txt' file
+3- Replace '$ENV{QXORM_DIR}' by your QxOrm library installation path
+4- Replace 'C:/Temp/qxee/cpp/' by the path where you have exported the 'qxBlog.qxee' project as a C++ project
+5- run cmake or cmake-gui to configure and generate your make files
+
+
+

+ Voici le contenu comment� de la fonction main() qui montre un exemple d'utilisation + (proche du tutoriel qxBlog) : +

+
+
+int main(int argc, char * argv[])
+{
+   // Qt application
+   QCoreApplication app(argc, argv);
+   QFile::remove("./qxBlog.sqlite");
+
+   // Parameters to connect to database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+   // Only for debug purpose : assert if invalid offset detected fetching a relation
+   qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true);
+
+   // !!! TO CREATE TABLES, PLEASE USE THE C++ DDL SQL EXPORT PLUGIN OF QXENTITYEDITOR !!!
+   // Create all tables in database (you should not use 'qx::dao::create_table<T>()' function in a production software, use it just for prototypes or samples)
+   QSqlError daoError = qx::dao::create_table<author>();
+   daoError = qx::dao::create_table<comment>();
+   daoError = qx::dao::create_table<category>();
+   daoError = qx::dao::create_table<blog>();
+
+   // Create a list of 3 author
+   author_ptr author_1; author_1.reset(new author());
+   author_ptr author_2; author_2.reset(new author());
+   author_ptr author_3; author_3.reset(new author());
+
+   author_1->setlastname("author_1");
+   author_1->setsex(sex::male);
+   author_1->setbirthdate(QDateTime::currentDateTime());
+   author_2->setlastname("author_2");
+   author_2->setsex(sex::female);
+   author_2->setbirthdate(QDateTime::currentDateTime());
+   author_3->setlastname("author_3");
+   author_3->setsex(sex::female);
+   author_3->setbirthdate(QDateTime::currentDateTime());
+
+   list_of_author authorX;
+   authorX.insert(1, author_1);
+   authorX.insert(2, author_2);
+   authorX.insert(3, author_3);
+
+   // Insert list of 3 author into database
+   daoError = qx::dao::insert(authorX);
+   qAssert(qx::dao::count<author>() == 3);
+
+   // Clone author n�2 : 'author_id_2'
+   author_ptr author_clone = qx::clone(* author_2);
+   qAssert(author_clone->getauthor_id() == author_2->getauthor_id());
+   qAssert(author_clone->getsex() == sex::female);
+
+   // Create a query to fetch only female author : 'author_id_2' and 'author_id_3'
+   qx::QxSqlQuery query("WHERE t_author.sex = :sex");
+   query.bind(":sex", sex::female);
+
+   list_of_author list_of_female_author;
+   daoError = qx::dao::fetch_by_query(query, list_of_female_author);
+   qAssert(list_of_female_author.count() == 2);
+
+   // Dump list of female author (xml serialization)
+   qx::dump(list_of_female_author);
+
+   // Create 3 categories
+   category_ptr category_1 = category_ptr(new category("cat_1"));
+   category_ptr category_2 = category_ptr(new category("cat_2"));
+   category_ptr category_3 = category_ptr(new category("cat_3"));
+
+   category_1->setname("category_1"); category_1->setdescription("desc_1");
+   category_2->setname("category_2"); category_2->setdescription("desc_2");
+   category_3->setname("category_3"); category_3->setdescription("desc_3");
+
+   { // Create a scope to destroy temporary connexion to database
+
+   // Open a transaction to database
+   QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
+   bool bCommit = db.transaction();
+
+   // Insert 3 categories into database, use 'db' parameter for the transaction
+   daoError = qx::dao::insert(category_1, (& db));    bCommit = (bCommit && ! daoError.isValid());
+   daoError = qx::dao::insert(category_2, (& db));    bCommit = (bCommit && ! daoError.isValid());
+   daoError = qx::dao::insert(category_3, (& db));    bCommit = (bCommit && ! daoError.isValid());
+
+   qAssert(bCommit);
+   qAssert(category_1->getcategory_id() != "");
+   qAssert(category_2->getcategory_id() != "");
+   qAssert(category_3->getcategory_id() != "");
+
+   // Terminate transaction => commit or rollback if there is error
+   if (bCommit) { db.commit(); }
+   else { db.rollback(); }
+
+   } // End of scope : 'db' is destroyed
+
+   // Create a blog with the class name (factory)
+   boost::any blog_any = qx::create("blog");
+   blog_ptr blog_1;
+   try { blog_1 = boost::any_cast<blog_ptr>(blog_any); }
+   catch (...) { blog_1.reset(new blog()); }
+   blog_1->settext("blog_text_1");
+   blog_1->settitle("blog_title_1");
+   blog_1->setauthor(author_1);
+
+   // Insert 'blog_1' into database with 'save()' method
+   daoError = qx::dao::save(blog_1);
+
+   // Modify 'blog_1' properties and save into database
+   blog_1->settext("update blog_text_1");
+   blog_1->setauthor(author_2);
+   daoError = qx::dao::save(blog_1);
+
+   // Add 2 comments to 'blog_1'
+   comment_ptr comment_1; comment_1.reset(new comment());
+   comment_ptr comment_2; comment_2.reset(new comment());
+
+   comment_1->settext("comment_1 text");
+   comment_1->setblog_id(blog_1);
+   comment_2->settext("comment_2 text");
+   comment_2->setblog_id(blog_1);
+
+   daoError = qx::dao::insert(comment_1);
+   daoError = qx::dao::insert(comment_2);
+   qAssert(qx::dao::count<comment>() == 2);
+
+   // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog'
+   blog::type_list_of_category lst_category;
+   lst_category.insert(category_1->getcategory_id(), category_1);
+   lst_category.insert(category_3->getcategory_id(), category_3);
+   blog_1->setlist_of_category(lst_category);
+   daoError = qx::dao::save_with_relation("list_of_category", blog_1);
+
+   // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category'
+   blog_ptr blog_tmp; blog_tmp.reset(new blog());
+   blog_tmp->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp);
+
+   qAssert(blog_tmp->list_of_comment().count() == 2);
+   qAssert(blog_tmp->list_of_category().count() == 2);
+   qAssert(blog_tmp->gettext() == "update blog_text_1");
+   qAssert(blog_tmp->getauthor() && blog_tmp->getauthor()->getauthor_id() == author_2->getauthor_id());
+
+   // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships)
+   blog_tmp.reset(new blog());
+   blog_tmp->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp);
+
+   qAssert(blog_tmp->list_of_comment().count() == 2);
+   qAssert(blog_tmp->list_of_category().count() == 2);
+   qAssert(blog_tmp->gettext() == "update blog_text_1");
+   qAssert(blog_tmp->getauthor() && blog_tmp->getauthor()->getauthor_id() == author_2->getauthor_id());
+
+   // Dump 'blog_tmp' result from database (xml serialization)
+   qx::dump(blog_tmp);
+
+   // Check qx::dao::save_with_relation_recursive() function
+   daoError = qx::dao::save_with_relation_recursive(blog_tmp);
+   qAssert(! daoError.isValid());
+   daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only);
+   qAssert(! daoError.isValid());
+
+   // Call 'age()' method with class name and method name (reflexion)
+   //qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1);
+   //qAssert(bInvokeOk);
+
+   // Test 'isDirty()' method
+   qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(new blog());
+   blog_isdirty->setblog_id(blog_1->getblog_id());
+   daoError = qx::dao::fetch_by_id(blog_isdirty);
+   qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());
+
+   blog_isdirty->settext("blog property 'text' modified => blog is dirty !!!");
+   QStringList lstDiff; bool bDirty = blog_isdirty.isDirty(lstDiff);
+   qAssert(bDirty && (lstDiff.count() == 1) && (lstDiff.at(0) == "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<author_ptr> > type_lst_author_test_is_dirty;
+   type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
+   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->setlastname("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->setfirstname("firstname changed");
+   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_text' of blog
+   QStringList lstColumns = QStringList() << "text";
+   QList<blog_ptr> lst_blog_with_only_text;
+   daoError = qx::dao::fetch_all(lst_blog_with_only_text, NULL, lstColumns);
+   qAssert(! daoError.isValid() && (lst_blog_with_only_text.size() > 0));
+   if ((lst_blog_with_only_text.size() > 0) && (lst_blog_with_only_text[0].get() != NULL))
+   { qAssert(lst_blog_with_only_text[0]->gettitle().isEmpty()); }
+   qx::dump(lst_blog_with_only_text);
+
+   // Dump all registered classes into QxOrm context (introspection engine)
+   qx::QxClassX::dumpAllClasses();
+
+   // Call a custom SQL query or a stored procedure
+   qx_query testStoredProc("SELECT * FROM t_author");
+   daoError = qx::dao::call_query(testStoredProc);
+   qAssert(! daoError.isValid());
+   testStoredProc.dumpSqlResult();
+
+   // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
+   qx_query testStoredProcBis("SELECT * FROM t_author");
+   authorX.clear();
+   daoError = qx::dao::execute_query(testStoredProcBis, authorX);
+   qAssert(! daoError.isValid()); qAssert(authorX.count() > 0);
+   qx::dump(authorX);
+
+   // Call a custom SQL query or a stored procedure and fetch automatically properties
+   qx_query testStoredProcThird("SELECT name, category_id FROM t_category");
+   category_ptr category_tmp = category_ptr(new category());
+   daoError = qx::dao::execute_query(testStoredProcThird, category_tmp);
+   qAssert(! daoError.isValid()); qAssert(category_tmp->getcategory_id() != "");
+   qx::dump(category_tmp);
+
+   return 0;
+}
+
+
+

+
+
+

Exporter en projet C++ de type model/view

+
+ La biblioth�que QxOrm fournit le module QxModelView. + Une documentation sur le module QxModelView est disponible dans le manuel utilisateur de la biblioth�que QxOrm. + Le module QxModelView + permet d'utiliser le moteur + model/view de Qt avec toutes les classes enregistr�es dans le contexte QxOrm : +
    +
  • QML : toute propri�t� enregistr�e dans le contexte + QxOrm est accessible en QML : le module QxModelView + permet ainsi de faciliter l'int�raction entre QML et les bases de donn�es ;
  • +
  • Qt widgets : utilisation de QTableView ou + QListView par exemple pour afficher/modifier le contenu d'une table de la base de + donn�es. +
  • +
+
+ L'application QxEntityEditor permet de g�n�rer un projet C++ de type model/view complet et pr�t + � �tre compil� : ainsi toutes les entit�s et leurs relations sont accessibles dans des vues QML + par exemple. +

+

Param�tres de l'export

+
+ Les param�tres de l'export C++ de type model/view sont accessibles par le menu principal : + Tools >> Export to C++ model/view project (settings). + Cet �cran de param�trage apparait automatiquement au 1er export si aucun param�tre n'a �t� + enregistr� au niveau du projet. + Lorsqu'un export C++ model/view a d�j� �t� r�alis�, alors cette fen�tre de param�trage est + accessible uniquement par le menu principal : Tools >> Export to C++ model/view + project (settings) : +

+ Export C++ model/view +

+ Cet �cran d'export est divis� en plusieurs sections : +

+ -- Section C++ model/view export settings : +
    +
  • Champ � C++ model/view project location � : r�pertoire de destination qui + contiendra tous les fichiers du + projet C++ model/view g�n�r�. Il est possible de renseigner dans ce champ un + chemin relatif par rapport au fichier projet *.qxee ;
  • +
  • Champ � C++ entities project location � : lecture seule uniquement, indique le + r�pertoire de destination du projet C++ g�n�r� + (entit�s enregistr�es dans le contexte QxOrm) dont d�pend le projet C++ model/view ; +
  • +
  • Champ � Namespace for model/view � : espace de nom utilis� pour les classes C++ + g�n�r�es de type model/view (ces classes impl�mentent l'interface qx::IxModel) ; +
  • +
  • Champ � Generate custom files � : si coch�, le projet C++ g�n�r� contient un + fichier personnalis� par entit�. + Par d�faut, ces fichiers custom sont vides et ne seront jamais �cras�s par un nouvel + export C++.
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : param�trage du moteur de personnalisation + de l'export. +
    +
  • Champ � Custom script file � : chemin d'acc�s au fichier Javascript permettant + de personnaliser l'export C++. Si vide, aucune + personnalisation n'est appliqu�e (export par d�faut). + Il est possible de renseigner dans ce champ un chemin relatif par rapport au fichier + projet *.qxee, par exemple ./my_script.js si le fichier + my_script.js se trouve dans le m�me r�pertoire que le fichier projet + *.qxee ; +
  • +
  • Bouton � Debug custom Javascript file � : si un fichier Javascript est d�fini, + un clic sur ce bouton d�clenchera le mode d�bogage + Javascript au prochain lancement d'export C++. + Au lieu d'utiliser ce bouton, il est �galement possible d'activer le mode d�bogage Javascript en maintenant la touche + SHIFT au moment de lancer un export C++. +
  • +
+
+ -- Section C++ model/view template files : cette section d�finit le code C++ + model/view pour les fichiers Header *.h et Source *.cpp. + Le moteur d'export utilise des mots-cl� (placeholder sous la forme @@ACTION@@) + pour remplacer le code par la valeur correspondante. + Cette notion de placeholder est la base du moteur de + personnalisation Javascript. + Il est possible de renseigner des placeholder + personnalis�s en prefixant par @@CUSTOM_, par exemple : + @@CUSTOM_MY_ACTION@@. + +
+
+

Pr�sentation du projet g�n�r�

+
+ Le projet C++ model/view g�n�r� dispose de l'arborescence suivante : +

+ Export C++ model/view output +

+
    +
  • le dossier � bin � est vide par d�faut, et contiendra le binaire compil� + (*.dll sous Windows, *.so sous Linux, etc...) ;
  • +
  • le dossier � build � est vide par d�faut, il peut �tre utilis� pour produire + les fichiers CMake ;
  • +
  • le dossier � custom � est aliment� si l'option � Generate custom files � + est coch�e ;
  • +
  • le dossier � include � contient les d�finitions de tous les mod�les du projet ; +
  • +
  • le dossier � src � contient les impl�mentations de tous les mod�les du projet ; +
  • +
  • le fichier � CMakeLists.txt � peut �tre utilis� pour compiler le projet C++ + avec CMake ;
  • +
  • les fichiers � *.gen.pri � et � *.gen.pro � peuvent �tre utilis�s pour + compiler le projet C++ avec qmake ;
  • +
+
+
+
+

Exporter en projet C++ de type services

+
+ La biblioth�que QxOrm fournit le module QxService. + Une documentation sur le module QxService est disponible dans le manuel utilisateur de la biblioth�que QxOrm. + Le module QxService de la + biblioth�que QxOrm permet de cr�er rapidement un serveur d'applications C++ performant + (notion de services avec demande du client et r�ponse du serveur). + Un tutoriel est disponible sur le site QxOrm afin de pr�senter + un exemple d'utilisation du module QxService. +

+ L'application QxEntityEditor permet de g�n�rer un projet C++ de type services (un projet C++ + pour g�rer la couche cliente et un projet C++ pour publier les services c�t� serveur) complet et + pr�t � �tre compil� : ainsi toutes les entit�s et leurs relations peuvent �tre transf�r�es sur + le r�seau pour une application de type client/serveur. +

+

Param�tres de l'export

+
+ Les param�tres de l'export C++ de type services sont accessibles par le menu principal : + Tools >> Export to C++ services project (settings). + Cet �cran de param�trage apparait automatiquement au 1er export si aucun param�tre n'a �t� + enregistr� au niveau du projet. + Lorsqu'un export C++ de type services a d�j� �t� r�alis�, alors cette fen�tre de param�trage + est accessible uniquement par le menu principal : Tools >> Export to C++ services + project (settings) : +

+ Export C++ services +

+ Cet �cran d'export est divis� en plusieurs sections : +

+ -- Section C++ services export settings : +
    +
  • Champ � C++ services project location � : r�pertoire de destination qui + contiendra tous les fichiers du + projet C++ de type services g�n�r�. Il est possible de renseigner dans ce champ + un chemin relatif par rapport au fichier projet *.qxee ;
  • +
  • Champ � C++ entities project location � : lecture seule uniquement, indique le + r�pertoire de destination du projet C++ g�n�r� + (entit�s enregistr�es dans le contexte QxOrm) dont d�pend le projet C++ services ;
  • +
  • Champ � Namespace for services � : espace de nom utilis� pour les classes C++ + g�n�r�es de type services (ces classes permettent de transf�rer les entit�s sur le r�seau, couche + cliente et serveur) ;
  • +
  • Champ � Generate custom files � : si coch�, le projet C++ g�n�r� contient un + fichier personnalis� par entit�. + Par d�faut, ces fichiers custom sont vides et ne seront jamais �cras�s par un nouvel + export C++. + Ces fichiers custom peuvent par exemple �tre utilis�s pour impl�menter des nouveaux + services ;
  • +
  • Champ � Generate server application � : si coch�, un projet C++ d'exemple de type + serveur d'applications est g�n�r� et permet de charger et publier les services + c�t� serveur avec un syst�me de plugins ;
  • +
  • Champ � Server application location � : si l'option � Generate server + application � est coch�e, d�fini le r�pertoire de destination du projet + d'exemple serveur + d'applications.
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the + export process : param�trage du moteur de personnalisation + de l'export. +
    +
  • Champ � Custom script file � : chemin d'acc�s au fichier Javascript permettant + de personnaliser l'export C++. Si vide, aucune + personnalisation n'est appliqu�e (export par d�faut). + Il est possible de renseigner dans ce champ un chemin relatif par rapport au fichier + projet *.qxee, par exemple ./my_script.js si le fichier + my_script.js se trouve dans le m�me r�pertoire que le fichier projet + *.qxee ; +
  • +
  • Bouton � Debug custom Javascript file � : si un fichier Javascript est d�fini, + un clic sur ce bouton d�clenchera le mode d�bogage + Javascript au prochain lancement d'export C++. + Au lieu d'utiliser ce bouton, il est �galement possible d'activer le mode d�bogage Javascript en maintenant la touche + SHIFT au moment de lancer un export C++. +
  • +
+
+ -- Section C++ services template files : cette section d�finit le code C++ des + services pour les fichiers Header *.h et Source *.cpp (client et + serveur). + Le moteur d'export utilise des mots-cl� (placeholder sous la forme @@ACTION@@) + pour remplacer le code par la valeur correspondante. + Cette notion de placeholder est la base du moteur de + personnalisation Javascript. + Il est possible de renseigner des placeholder + personnalis�s en prefixant par @@CUSTOM_, par exemple : + @@CUSTOM_MY_ACTION@@. +
    +
  • Option � Default � : si coch� (option par d�faut), g�n�re les services (couche + cliente et serveur) par d�faut : les entit�s peuvent �tre transf�r�es sur le r�seau et + les actions CRUD sur la base de donn�es sont support�es ;
  • +
  • Option � Custom � : si coch�, possibilit� de fournir son propre code C++ pour + g�n�rer les services (il est cependant conseill� de commencer � copier/coller + Header *.h et Source *.cpp de l'option par d�faut pour + r�cup�rer les placeholder � utiliser). +
  • +
+
+
+

Pr�sentation du projet g�n�r�

+
+ Le projet C++ de type services (client et serveur) g�n�r� dispose de l'arborescence suivante + : +

+ Export C++ services output +

+
    +
  • le dossier � bin � est vide par d�faut, et contiendra les binaires compil�s + (*.dll sous Windows, *.so sous Linux, etc...) pour la partie cliente et + serveur ;
  • +
  • le dossier � build � est vide par d�faut, il peut �tre utilis� pour produire + les fichiers CMake ;
  • +
  • le dossier � client � contient les fichiers qmake et CMake pour compiler la couche cliente + du projet ;
  • +
  • le dossier � custom � est aliment� si l'option � Generate custom files � + est coch�e ;
  • +
  • le dossier � include � contient les d�finitions de tous les services du projet + ;
  • +
  • le dossier � server � contient les fichiers qmake et CMake pour compiler la couche serveur + du projet ;
  • +
  • le dossier � src � contient les impl�mentations de tous les services du projet + ;
  • +
  • le fichier � CMakeLists.txt � peut �tre utilis� pour compiler le projet C++ + (client et serveur) avec CMake ;
  • +
  • les fichiers � *.gen.pri � et � *.gen.pro � peuvent �tre utilis�s pour + compiler le projet C++ (client et serveur) avec qmake ;
  • +
  • le fichier � *.gen.json � est utilis� par la couche serveur pour g�n�rer un + plugin pouvant �tre charg� dynamiquement par le serveur d'applications.
  • +
+
+
+

Serveur d'applications g�n�rique

+
+ Si l'option � Generate server + application � est coch�e, l'export C++ de type services g�n�re �galement un + exemple de serveur d'applications g�n�rique pouvant publier des services en chargeant des + plugins. + Tout comme les autres projets C++ g�n�r�s par QxEntityEditor, le serveur d'applications + g�n�rique peut �tre compil� qmake et CMake. + Ce projet d'exemple dispose de l'arborescence suivante : +

+ Export C++ services server app output +

+ Une fois compil�, l'ex�cutable se trouve dans le dossier � bin �. + Le lancement du serveur d'applications g�n�rique ouvre la fen�tre suivante : +

+ Export C++ services server app +

+ Cet �cran est divis� en plusieurs sections : +

+ -- Section Plugins services : +
    +
  • Champ � Plugins path � : il est n�cessaire de d�finir le r�pertoire contenant + les plugins � charger. + Ces plugins correspondent � la couche + serveur du projet C++ de type services. + Une fois charg�, les plugins publient des services pouvant �tre appel�s par les + applications clientes. + Si aucun plugin n'est charg� apr�s la s�lection du r�pertoire, il est possible de + d�finir la + variable d'environnement QT_DEBUG_PLUGINS afin d'avoir des logs sur + l'erreur de chargement de plugin (en g�n�ral, une d�pendance du plugin non trouv�). +
  • +
+
+ -- Section Database connection parameters : +
    +
  • Cette section contient tous les param�tres n�cessaires pour initialiser la connexion � + la base de donn�es utilis�e par les services (utilisation de la classe qx::QxSqlDatabase).
  • +
+
+ -- Section Server parameters : +
    +
  • Champ � Port number � : d�fini le n� de port utilis� par le serveur + d'applications pour publier les services. Les applications clientes devront se + connecter sur ce port pour effectuer des requ�tes au serveur ;
  • +
  • Champ � Thread count � : nombre de threads utilis�s par le serveur pour traiter + les requ�tes provenant des applications clientes ;
  • +
  • Champ � Serialization type � : type de s�rialisation utilis� pour renvoyer les + r�ponses du serveur au client ;
  • +
  • Champ � Compress data � : si coch�, les donn�es renvoy�es au client sont + compress�es ;
  • +
  • Champ � Encrypt data � : si coch�, les donn�es renvoy�es au client sont + crypt�es (possibilit� de d�finir une cl� de cryptage) ;
  • +
  • Bouton � Start server � : bouton permettant de d�marrer et arr�ter le serveur. +
  • +
+
+ -- Section Log last client-server reply-request transaction : +
    +
  • Affiche dans un flux XML ou JSON les d�tails de la derni�re transaction client-serveur + trait�e par le serveur d'applications.
  • +
+
+ -- Section Log last server error : +
    +
  • Si une erreur se produit sur le serveur d'applications, elle est automatiquement + loggu�e dans cette section.
  • +
+
+
+
+

Exporter le + sch�ma de base de donn�es SQL DDL

+
+ L'application QxEntityEditor permet de g�n�rer le sch�ma de base de donn�es dans un format DDL + SQL. + L'application QxEntityEditor supporte les bases de donn�es les plus fr�quemment utilis�es : + SQLite, MySQL, MariaDB, PostgreSQL, Oracle et Microsoft SQL Server. + Le script DDL SQL g�n�r� par QxEntityEditor peut �tre import� par la base de donn�es pour cr�er + automatiquement toutes les tables, colonnes, cl�s primaires, relations, index, etc... + Les param�tres de l'export DDL SQL sont accessibles par le menu principal : Tools >> + Export to DDL SQL script file (settings) : +

+ Export SQL DDL +

+ Cet �cran d'export est divis� en plusieurs sections : +

+ -- Section DDL export settings : +
    +
  • Champ � File location � : r�pertoire de destination qui contiendra le script DDL + SQL g�n�r� ;
  • +
  • Champ � Database type � : type de base de donn�es qui sera utilis� pour importer + le sch�ma DDL SQL (SQLite, MySQL, MariaDB, PostgreSQL, Oracle ou Microsoft SQL Server) ; +
  • +
  • Champ � Relationships � : si coch�, des cl�s �trang�res (foreign keys) sont cr��es + pour g�rer les relations entre entit�s ;
  • +
  • Champ � Schema � : d�fini le type d'export DDL : 1 fichier contenant toute la + structure du projet *.qxee, ou bien 1 fichier par + version du projet *.qxee (gestion de l'�volution du sch�ma de base de + donn�es).
  • +
+
+ -- Section Mapping C++ type to database SQL type : +
    +
  • Liste permettant d'associer un type C++ (renseign� au niveau des propri�t�s du projet + *.qxee) � un type SQL. +
  • +
+
+ -- Section Custom script (Javascript file) to change the default behaviour of the export + process : param�trage du moteur de personnalisation de + l'export. +
    +
  • Champ � Custom script file � : chemin d'acc�s au fichier Javascript permettant de + personnaliser l'export DDL. Si vide, aucune personnalisation + n'est appliqu�e (export par d�faut). + Il est possible de renseigner dans ce champ un chemin relatif par rapport au fichier + projet *.qxee, par exemple ./my_script.js si le fichier my_script.js + se trouve dans le m�me r�pertoire que le fichier projet *.qxee ; +
  • +
  • Bouton � Debug custom Javascript file � : si un fichier Javascript est d�fini, un + clic sur ce bouton d�clenchera le mode d�bogage Javascript + au prochain lancement d'export DDL. + Au lieu d'utiliser ce bouton, il est �galement possible d'activer le mode d�bogage Javascript en maintenant la touche + SHIFT au moment de lancer un export DDL. +
  • +
+
+
+

Imprimer le + diagramme d'entit�s

+
+ L'application QxEntityEditor permet d'imprimer le diagramme d'entit�s dans un format PNG et/ou + PDF. + Les param�tres d'impression sont accessibles par le menu principal : Tools >> Print the + entities diagram (settings) : +

+ Export print PNG/PDF +

+
+

Exporter le projet dans un r�pertoire associ� � un + gestionnaire de code source (Git, Perforce, CVS, etc.)

+
+ Un projet QxEntityEditor (fichier *.qxee) peut �tre g�r� par une �quipe de d�veloppeurs : + le code source d'un projet QxEntityEditor peut �tre export�/import� (manuellement ou en ligne de + commande) avec les plugins QxEESourceControlExport et QxEESourceControlImport.
+
+ Associ� � un gestionnaire de code source (Git, Perforce, CVS, etc.), ces 2 plugins permettent + ainsi : +
    +
  • plusieurs personnes peuvent travailler simultan�ment sur un m�me projet ;
  • +
  • un projet peut facilement �tre versionn� dans le gestionnaire de code source ;
  • +
  • chaque �l�ment d'un projet peut �tre compar� (diff�rence entre 2 versions d'une m�me + entit� par exemple).
  • +
+ Voici un exemple d'utilisation des plugins QxEESourceControlExport et QxEESourceControlImport, avec 2 d�veloppeurs + nomm�s 'dev A' et 'dev B' (l'exemple pouvant �tre �tendu � X d�veloppeurs) : +
    +
  • dev A et dev B travaillent sur un m�me projet QxEntityEditor (fichier *.qxee) ; +
  • +
  • dev A cr��/modifie/supprime certaines entit�s dans l'application QxEntityEditor ;
  • +
  • dev B cr��/modifie/supprime d'autres entit�s dans l'application QxEntityEditor ;
  • +
  • dev A et dev B exportent le projet *.qxee en utilisant le plugin QxEESourceControlExport (manuellement + ou en ligne de commande) ;
  • +
  • une fois le projet export� dans un r�pertoire, dev A et dev B enregistrent + (check-in ou submit) les fichiers JSON g�n�r�s dans le gestionnaire de code + source (Git, Perforce, CVS, etc.) sur leur propre branche de travail ;
  • +
  • depuis le gestionnaire de code source, dev A et dev B int�grent (merge ou + integrate) leur branche de travail sur la branche de d�veloppement DEV (ou MAIN ou + MASTER ou LATEST); Remarque : m�me si il y a des conflits � r�soudre, ils seront + simples � corriger car le format JSON est lisible facilement ; +
  • +
  • dev A et dev B peuvent � pr�sent obtenir la derni�re version des fichiers JSON (get + latest depuis le gestionnaire de code source) � partir de la branche DEV (ou MAIN + ou MASTER ou LATEST) : les fichiers JSON obtenus contiennent � la fois les + modifications de dev A et dev B ;
  • +
  • dev A et dev B peuvent importer ces fichiers JSON dans l'application QxEntityEditor en + utilisant le plugin d'import QxEESourceControlImport (manuellement ou + en ligne de commande).
  • +
+ Les param�tres du plugin d'export sont accessibles depuis le menu principal Tools >> + Export to Source Control repository (Git, Perforce, CVS, etc.) as JSON files (settings) : +

+ Source Control export plugin settings +

+ Le param�tre � renseigner correspond au r�pertoire dans lequel seront g�n�r�s les fichiers + JSON.
+ Chaque �l�ment du projet *.qxee (entit�s, propri�t�s, relations, commentaires, etc.) est + export� dans un fichier JSON sp�cifique.
+ Le r�pertoire o� sont export�s les fichiers JSON a la structure suivante : +

+ Source Control output directory +

+ Remarque : il est possible d'exporter un projet en ligne de commande sans d�marrer + l'interface utilisateur de l'application QxEntityEditor.
+ Exemple de ligne de commande :
+
+ +
QxEntityEditor --no_gui --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlExport --QxEESourceControlExport_path="<path_to_your_export_output_directory>"
+
+
+

+
+

Exporter le + projet sous format XML ou JSON

+
+ + Remarque : + pour travailler avec un gestionnaire de code source (Git, Perforce, CVS, etc.), il est + conseill� d'utiliser les plugins QxEESourceControlExport et QxEESourceControlImport (au lieu de cr�er un + fichier unique).
+
+ L'application QxEntityEditor permet d'exporter l'int�gralit� d'un projet *.qxee dans un + format XML ou JSON. + Les param�tres d'export XML/JSON sont accessibles par le menu principal : Tools >> + Export to XML or JSON file (settings) : +

+ Export XML/JSON +

+ Remarque : un export XML ne peut pas �tre import� dans un projet *.qxee. + Par contre, un fichier JSON peut �tre utilis� pour importer les donn�es dans un projet + *.qxee en utilisant le plugin d'import : Importer un projet � + partir d'un fichier texte au format JSON. +

+
+
+ +

Moteur Javascript pour + personnaliser les exports

+
+ L'application QxEntityEditor fournit un puissant moteur de personnalisation des exports. + Ce moteur utilise le langage + Javascript pour �crire des scripts pour personnaliser les exports. + Ces scripts Javascript ont + acc�s � l'ensemble des param�tres d'un projet *.qxee, et peuvent �tre d�bogu�s � l'aide d'un + d�bogueur int�gr� � QxEntityEditor. + Il est �galement possible d'�crire de nouveaux fichiers lors + des exports. +

+ Remarque : le dossier ./samples/ du package QxEntityEditor fournit 2 exemples de + scripts document�s : custom_script.js et q_property.js. +

+

Architecture + et fonctionnement du moteur de personnalisation Javascript

+
+ Tous les plugins d'export de l'application QxEntityEditor dispose + d'un param�trage nomm� : Custom script (Javascript + file) to change the default behaviour of the export process. + Il est ainsi possible de param�trer un script Javascript utilis� au moment de l'export. + Le moteur d'export utilise des mots-cl� (placeholder sous la forme @@ACTION@@) + pour remplacer le code par la valeur correspondante. + Cette notion de placeholder est la base du moteur de + personnalisation Javascript. + Il est possible de renseigner des placeholder + personnalis�s en prefixant par @@CUSTOM_, par exemple : + @@CUSTOM_MY_ACTION@@. + Lors d'un export, l'application QxEntityEditor parcourt la liste de toutes les entit�s d�finies + dans le projet *.qxee. + Chaque fois qu'un placeholder (sous la forme @@ACTION@@) est rencontr�, le script + Javascript est appel� + avec tous les param�tres n�cessaires pour effectuer ou non une personnalisation. +

+ Voici un exemple de script Javascript minimal. + Ce script ne fait rien, il permet de montrer uniquement la structure minimale d'un Javascript valide pour + QxEntityEditor : + +
+
+
({
+
+// Here is the entry point of the QxEntityEditor javascript engine
+// This function is called for each placeholder defined in the C++ template section
+customProcess : function(params)
+{
+   try
+   {
+      // quit with 'params[0]' means : doesn't change the default export behaviour
+      return params[0];
+   }
+   catch (err)
+   { return ("[CustomScriptError] an unexpected error occurred : " + err); }
+}
+
+});
+
+

+

Liste des + param�tres d'appel du moteur Javascript

+
+ Le param�tre d'entr�e params de la fonction customProcess() est un tableau + contenant une liste de valeurs (ce qui correspond au contexte d'appel du script). + Voici un exemple de fonction qui peut �tre utilis�e dans vos scripts pour lister et donner + une signification aux valeurs d'entr�e : +

+
+
function printParams(params)
+{
+   var log = "";
+   log = log + "\n - default_value = " + params[0];
+   log = log + "\n - project_name = " + params[1];
+   log = log + "\n - project_file = " + params[2];
+   log = log + "\n - plugin_name = " + params[3];
+   log = log + "\n - current_file = " + params[4];
+   log = log + "\n - action (or placeholder) = " + params[5];
+   log = log + "\n - entity_name = " + params[6];
+   log = log + "\n - entity_table_name = " + params[7];
+   log = log + "\n - property_name = " + params[8];
+   log = log + "\n - property_type = " + params[9];
+   log = log + "\n - property_column_name = " + params[10];
+   log = log + "\n - property_is_primary_key = " + params[11];
+   log = log + "\n - enumeration_name = " + params[12];
+   log = log + "\n - entity_id = " + params[13];
+   log = log + "\n - property_id = " + params[14];
+   log = log + "\n - enumeration_id = " + params[15];
+   log = log + "\n - output_location = " + params[16];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return log;
+}
+
+

+
+
+

Fonctions + disponibles par Javascript

+
+ Le moteur de personnalisation des exports de QxEntityEditor supporte toutes les fonctionnalit�s + du langage Javascript + (ECMAScript 5). + L'application QxEntityEditor fournit en plus une instance d'objet nomm�e helper + qui peut �tre utilis�e pour acc�der � de nouvelles fonctionnalit�s. + Nous allons lister dans ce chapitre les cas d'usage les plus couramment utilis�s pour + personnaliser les exports. +

+

Obtenir les informations associ�es � une entit�

+
+ Voici comment r�cup�rer le param�trage de l'entit� courante, + helper.getEntityDetails(entity_id) : +

+
+
var entity_id = params[13];
+printEntityDetails(entity_id);
+
+//...
+
+function printEntityDetails(entity_id)
+{
+   var details = helper.getEntityDetails(entity_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - entity_id = " + details[0];
+   log = log + "\n - entity_key = " + details[1];
+   log = log + "\n - entity_name = " + details[2];
+   log = log + "\n - entity_namespace = " + details[3];
+   log = log + "\n - entity_tablename = " + details[4];
+   log = log + "\n - entity_description = " + details[5];
+   log = log + "\n - entity_is_read_only = " + details[6];
+   log = log + "\n - entity_is_abstract = " + details[7];
+   log = log + "\n - entity_version = " + details[8];
+   log = log + "\n - entity_primary_key_property_id = " + details[9];
+   log = log + "\n - entity_list_of_properties_id = " + details[10];
+   log = log + "\n - entity_has_triggers = " + details[11];
+   log = log + "\n - entity_trigger_on_before_fetch = " + details[12];
+   log = log + "\n - entity_trigger_on_after_fetch = " + details[13];
+   log = log + "\n - entity_trigger_on_before_insert = " + details[14];
+   log = log + "\n - entity_trigger_on_after_insert = " + details[15];
+   log = log + "\n - entity_trigger_on_before_update = " + details[16];
+   log = log + "\n - entity_trigger_on_after_update = " + details[17];
+   log = log + "\n - entity_trigger_on_before_delete = " + details[18];
+   log = log + "\n - entity_trigger_on_after_delete = " + details[19];
+   log = log + "\n - entity_parent_id = " + details[20];
+   log = log + "\n - entity_soft_delete_column = " + details[21];
+   log = log + "\n - entity_validator_method = " + details[22];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Parcourir la liste des propri�t�s d'une + entit�

+
+ Voici comment parcourir la liste des propri�t�s de l'entit� courante : +

+
+
var entity_id = params[13];
+var entity_details = helper.getEntityDetails(entity_id);
+var entity_list_of_properties_id = ((entity_details.length > 0) ? entity_details[10] : "");
+var entity_list_of_properties_array = entity_list_of_properties_id.split("|");
+for (var idx = 0; idx < entity_list_of_properties_array.length; idx++)
+{
+   var property_id = entity_list_of_properties_array[idx];
+   var property_details = helper.getPropertyDetails(property_id);
+   // ...
+}
+
+

+
+

Obtenir les informations associ�es � une propri�t� +

+
+ Voici comment r�cup�rer le param�trage d'une propri�t�, + helper.getPropertyDetails(property_id) : +

+
+
function printPropertyDetails(property_id)
+{
+   var details = helper.getPropertyDetails(property_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - property_id = " + details[0];
+   log = log + "\n - property_key = " + details[1];
+   log = log + "\n - property_name = " + details[2];
+   log = log + "\n - property_column_name = " + details[3];
+   log = log + "\n - property_description = " + details[4];
+   log = log + "\n - property_type = " + details[5];
+   log = log + "\n - property_version = " + details[6];
+   log = log + "\n - property_entity_id = " + details[7];
+   log = log + "\n - property_is_read_only = " + details[8];
+   log = log + "\n - property_is_primary_key = " + details[9];
+   log = log + "\n - property_is_serializable = " + details[10];
+   log = log + "\n - property_is_transient = " + details[11];
+   log = log + "\n - property_is_obsolete = " + details[12];
+   log = log + "\n - property_is_index = " + details[13];
+   log = log + "\n - property_is_unique = " + details[14];
+   log = log + "\n - property_allow_null = " + details[15];
+   log = log + "\n - property_order_level = " + details[16];
+   log = log + "\n - property_default_value = " + details[17];
+   log = log + "\n - property_format = " + details[18];
+   log = log + "\n - property_force_sql_type = " + details[19];
+   log = log + "\n - property_force_sql_alias = " + details[20];
+   log = log + "\n - property_min_value = " + details[21];
+   log = log + "\n - property_max_value = " + details[22];
+   log = log + "\n - property_min_length = " + details[23];
+   log = log + "\n - property_max_length = " + details[24];
+   log = log + "\n - property_reg_exp = " + details[25];
+   log = log + "\n - property_accessibility = " + details[26];
+   log = log + "\n - property_is_relationship = " + details[27];
+   log = log + "\n - property_relation_type = " + details[28];
+   log = log + "\n - property_relation_entity_target_id = " + details[29];
+   log = log + "\n - property_relation_inverse_property_id = " + details[30];
+   log = log + "\n - property_relation_foreign_key = " + details[31];
+   log = log + "\n - property_relation_foreign_key_owner = " + details[32];
+   log = log + "\n - property_relation_extra_table = " + details[33];
+   log = log + "\n - property_relation_type_desc = " + details[34];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Obtenir + les informations associ�es � une �num�ration

+
+ Voici comment r�cup�rer le param�trage de l'�num�ration courante, + helper.getEnumerationDetails(enumeration_id) : +

+
+
var enumeration_id = params[15];
+printEnumerationDetails(enumeration_id);
+
+//...
+
+function printEnumerationDetails(enumeration_id)
+{
+   var details = helper.getEnumerationDetails(enumeration_id);
+   if (details.length == 0) { return details; }
+
+   var log = "";
+   log = log + "\n - enumeration_id = " + details[0];
+   log = log + "\n - enumeration_key = " + details[1];
+   log = log + "\n - enumeration_name = " + details[2];
+   log = log + "\n - enumeration_namespace = " + details[3];
+   log = log + "\n - enumeration_description = " + details[4];
+   log = log + "\n - enumeration_version = " + details[5];
+   log = log + "\n - enumeration_use_qt_enum_macro = " + details[6];
+   log = log + "\n - enumeration_list_of_keys = " + details[7];
+   log = log + "\n - enumeration_list_of_values = " + details[8];
+
+   print(log); // print value to the custom script debugger window
+   helper.print(log); // print value to the standard output (for example, on Windows, use the 'DebugView' application to see all logs)
+   return details;
+}
+
+

+
+

Acc�s aux m�ta-donn�es d'une + entit�/propri�t�/�num�ration

+
+ L'application QxEntityEditor permet de d�finir des m�ta-donn�es li�es � une entit�, propri�t� ou �num�ration. + Ces m�ta-donn�es peuvent �tre utilis�es par exemple pour d�finir du param�trage + suppl�mentaire non fourni par d�faut par QxEntityEditor. + Ces m�ta-donn�es sont accessibles dans le code C++ g�n�r� (moteur d'introspection de la biblioth�que QxOrm), et + sont accessibles �galement dans le moteur Javascript de QxEntityEditor. + Voici comment r�cup�rer des m�ta-donn�es en Javascript : +

+
+
var entity_id = params[13];
+var entity_meta_data = helper.getEntityMetaData(entity_id, "MY_ENTITY_META_DATA_KEY");
+
+// ...
+
+var property_meta_data = helper.getPropertyMetaData(property_id, "MY_PROPERTY_META_DATA_KEY");
+
+// ...
+
+var enumeration_id = params[15];
+var enumeration_meta_data = helper.getEnumerationMetaData(enumeration_id, "MY_ENUM_META_DATA_KEY");
+
+

+
+

Acc�der aux variables d'environnement

+
+ Voici comment acc�der aux variables d'environnement, + helper.getEnvironmentVariable() et + helper.setEnvironmentVariable() : +

+
+
var env_var = helper.getEnvironmentVariable("QT_DIR");
+var set_env_var_ok = helper.setEnvironmentVariable("MY_ENV_VAR", "my_value");
+
+

+
+

Gestion + des fichiers : lecture et �criture

+
+ Le moteur de personnalisation des exports Javascript de QxEntityEditor permet de lire des + fichiers, et permet d'�crire dans des fichiers. + Les classes Javascript file et dir permettent d'instancier des + objets Javascript pour effectuer des traitements sur les fichiers. +

+ La classe file propose la m�me d�finition que la classe Qt QFile : +

+
+
/*
+   --- 'file' class methods available by script (QFile wrapper : http://doc.qt.io/qt-5/qfile.html) ---
+
+   bool copy(string fileName, string newName);
+   bool exists(string fileName);
+   bool link(string fileName, string linkName);
+   bool remove(string fileName);
+   bool rename(string oldName, string newName);
+   string readAll(string fileName);
+
+   void setFileName(string name);
+   string fileName();
+   bool open(int mode); // enum QIODevice::OpenMode, for example : 26 = (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) = (2 + 8 + 16)
+   int error(); // enum QFile::FileError
+   void close();
+   bool atEnd();
+   string readLine();
+   void write(string text);
+*/
+
+

+ La classe dir propose la m�me d�finition que la classe Qt QDir : +

+
+
/*
+   --- 'dir' class methods available by script (QDir wrapper : http://doc.qt.io/qt-5/qdir.html) ---
+
+   void setPath(string path);
+   string path();
+   string appPath();
+   string homePath();
+   string rootPath();
+   string tempPath();
+
+   string fromNativeSeparators(string pathName);
+   string toNativeSeparators(string pathName);
+
+   string cleanPath(string path);
+   bool isAbsolutePath(string path);
+   bool isRelativePath(string path);
+   bool match(string filter, string fileName);
+
+   bool mkdir(string dirName);
+   bool mkpath(string dirPath);
+   bool rmdir(string dirName);
+   bool rmpath(string dirPath);
+   bool exists(string name);
+
+   bool cdUp();
+   bool cd(string dirName);
+   string absoluteFilePath(string fileName);
+   string absolutePath();
+   string canonicalPath();
+   string dirName();
+   string filePath(string fileName);
+   void refresh();
+   string relativeFilePath(string fileName);
+
+   bool isAbsolute();
+   bool isReadable();
+   bool isRelative();
+   bool isRoot();
+*/
+
+

+ Exemple : lire le contenu d'un fichier : +

+
+
var f1 = new file();
+var f1_content = f1.readAll("C:\\Temp\\my_file.txt");
+
+

+ Autre exemple : �crire dans un fichier : +

+
+
var f2 = new file();
+f2.setFileName("C:\\Temp\\file_generated_by_script.txt");
+f2.open(26); // (QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) = (2 + 8 + 16)
+f2.write("aaa");
+f2.write("bbb");
+f2.close();
+
+

+
+

Obtenir + la liste des toutes les entit�s/�num�rations d'un projet

+
+ Voici comment r�cup�rer la liste de toutes les entit�s et �num�rations d'un projet + *.qxee : +

+
+
var listOfAllEntities = helper.getListOfAllEntities(); // 'listOfAllEntities' variable is an array, each item of this array contains : <entity_id>|<entity_name>
+var listOfAllEnums = helper.getListOfAllEnums(); // 'listOfAllEnums' variable is an array, each item of this array contains : <enum_id>|<enum_name>
+
+

+
+

R�cup�rer + le param�trage de l'application (niveau global, projet et plugin)

+
+ Voici comment r�cup�rer tout le param�trage d�fini au niveau de l'application (au format + JSON) : + +
+
+
var globalSettings = helper.getQxEEGlobalSettingsJson();    // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+var projectSettings = helper.getQxEEProjectSettingsJson();  // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+var pluginSettings = helper.getQxEEPluginSetingsJson();     // the result is a string in JSON format ==> so just use JSON.parse() function to get a javascript object instance
+
+print(globalSettings); helper.print(globalSettings);
+print(projectSettings); helper.print(projectSettings);
+print(pluginSettings); helper.print(pluginSettings);
+
+globalSettings = JSON.parse(globalSettings);    // Now 'globalSettings' is a javascript object instance
+projectSettings = JSON.parse(projectSettings);  // Now 'projectSettings' is a javascript object instance
+pluginSettings = JSON.parse(pluginSettings);    // Now 'pluginSettings' is a javascript object instance
+
+

+
+
+

Ajout d'une + action (placeholder) personnalis�e dans le template d'export C++

+
+ Les plugins d'export C++ disposent d'un param�tre permettant de + d�finir le code source des fichiers Header *.h et Source *.cpp. + L'application QxEntityEditor propose plusieurs template par d�faut, et il est possible d'�crire + son propre template (option � Custom). + Cette d�finition des fichiers Header *.h et Source *.cpp utilisent + des mots-cl� (placeholder sous la forme @@ACTION@@) pour remplacer le code par la + valeur correspondante. + Cette notion de placeholder est la base du moteur de + personnalisation Javascript. + Il est possible de renseigner des placeholder + personnalis�s en prefixant par @@CUSTOM_, par exemple : + @@CUSTOM_MY_ACTION@@. +

+ Voici comment tester le code action courant (placeholder) dans le moteur Javascript : +

+
+ /* you can define your own placeholder in the template, it must start + with @@CUSTOM_, for example : @@CUSTOM_MY_ACTION@@ + ==> then, in the custom script, check if you are processing your custom action with this + code : */ +
var action = params[5];
+if (action == "CUSTOM_MY_ACTION")
+{
+   return "quit with my custom code here";
+}
+
+

+
+

Exemple + de script : ajout automatique de la d�finition Q_PROPERTY sur les propri�t�s C++ g�n�r�es +

+
+ Voici un exemple de script document� (fourni dans le dossier ./samples/q_property.js du + package QxEntityEditor) pour montrer comment ajouter automatiquement la d�finition Q_PROPERTY pour chacune des + propri�t�s du projet *.qxee : +

+
+
({
+
+/* ----------------------------------------------------------------------------------------
+   ----------------------------------------------------------------------------------------
+   'q_property.js' : custom javascript file to customize QxEntityEditor C++ export process.
+   This script is an example to show how to use QxEntityEditor javascript engine to add a Q_PROPERTY definition for each property generated by QxEntityEditor.
+   More details about Q_PROPERTY macro on Qt web site : http://doc.qt.io/qt-5/properties.html
+
+   To use this javascript file :
+      1- go to the main menu of QxEntityEditor 'Tools >> Export to C++ project (settings)' ;
+      2- select the C++ template 'qx::IxPersistable + QObject' : now generated entities will inherit from QObject, which is required to use the Qt Q_PROPERTY macro ;
+      3- in the field 'Custom script file' : put the location of this 'q_property.js' custom javascript file ;
+      4- save the settings and start the C++ export process ;
+      5- check generated files : Q_PROPERTY should be added automatically by the export process.
+   ----------------------------------------------------------------------------------------
+   ---------------------------------------------------------------------------------------- */
+
+// Here is the entry point of the QxEntityEditor javascript engine
+// This function is called for each placeholder defined in the C++ template section
+customProcess : function(params)
+{
+   try
+   {
+      // We use here the @@MACRO_QX_PERSISTABLE_HPP@@ placeholder which is present in the default C++ template 'qx::IxPersistable + QObject'
+      // You could also create your own custom C++ template (based on 'qx::IxPersistable + QObject' template), and create your own placeholder (which must be prefixed by @@CUSTOM_), for example : @@CUSTOM_Q_PROPERTY@@
+      var action = params[5];
+      if (action != "MACRO_QX_PERSISTABLE_HPP") { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Check if we have an entity
+      var entity_id = params[13];
+      if ((entity_id == "") || (entity_id == "0")) { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Get the list of properties
+      var entity_details = helper.getEntityDetails(entity_id);
+      var entity_list_of_properties_id = ((entity_details.length > 0) ? entity_details[10] : "");
+      var entity_list_of_properties_array = entity_list_of_properties_id.split("|");
+      if (entity_list_of_properties_array.length <= 0) { return params[0]; } // quit with 'params[0]' means : doesn't change the default export behaviour
+
+      // Prepare output string
+      var output = params[0] + "\n";
+
+      // Iterate over each property
+      for (var idx = 0; idx < entity_list_of_properties_array.length; idx++)
+      {
+         // Get property details
+         var property_id = entity_list_of_properties_array[idx];
+         var property_details = helper.getPropertyDetails(property_id);
+
+         // Here you could also get property meta-data that you can define in QxEntityEditor, property parameters screen, section 'List of meta-data'
+         // This is a way to manage your own property parameters which are not a part of QxEntityEditor
+         // It could be useful for example to manage some Q_PROPERTY settings like : RESET, NOTIFY, REVISION, DESIGNABLE, SCRIPTABLE, FINAL, etc...
+         // To get a property meta-data value, just write this code : var my_meta_data = helper.getPropertyMetaData(property_id, "MY_META_DATA_KEY");
+
+         // Get property type and name
+         var property_type = property_details[5];
+         var property_name = property_details[2];
+
+         // Check if property type can be used with Q_PROPERTY macro
+         if (list_of_compatible_property_type.indexOf(property_type) == -1) { continue; }
+
+         // Create Q_PROPERTY definition
+         output += "\n   Q_PROPERTY(" + property_type + " " + property_name + " READ get" + property_name + " WRITE set" + property_name + ")";
+      }
+
+      return output;
+   }
+   catch (err)
+   { return ("[CustomScriptError] an unexpected error occurred : " + err); }
+}
+
+});
+
+// Here is a list of C++ types compatible with Qt Q_PROPERTY macro (C++ type can be converted to/from QVariant)
+// You can of course register your own C++ types to be able to use them with Q_PROPERTY macro (using Qt Q_DECLARE_METATYPE() macro)
+// So the following array is not fixed : you can add all C++ types you want...
+var list_of_compatible_property_type = [ "QBitArray", "QBitmap", "bool", "QBrush", "QByteArray", "QChar", "QColor", "QDate", "QDateTime", "double", 
+                                         "QUuid", "QFont", "QVariantHash", "QIcon", "QImage", "int", "QLine", "QLineF", "QVariantList", "qlonglong", 
+                                         "QVariantMap", "QMatrix", "QMatrix4x4", "QPixmap", "QPoint", "QPointF", "QPolygon", "QPolygonF", "QRect", "QRectF", 
+                                         "QRegExp", "QRegion", "QSize", "QSizeF", "QString", "QStringList", "QTime", "uint", "qulonglong", "QUrl", 
+                                         "QVector2D", "QVector3D", "QVector4D" ];
+
+

+
+

Activation du + d�bogueur Javascript int�gr�

+
+ Le moteur Javascript de personnalisation des exports de QxEntityEditor int�gre un d�bogueur. + Cet environnement de d�bogage dispose de toutes les fonctionnalit�s n�cessaires pour vous aider + � d�velopper et corriger vos scripts : +
    +
  • d�finition de points d'arr�t (breakpoints) ;
  • +
  • mode pas � pas pour passer d'une ligne de code � une autre pendant l'ex�cution du script + ;
  • +
  • visualisation des variables et de leur valeur au fil de l'ex�cution ;
  • +
  • affichage d'une fen�tre de logs.
  • +
+
+ Par d�faut, le d�bogueur est d�sactiv� lors d'un export. Pour l'activer et afficher l'�cran + suivant, vous devez : +
    +
  • aller dans les param�tres d'export, d�finir + un script � utiliser, puis cliquer sur le bouton � Debug custom Javascript file � ; +
  • +
  • ou bien maintenir la touche SHIFT au lancement d'un export.
  • +
+
+ JS debug +

+
+
+ +

Ex�cution de scripts + personnalis�s avant/apr�s ex�cution d'un plugin

+
+ L'application QxEntityEditor permet de d�finir des scripts de type *.bat (Windows), + *.sh (Linux) ou m�me des ex�cutables � lancer avant ou apr�s ex�cution d'un plugin + QxEntityEditor. + Chaque script (ou processus) est appel� avec un param�tre d'entr�e : le chemin d'acc�s au fichier + projet *.qxee. + Cette fonctionnalit� peut �tre utilis�e par exemple pour : +
    +
  • int�grer les fichiers g�n�r�s par un export QxEntityEditor dans un gestionnaire de code + source (Git, Perforce, CVS, etc...) ;
  • +
  • d�marrer la compilation d'un projet C++ g�n�r� par QxEntityEditor ;
  • +
  • ex�cuter des tests unitaires ou bien lancer une int�gration continue avec un serveur Jenkins + par exemple ;
  • +
  • modifier des valeurs dans la base de donn�es SQLite d'un projet + *.qxee suite � un import de base de donn�es.
  • +
+
+ Pour d�finir les scripts ou ex�cutables � lancer suite � un processus d'import ou d'export de + QxEntityEditor, aller dans le menu principal : Tools >> Plugins scripts. +

+ Plugin scripts +

+ Remarque : pour d�finir un script � ex�cuter dans cette liste, il est possible de renseigner + le chemin d'acc�s absolu au script, ou bien un chemin relatif par rapport au projet *.qxee. + Par exemple, en mettant le chemin relatif ./my_script.sh, le fichier my_script.sh + doit se trouver dans le m�me r�pertoire que le fichier projet *.qxee de QxEntityEditor. +

+
+ +

Ex�cuter + QxEntityEditor en ligne de commande

+
+ L'application QxEntityEditor peut �tre d�marr�e en ligne de commande. Nous allons d�tailler dans ce + chapitre quelques exemples d'appels : +


+ -- Exemple n�1 : d�marrer QxEntityEditor en sp�cifiant un projet *.qxee � charger + (param�tre --project) : +
+
+ +
QxEntityEditor --project="c:\test\qxBlog.qxee"
+
+
+

+ -- Exemple n�2 : d�marrer QxEntityEditor sans afficher l'interface graphique (param�tre + --no_gui), en sp�cifiant un projet *.qxee � charger (param�tre --project) et + en d�marrant automatiquement un processus d'export C++ (param�tre --plugin) : +
+
+ +
QxEntityEditor --no_gui --project="c:\test\qxBlog.qxee" --plugin=QxEECppExport
+
+
+

+ -- Exemple n�3 : d�marrer QxEntityEditor en mode visionneuse (param�tre + --viewer_mode), ce mode permet d'ouvrir QxEntityEditor en mode lecture seule et permet de + charger des projets *.qxee sans cl� de licence : +
+
+ +
QxEntityEditor --viewer_mode
+
+
+

+ -- Exemple n�4 : d�marrer QxEntityEditor avec affichage des logs SQL (param�tre + --log_sql), ce param�tre permet de tracer toutes les requ�tes SQL effectu�es sur la base de donn�es SQLite du projet *.qxee : +
+
+ +
QxEntityEditor --log_sql
+
+
+

+ -- Exemple n�5 : d�marrer QxEntityEditor en chargeant un projet *.qxee � partir d'un + fichier JSON : +
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEEJsonImport --QxEEJsonImport_file="<path_to_your_json_file>"
+
+
+

+ -- Exemple n�6 : afficher la documentation de tous les param�tres en ligne de commande : +
+
+ +
QxEntityEditor --?
+
+
+
+ Ce qui produit le r�sultat suivant : +
+
+ +
*** QxEntityEditor 1.2.5 application global command line parameters ***
+
+  --project="<full path to *.qxee project file>" : run QxEntityEditor defining a *.qxee project to load at startup
+  --no_gui : run QxEntityEditor without displaying the user interface
+  --viewer_mode : run QxEntityEditor in read-only mode, this parameter can be used to open large *.qxee projects without any registered license key
+  --log_sql : run QxEntityEditor tracing all SQL logs, this parameter logs all SQL queries executed to *.qxee SQLite database
+  --font : define application font (due to issues since macOS Catalina 10.15) with syntax <family>||<pointSize>||<weight>||<italic> (only <family> is required), for example : Courier New||14
+  --style_sheet : define application style sheet (more details here : https://doc.qt.io/qt-5/stylesheet-reference.html), for example : QWidget { background-color: black }
+  --plugin=<plugin name> : run QxEntityEditor and execute automatically a plugin process (see below for specific parameters per plugin)
+
+*** Import plugin QxEEJsonImport ***
+
+  --QxEEJsonImport_file="<full path to your json file>" : [Required] run QxEntityEditor loading a *.qxee project from a JSON file
+
+*** Import plugin QxEEMySQLImport ***
+
+  --QxEEMySQLImport_db_ip="<DB IP>" : [Required] Database server address (IP)
+  --QxEEMySQLImport_db_port="<DB port>" : [Required] Port number to connect to database
+  --QxEEMySQLImport_db_name="<DB name>" : [Required] Database name
+  --QxEEMySQLImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEMySQLImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEMySQLImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEMySQLImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEMySQLImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEMySQLImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEMySQLImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEMySQLImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEMySQLImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEMySQLImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEMySQLImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEMySQLImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEMySQLImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEEOdbcImport ***
+
+  --QxEEOdbcImport_dsn="<ODBC DSN>" : [Required] ODBC DSN to connect to database
+  --QxEEOdbcImport_db_type=<numeric value> : [Required] Database engine type (0=generic, 1=postgresql, 2=mysql, 3=oracle, 4=mssqlserver, 5=sqlite)
+  --QxEEOdbcImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEOdbcImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEOdbcImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEOdbcImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEOdbcImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEOdbcImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEOdbcImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEOdbcImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEOdbcImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEOdbcImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEOdbcImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEOdbcImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEOdbcImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEEPostgreSQLImport ***
+
+  --QxEEPostgreSQLImport_db_ip="<DB IP>" : [Required] Database server address (IP)
+  --QxEEPostgreSQLImport_db_port="<DB port>" : [Required] Port number to connect to database
+  --QxEEPostgreSQLImport_db_name="<DB name>" : [Required] Database name
+  --QxEEPostgreSQLImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEEPostgreSQLImport_login="<DB Login>" : [Optional] Login to connect to database
+  --QxEEPostgreSQLImport_pwd="<DB Password>" : [Optional] Password to connect to database
+  --QxEEPostgreSQLImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEEPostgreSQLImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEEPostgreSQLImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEEPostgreSQLImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEEPostgreSQLImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEEPostgreSQLImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEEPostgreSQLImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEEPostgreSQLImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEEPostgreSQLImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEEPostgreSQLImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Import plugin QxEESQLiteImport ***
+
+  --QxEESQLiteImport_db_path="<DB File Path>" : [Required] SQLite database file path
+  --QxEESQLiteImport_filter_regexp="<Regular Expression>" : [Optional] Filter to select tables from database to import
+  --QxEESQLiteImport_namespace="<Namespace>" : [Optional] C++ namespace where imported classes will be located
+  --QxEESQLiteImport_delete_namespace=0/1 : [Optional] Delete all entities in the namespace before importing
+  --QxEESQLiteImport_import_comment=0/1 : [Optional] Import tables/columns comment to entities/properties description
+  --QxEESQLiteImport_import_default_value=0/1 : [Optional] Import columns default value
+  --QxEESQLiteImport_boost_optional=0/1 : [Optional] Add boost::optional<T> decoration if a column definition allows NULL value
+  --QxEESQLiteImport_organize_diagram=0/1 : [Optional] Organize diagram layout after import process
+  --QxEESQLiteImport_relation_decoration=<numeric value> : [Optional] Decoration used for relationships (0=no decoration, 1=boost::shared_ptr, 2=QSharedPointer, 5=std::shared_ptr)
+  --QxEESQLiteImport_relation_collection=<numeric value> : [Optional] Collection used for relationships (1=qx::QxCollection, 2=std::vector, 3=std::list, 8=QHash, 10=QList)
+  --QxEESQLiteImport_mapping_sql_to_cpp="sql1~cpp1;sql2~cpp2;etc..." : [Optional] List of mappings from SQL type to C++ type
+  --QxEESQLiteImport_verbose=0/1 : [Optional] Display more details during the import process
+
+*** Export plugin QxEECppExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppExport_path="<Export Path>" : [Optional] C++ export path parameter
+  --QxEECppExport_template_type=<numeric value> : [Optional] C++ template type selected to build C++ files (0=no_inheritance, 1=ix_persistable, 2=qx_persistable, 3=ix_persistable_and_q_object, 4=custom)
+  --QxEECppExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppExport_template_type parameter must be equal to 4, which means custom)
+  --QxEECppExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppExport_template_type parameter must be equal to 4, which means custom)
+  --QxEECppExport_qxorm_relative_path=0/1 : [Optional] Relative path to QxOrm library
+  --QxEECppExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEECppModelViewExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppModelViewExport_path="<Export Path>" : [Optional] C++ model/view export path parameter
+  --QxEECppModelViewExport_namespace="<Namespace>" : [Optional] Namespace where to put all model/view classes
+  --QxEECppModelViewExport_template_type=<numeric value> : [Optional] C++ model/view template type selected to build C++ files (0=default, 1=custom, 2=qx_model_service)
+  --QxEECppModelViewExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppModelViewExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppModelViewExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppModelViewExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppModelViewExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppModelViewExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEECppServicesExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEECppServicesExport_path="<Export Path>" : [Optional] C++ services export path parameter
+  --QxEECppServicesExport_namespace="<Namespace>" : [Optional] Namespace where to put all services classes
+  --QxEECppServicesExport_template_type=<numeric value> : [Optional] C++ services template type selected to build C++ files (0=default, 1=custom)
+  --QxEECppServicesExport_template_header="<Template Header>" : [Optional] Custom C++ template header file path (QxEECppServicesExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppServicesExport_template_source="<Template Source>" : [Optional] Custom C++ template source file path (QxEECppServicesExport_template_type parameter must be equal to 1, which means custom)
+  --QxEECppServicesExport_generate_custom_files=0/1 : [Optional] Generate a custom directory with custom files for each entity
+  --QxEECppServicesExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+  --QxEECppServicesExport_generate_server_app=0/1 : [Optional] Generate a sample server application
+  --QxEECppServicesExport_server_app_path="<Server App Path>" : [Optional] Server application location
+
+*** Export plugin QxEEGenericDDLExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEEGenericDDLExport_path="<Export Path>" : [Optional] DDL export path parameter
+  --QxEEGenericDDLExport_db_type=<numeric value> : [Optional] Database type (0=default, 1=sqlite, 2=mysql, 3=postgresql, 4=oracle, 5=mssqlserver)
+  --QxEEGenericDDLExport_relation_as_fk=0/1 : [Optional] Export relationships as foreign keys in database
+  --QxEEGenericDDLExport_schema_type=<numeric value> : [Optional] Way to export database schema (0=full, 1=evolution, 2=full_and_evolution)
+  --QxEEGenericDDLExport_custom_javacript="<Custom JS>" : [Optional] Custom script (javascript file) to change the default behaviour of the export process
+
+*** Export plugin QxEEPrinter ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process !!!
+
+*** Export plugin QxEEXmlExport ***
+
+  !!! Note : this plugin loads automatically previous parameters values before starting the export process, but you can use following parameters to override them !!!
+  --QxEEXmlExport_path="<Export Path>" : [Optional] XML or JSON export path parameter
+  --QxEEXmlExport_as_json=0/1 : [Optional] Export project as JSON format
+
+
+
+
+ Remarque : pour faire apparaitre les logs g�n�r�s par l'application QxEntityEditor : +
    +
  • Windows : utiliser un outil externe comme par exemple DebugView ;
  • +
  • Linux : d�marrer QxEntityEditor depuis un terminal ;
  • +
  • Mac OS X : d�marrer QxEntityEditor depuis un terminal en allant dans le sous-dossier + QxEntityEditor.app, par exemple : cd QxEntityEditor.app/Content/MacOS/, puis : + ./QxEntityEditor +
  • +
+

+ -- Exemple n�7 : importer en ligne de commande un sch�ma de base de donn�es par ODBC (plugin + QxEEOdbcImport) : +
+
+ +
QxEntityEditor --no_gui --project="<project_path>" --plugin=QxEEOdbcImport --QxEEOdbcImport_db_type=1 --QxEEOdbcImport_dsn="<your_dsn>" --QxEEOdbcImport_login="<your_login>" --QxEEOdbcImport_pwd="<your_password>" --QxEEOdbcImport_delete_namespace=1
+
+
+

+ -- Exemple n�8 : importer en ligne de commande un sch�ma de base de donn�es PostgreSQL + (plugin QxEEPostgreSQLImport) : +
+
+ +
QxEntityEditor --no_gui --project="<project_path>" --plugin=QxEEPostgreSQLImport --QxEEPostgreSQLImport_db_ip="<ip>" --QxEEPostgreSQLImport_db_port=5432 --QxEEPostgreSQLImport_db_name="<dbname>" --QxEEPostgreSQLImport_login="<your_login>" --QxEEPostgreSQLImport_pwd="<your_password>" --QxEEPostgreSQLImport_delete_namespace=1
+
+
+

+ -- Exemple n�9 : exporter en ligne de commande un projet QxEntityEditor associ� � un + gestionnaire de code source Git, Perforce, CVS, etc. (plugin QxEESourceControlExport) : +
+
+ +
QxEntityEditor --no_gui --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlExport --QxEESourceControlExport_path="<path_to_your_export_output_directory>"
+
+
+

+ -- Exemple n�10 : importer en ligne de commande un projet QxEntityEditor associ� � un + gestionnaire de code source Git, Perforce, CVS, etc. (plugin QxEESourceControlImport) : +
+
+ +
QxEntityEditor --project="<path_to_your_qxee_project_file>" --plugin=QxEESourceControlImport --QxEESourceControlImport_path="<path_to_the_root_source_control_json_file>"
+
+
+

+
+ +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/model.html b/doc/qxorm_fr/model.html new file mode 100644 index 0000000..5c759d8 --- /dev/null +++ b/doc/qxorm_fr/model.html @@ -0,0 +1,177 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> [model] + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/quick_sample.html b/doc/qxorm_fr/quick_sample.html new file mode 100644 index 0000000..2f2a2ef --- /dev/null +++ b/doc/qxorm_fr/quick_sample.html @@ -0,0 +1,460 @@ + + + + + + QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor + (data model designer and source code generator) + + + + + + + + + + + + + + + + + + + + + +
QxOrm + + + + Windows + Linux + Macintosh + C++
+
+ + + + + + + + + + + + + + + + + + +
AccueilT�l�chargementExemple rapide + Tutoriel (4) + + + + + + +
+ +
+
+ Manuel (2) + + + + + + +
+ +
+
ForumNos clients
+
+ + + + + + + + + + + + + + + + + +
+ QxOrm >> Exemple rapide + + + + + + + + + + + + + + +
+ Version courante :  + + QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub +
+ + + QxEntityEditor 1.2.8 +
+
Version fran�aise du siteWeb site english version
+ + + + + + + +
+ + + + + + + + + +
Dans ce chapitre, nous allons traiter un exemple + rapide d'utilisation qui pr�sente les fonctionnalit�s de base de la + biblioth�que QxOrm.
+
+ Remarque : la biblioth�que QxOrm utilise les conventions d'�criture de code C++ + suivantes : +
    +
  • toutes les classes, fonctions, variables, etc... sont d�finies sous le namespace qx +
  • +
  • les macro de QxOrm sont �crites sous la forme QX_... +
  • +
  • les classes abstraites (ou interfaces) sont pr�fix�es par Ix (par exemple + IxFactory est une interface pour la cr�ation d'instances) +
  • +
  • les autres classes sont pr�fix�es par Qx (par exemple QxDataMember) +
  • +
  • les collections d'objets ont pour suffixe X (par exemple QxDataMemberX est une + collection de QxDataMember) +
  • +
  • les fonctions pour communiquer avec les bases de donn�es se trouvent sous le namespace qx::dao (par exemple + qx::dao::fetch_by_id()) +
  • +
  • les fonctions pour la serialization des donn�es se trouvent sous le namespace qx::serialization + (par exemple qx::serialization::xml::to_file()) +
  • +
  • le moteur de reflection est accessible depuis la classe qx::QxClassX (par + exemple qx::QxClassX::invoke() pour invoquer une m�thode de classe) +
  • +
  • les classes de traits se trouvent sous le namespace qx::trait (par exemple + qx::trait::is_smart_ptr<T>) +
  • +
+
qt_ambassador
+ + QxOrm library has been accepted into the Qt Ambassador + Program + +
+ Autre Remarque : un exemple plus complet (avec notion d'h�ritage, de + relations entre tables, de collections, de libraries partag�es, de + memory leak, etc...) est pr�sent dans le dossier ./test/qxDllSample/ de la + distribution de QxOrm. Ce dossier ./test/qxDllSample/ contient 2 projets de + type dll et 1 projet de type ex�cutable : ./dll1/, + ./dll2/ et ./exe/.
La solution compl�te peut �tre + compil�e avec Visual C++ 2008, 2010 ou 2012 sous Windows (ouvrir le fichier + ./test/qxDllSample/test.sln).
+ Elle peut �tre �galement compil�e avec GCC sous Linux et MinGW sous Windows en utilisant la + commande qmake.
+
+ L'exemple qui suit pr�sente diff�rentes �tapes : + +
+ * + -----------------------------------------------------------------------------------------------------
+ * 1- fichier drug.h : d�finition d'une classe drug avec 3 + attributs : id, name et description

+ * + -----------------------------------------------------------------------------------------------------
+

+ + + + + + + +
+
#ifndef _CLASS_DRUG_H_
+#define _CLASS_DRUG_H_
+
+class drug
+{
+public:
+   long id;
+   QString name;
+   QString description;
+
+   drug() : id(0) { ; }
+   virtual ~drug() { ; }
+};
+
+QX_REGISTER_HPP_MY_TEST_EXE(drug, qx::trait::no_base_class_defined, 1)
+
+/* This macro is necessary to register 'drug' class in QxOrm context */
+/* param 1 : the current class to register => 'drug' */
+/* param 2 : the base class, if no base class, use the qx trait => 'qx::trait::no_base_class_defined' */
+/* param 3 : the class version used by serialization to provide 'ascendant compatibility' */
+
+#endif // _CLASS_DRUG_H_
+
+

+ * + ----------------------------------------------------------------------------------------------------
+ * 2- fichier drug.cpp : impl�mentation de la 'fonction de + param�trage' : void qx::register_class()
+ * + ---------------------------------------------------------------------------------------------------- +


+ + + + + + + +
+
#include "precompiled.h"   // Precompiled-header with '#include <QxOrm.h>' and '#include "export.h"'
+#include "drug.h"          // Class definition 'drug'
+#include <QxOrm_Impl.h>     // Automatic memory leak detection and boost serialization export macro
+
+QX_REGISTER_CPP_MY_TEST_EXE(drug)   // This macro is necessary to register 'drug' class in QxOrm context
+
+namespace qx {
+template <> void register_class(QxClass<drug> & t)
+{
+  t.id(& drug::id, "id");               // Register 'drug::id' <=> primary key in your database
+  t.data(& drug::name, "name", 1);      // Register 'drug::name' property with key 'name' and version '1'
+  t.data(& drug::description, "desc");  // Register 'drug::description' property with key 'desc'
+}}
+
+
+
+ * + -----------------------------------------------------------------------------------------------
+ * 3- fichier main.cpp : pr�sentation des fonctionnalit�s de base + de QxOrm avec la classe drug
+ * + ----------------------------------------------------------------------------------------------- +


+ + + + + + + +
+
#include "precompiled.h"
+#include "drug.h"
+#include <QxOrm_Impl.h>
+
+int main(int argc, char * argv[])
+{
+   QApplication app(argc, argv); // Qt application
+
+   // Create 3 new drugs
+   // It is possible to use 'std' and 'Qt' smart pointer : 'std::shared_ptr', 'QSharedPointer', etc...
+   typedef std::shared_ptr<drug> drug_ptr;
+   drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1";
+   drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2";
+   drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3";
+
+   // Insert drugs into container
+   // It is possible to use a lot of containers from 'std', 'boost', 'Qt' and 'qx::QxCollection<Key, Value>'
+   typedef std::vector<drug_ptr> type_lst_drug;
+   type_lst_drug lst_drug;
+   lst_drug.push_back(d1);
+   lst_drug.push_back(d2);
+   lst_drug.push_back(d3);
+
+   // Init parameters to communicate with a database
+   qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
+   qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
+   qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
+   qx::QxSqlDatabase::getSingleton()->setUserName("root");
+   qx::QxSqlDatabase::getSingleton()->setPassword("");
+
+   // Create table 'drug' into database to store drugs
+   QSqlError daoError = qx::dao::create_table<drug>();
+
+   // Insert drugs from container to database
+   // 'id' property of 'd1', 'd2' and 'd3' are auto-updated
+   daoError = qx::dao::insert(lst_drug);
+
+   // Modify and update the second drug into database
+   d2->name = "name2 modified";
+   d2->description = "desc2 modified";
+   daoError = qx::dao::update(d2);
+
+   // Delete the first drug from database
+   daoError = qx::dao::delete_by_id(d1);
+
+   // Count drugs into database
+   long lDrugCount = qx::dao::count<drug>();
+
+   // Fetch drug with id '3' into a new variable
+   drug_ptr d_tmp; d_tmp.reset(new drug());
+   d_tmp->id = 3;
+   daoError = qx::dao::fetch_by_id(d_tmp);
+
+   // Export drugs from container to a file under xml format (serialization)
+   qx::serialization::xml::to_file(lst_drug, "./export_drugs.xml");
+
+   // Import drugs from xml file into a new container
+   type_lst_drug lst_drug_tmp;
+   qx::serialization::xml::from_file(lst_drug_tmp, "./export_drugs.xml");
+
+   // Clone a drug
+   drug_ptr d_clone = qx::clone(* d1);
+
+   // Create a new drug by class name (factory)
+   qx::any d_any = qx::create("drug");
+
+   // Insert drugs container into 'qx::cache'
+   qx::cache::set("drugs", lst_drug);
+
+   // Remove all elements from 'qx::cache'
+   qx::cache::clear();
+
+   // Create a dummy memory leak
+   drug * pDummy = new drug();
+
+   return 0;
+}
+
+
+

+ * + -------------------------------------------------------------------------
+ * 4- ex�cution du programme de test et affichage des traces g�n�r�es
+ * + -------------------------------------------------------------------------
+

+

+

+ [QxOrm] qx::QxSqlDatabase : create new database + connection in thread '3616' with key + '{d315250c-b5c9-46e0-9402-f800368a6673}'
+ [QxOrm] sql query (78 ms) : CREATE TABLE drug (id INTEGER NOT NULL + PRIMARY KEY AUTOINCREMENT, name TEXT, desc TEXT)
+ [QxOrm] sql query (63 ms) : INSERT INTO drug (name, desc) VALUES + (:name, :desc)
+ [QxOrm] sql query (62 ms) : UPDATE drug SET id = :id, name = :name, + desc = :desc WHERE id = :id_bis
+ [QxOrm] sql query (63 ms) : DELETE FROM drug WHERE id = :id
+ [QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM drug
+ [QxOrm] sql query (0 ms) : SELECT drug.id AS drug_id_0, drug.name AS + drug_name_0, drug.desc AS drug_desc_0 FROM drug WHERE drug_id_0 = + :id
+ [QxOrm] Leaked object at 0xf52ad8 (size 16, src\main.cpp:74)
+ [QxOrm] **** 1 memory leaks found ****

+
+

+ * + ------------------------------------------------------------------------------
+ * 5- contenu du fichier ./export_drugs.xml cr�� par le programme + de test
+ * + ------------------------------------------------------------------------------
+

+
+ quick_sample.export_drugs.xml +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/doc/qxorm_fr/resource/ES.png b/doc/qxorm_fr/resource/ES.png new file mode 100644 index 0000000..805a1b6 Binary files /dev/null and b/doc/qxorm_fr/resource/ES.png differ diff --git a/doc/qxorm_fr/resource/FR.png b/doc/qxorm_fr/resource/FR.png new file mode 100644 index 0000000..35e3aaa Binary files /dev/null and b/doc/qxorm_fr/resource/FR.png differ diff --git a/doc/qxorm_fr/resource/GB.png b/doc/qxorm_fr/resource/GB.png new file mode 100644 index 0000000..3a18908 Binary files /dev/null and b/doc/qxorm_fr/resource/GB.png differ diff --git a/doc/qxorm_fr/resource/background.jpg b/doc/qxorm_fr/resource/background.jpg new file mode 100644 index 0000000..d9f012a Binary files /dev/null and b/doc/qxorm_fr/resource/background.jpg differ diff --git a/doc/qxorm_fr/resource/download.jpg b/doc/qxorm_fr/resource/download.jpg new file mode 100644 index 0000000..252f63c Binary files /dev/null and b/doc/qxorm_fr/resource/download.jpg differ diff --git a/doc/qxorm_fr/resource/gui_qxClientServer.jpg b/doc/qxorm_fr/resource/gui_qxClientServer.jpg new file mode 100644 index 0000000..5f10aa1 Binary files /dev/null and b/doc/qxorm_fr/resource/gui_qxClientServer.jpg differ diff --git a/doc/qxorm_fr/resource/gui_qxClient_01.jpg b/doc/qxorm_fr/resource/gui_qxClient_01.jpg new file mode 100644 index 0000000..c505283 Binary files /dev/null and b/doc/qxorm_fr/resource/gui_qxClient_01.jpg differ diff --git a/doc/qxorm_fr/resource/gui_qxClient_02.jpg b/doc/qxorm_fr/resource/gui_qxClient_02.jpg new file mode 100644 index 0000000..90e964b Binary files /dev/null and b/doc/qxorm_fr/resource/gui_qxClient_02.jpg differ diff --git a/doc/qxorm_fr/resource/gui_qxServer.jpg b/doc/qxorm_fr/resource/gui_qxServer.jpg new file mode 100644 index 0000000..e8a0549 Binary files /dev/null and b/doc/qxorm_fr/resource/gui_qxServer.jpg differ diff --git a/doc/qxorm_fr/resource/jquery.min.js b/doc/qxorm_fr/resource/jquery.min.js new file mode 100644 index 0000000..0f60b7b --- /dev/null +++ b/doc/qxorm_fr/resource/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; + +return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("
+
+ Cette vid�o pr�sente les �tapes suivantes : +
    +
  • T�l�charger et installer la biblioth�que QxOrm (10s) ;
  • +
  • T�l�charger et installer l'application QxEntityEditor (56s) ;
  • +
  • Cr�er un projet QxEntityEditor (1m 46s) ;
  • +
  • Exporter les entit�s vers un projet C++/Qt (8m 26s) ;
  • +
  • Exporter les entit�s vers un script DDL SQL de base de donn�es (10m 22s) ;
  • +
  • Cr�er une application client/serveur pour transf�rer son mod�le de donn�es sur le r�seau (12m + 31s) ;
  • +
  • Exporter un projet QxEntityEditor vers un fichier XML ou JSON (17m 13s) ;
  • +
  • Ex�cuter QxEntityEditor en ligne de commande (sans IHM) (18m 07s).
  • +
+
+
+
+ Voici une autre vid�o de l'application + QxEntityEditor pour montrer comment importer une structure de base de donn�es existante (projet MySQL + Workbench) :
+
+
+
+ Cette vid�o pr�sente les �tapes suivantes : +
    +
  • Projet MySQL Workbench - exemple de base de donn�es Sakila (10s) ;
  • +
  • Cr�ation d'un DSN pour se connecter � MySQL par ODBC (46s) ;
  • +
  • Import de la structure de base de donn�es dans un projet QxEntityEditor (1m 15s) ;
  • +
  • Export du projet QxEntityEditor vers un projet C++ Qt (3m 10s) ;
  • +
  • Compilation des classes g�n�r�es du projet C++ Qt (4m 22s).
  • +
+
+ + + +
+
+
+ + + + + + + + + + + +
+ QxOrm + + � 2011-202XDL Teamty - ic-east.com + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/include/QxCollection/IxCollection.h b/include/QxCollection/IxCollection.h new file mode 100644 index 0000000..b3c895d --- /dev/null +++ b/include/QxCollection/IxCollection.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 _IX_COLLECTION_H_ +#define _IX_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxCollection.h + * \author XDL Team + * \ingroup QxCollection + * \brief Common interface for all QxOrm containers qx::QxCollection + */ + +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxCollection + * \brief qx::IxCollection : common interface for all QxOrm containers qx::QxCollection + */ + class QX_DLL_EXPORT IxCollection + { + + public: + IxCollection() { ; } + virtual ~IxCollection() = 0; + + virtual long _count() const = 0; + virtual void _clear() = 0; + virtual bool _remove(long index) = 0; + virtual qx::any _at(long index) const = 0; + + template + T _get(long index) const + { + return qx::any_cast_dynamic::get(_at(index)); + } + }; + + typedef std::shared_ptr IxCollection_ptr; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(IxCollection) + +#endif // _IX_COLLECTION_H_ diff --git a/include/QxCollection/QxCollection.h b/include/QxCollection/QxCollection.h new file mode 100644 index 0000000..8a59087 --- /dev/null +++ b/include/QxCollection/QxCollection.h @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** 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_COLLECTION_H_ +#define _QX_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxCollection.h + * \author XDL Team + * \ingroup QxCollection + * \brief QxOrm thread-safe container (keep insertion order + quick access by index + quick access by key) + */ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4503) +#endif // _MSC_VER + +#include + +#include +#include + +#include + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxCollection + * \brief qx::QxCollection : QxOrm thread-safe container (keep insertion order + quick access by index + quick access by key) + * + * Based on boost::multi_index_container, this collection has advantages of std::vector (keep insertion order + quick access by index) + * and boost::unordered_map or QHash (quick access by key : hash-map). + * + * Note : qx::QxCollection is compatible with the foreach macro provided by Qt library and the BOOST_FOREACH macro provided by boost library. + * However, each element returned by these 2 macros corresponds to an object of type std::pair. + * To obtain a more natural and more readable result, it is advised to use the _foreach macro : this macro uses BOOST_FOREACH for all the containers except for qx::QxCollection. + * In this case, the returned element corresponds to the Value type (cf. following sample). + * The macro _foreach is compatible with all containers (stl, Qt, boost...) since it uses the macro BOOST_FOREACH. + * + * Additional note : qx::QxCollection is particularly suited to receive data resulting from a database. + * Indeed, these data can be sorted (by using ORDER BY in a SQL request for example), it is thus important to preserve the insertion order of the elements in the list. + * Furthermore, each data resulting from a database has a unique id. It is thus important to be able to access quickly to an element based on this single identifier (hash-map). + * + * Quick sample using qx::QxCollection container : + * \code + // definition of drug class with 3 properties : 'code', 'name' and 'description' + class drug { public: QString code; QString name; QString desc; }; + + // typedef a smart-pointer of drug class + typedef std::shared_ptr drug_ptr; + + // collection of drugs indexed by 'code' property (QString type) + qx::QxCollection lstDrugs; + + // create 3 new drugs + drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1"; + drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2"; + drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3"; + + // insert 3 drugs into the collection + lstDrugs.insert(d1->code, d1); + lstDrugs.insert(d2->code, d2); + lstDrugs.insert(d3->code, d3); + + // iterate over drugs container using QxOrm '_foreach' keyword + _foreach(drug_ptr p, lstDrugs) + { qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); } + + // iterate over drugs container using classic C++ 'for' keyword + for (long l = 0; l < lstDrugs.count(); ++l) + { + drug_ptr p = lstDrugs.getByIndex(l); + QString code = lstDrugs.getKeyByIndex(l); + qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); + } + + // iterate over drugs container using 'qx::QxCollectionIterator' Java-style iterator + qx::QxCollectionIterator itr(lstDrugs); + while (itr.next()) + { + QString code = itr.key(); + qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc); + } + + // sort drugs container ascending by key and sort descending by value + lstDrugs.sortByKey(true); + lstDrugs.sortByValue(false); + + // access to a drug into the collection by its 'code' property + drug_ptr p = lstDrugs.getByKey("code2"); + + // access to a drug into the collection by index (position in the list) + drug_ptr p = lstDrugs.getByIndex(2); + + // test if a drug exists into the collection and if the collection is empty + bool bExist = lstDrugs.exist("code3"); + bool bEmpty = lstDrugs.empty(); + + // remove the second drug from the collection + lstDrugs.removeByIndex(2); + + // remove a drug from the collection using its 'code' property + lstDrugs.removeByKey("code3"); + + // clear the collection : remove all items from the list + lstDrugs.clear(); + * \endcode + */ + template + class QxCollection : public IxCollection + { + + public: + typedef QPair type_pair_key_value; + + protected: + typedef QList type_list_pair_key_value; + typedef QHash type_hash_position; + + public: + typedef typename type_list_pair_key_value::iterator iterator; + typedef typename type_list_pair_key_value::const_iterator const_iterator; + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + typedef typename type_list_pair_key_value::reverse_iterator reverse_iterator; + typedef typename type_list_pair_key_value::const_reverse_iterator const_reverse_iterator; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + + typedef const Key &const_reference_key; + typedef const Value &const_reference_value; + + protected: + mutable QMutex m_mutex; //!< Mutex => qx::QxCollection is thread-safe + type_list_pair_key_value m_list; //!< Container to keep insertion order + type_hash_position m_hash; //!< Container for fast search by key + bool m_batch; //!< Batch mode to sync internal containers + + public: + QxCollection(); //!< Construct an empty list + QxCollection(const QxCollection &other); //!< Construct a copy of 'other' + virtual ~QxCollection(); //!< Destroy the list + + QxCollection &operator=(const QxCollection &other); //!< Assign 'other' to this list and return a reference to this list + bool operator==(const QxCollection &other) const; //!< Return 'true' if 'other' is equal to this list, otherwise return 'false' (same values in the same order) + bool operator!=(const QxCollection &other) const; //!< Return 'true' if 'other' is not equal to this list, otherwise return 'false' + + iterator begin(); //!< Return an STL-style iterator pointing to the first item in the list + iterator end(); //!< Return an STL-style iterator pointing to the imaginary item after the last item in the list + const_iterator begin() const; //!< Return a const STL-style iterator pointing to the first item in the list + const_iterator end() const; //!< Return a const STL-style iterator pointing to the imaginary item after the last item in the list + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + reverse_iterator rbegin(); //!< Return a reverse STL-style iterator pointing to the first item in the list + reverse_iterator rend(); //!< Return a reverse STL-style iterator pointing to the imaginary item after the last item in the list + const_reverse_iterator rbegin() const; //!< Return a const reverse STL-style iterator pointing to the first item in the list + const_reverse_iterator rend() const; //!< Return a const reverse STL-style iterator pointing to the imaginary item after the last item in the list +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + + void reserve(long size); //!< Request that the capacity of the allocated storage space for the items of the container be at least enough to hold 'size' elements + void reverse(); //!< Reverse all items in the list + void clear(); //!< Remove all items from the list + long count() const; //!< Return the number of items in the list (same as 'size()') + long size() const; //!< Return the number of items in the list (same as 'count()') + bool contains(const Key &key) const; //!< Return 'true' if the list contains an occurrence of 'key', otherwise return 'false' (same as 'exist()') + bool exist(const Key &key) const; //!< Return 'true' if the list contains an occurrence of 'key', otherwise return 'false' (same as 'contains()') + bool empty() const; //!< Return 'true' if the list contains no items; otherwise return 'false' + + bool push_back(const Key &key, const Value &value); //!< Add element 'value' at the end of the list indexed by 'key' + bool push_front(const Key &key, const Value &value); //!< Insert 'value' at the beginning of the list indexed by 'key' + bool insert(const Key &key, const Value &value); //!< Add element 'value' at the end of the list indexed by 'key' + bool insert(long index, const Key &key, const Value &value); //!< Insert element 'value' at position 'index' in the list indexed by 'key' + bool insert(const QxCollection &other); //!< Add all items of 'other' at the end of the list + bool insert(long index, const QxCollection &other); //!< Insert all items of 'other' at the end of the list + bool replace(long index, const Key &key, const Value &value); //!< Replace the item at index position 'index' with element 'value' indexed by 'key' + bool swap(long index1, long index2); //!< Exchange the item at index position 'index1' with the item at index position 'index2' + bool move(long indexFrom, long indexTo); //!< Move the item at index position 'indexFrom' to index position 'indexTo' + + bool removeByKey(const Key &key); //!< Remove the item indexed by 'key' in the list + bool removeByIndex(long index); //!< Remove the item at index position 'index' + bool removeByIndex(long first, long last); //!< Remove all items from index position 'first' to index position 'last' + bool removeFirst(); //!< Remove the first item in the list + bool removeLast(); //!< Remove the last item in the list + + const_reference_value getByKey(const Key &key) const; //!< Return the item associated with the 'key' + const_reference_value getByIndex(long index) const; //!< Return the item at index position 'index' + const_reference_value getFirst() const; //!< Return the first element in the list + const_reference_value getLast() const; //!< Return the last element in the list + const_reference_key getKeyByIndex(long index) const; //!< Return the key associated with the element at index position 'index' + + void sortByKey(bool bAscending = true); //!< Sort all items in the list using associated keys to compare + void sortByValue(bool bAscending = true); //!< Sort all items in the list + + template + void sort(Compare comp) + { + { + QMutexLocker locker(&m_mutex); + std::sort(m_list.begin(), m_list.end(), comp); + } + updateHashPosition(); + } + + protected: + void cloneCollection(QxCollection *pClone, const QxCollection &pRef); + bool isSameCollection(const QxCollection *p1, const QxCollection &p2) const; + void updateHashPosition(long from = 0, long to = -1, bool check = false); + + template + struct compareKeyValue + { + static bool compareByKeyAscending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return (v1.first < v2.first); } + static bool compareByKeyDescending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return (v1.first > v2.first); } + static bool compareByValueAscending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return (v1.second < v2.second); } + static bool compareByValueDescending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return (v1.second > v2.second); } + }; + + template + struct compareKeyValue + { + static bool compareByKeyAscending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return ((v1.first && v2.first) ? ((*v1.first) < (*v2.first)) : false); } + static bool compareByKeyDescending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return ((v1.first && v2.first) ? ((*v1.first) > (*v2.first)) : true); } + static bool compareByValueAscending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return ((v1.second && v2.second) ? ((*v1.second) < (*v2.second)) : false); } + static bool compareByValueDescending(const type_pair_key_value &v1, const type_pair_key_value &v2) { return ((v1.second && v2.second) ? ((*v1.second) > (*v2.second)) : true); } + }; + + public: + virtual long _count() const { return this->count(); } + virtual void _clear() { this->clear(); } + virtual bool _remove(long index) { return this->removeByIndex(index); } + virtual qx::any _at(long index) const + { + Value val = this->getByIndex(index); + return qx::any(val); + } + }; + +} // namespace qx + +#include "../../inl/QxCollection/QxCollection.inl" + +QX_REGISTER_CLASS_NAME_TEMPLATE_2(qx::QxCollection) + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_COLLECTION_H_ diff --git a/include/QxCollection/QxCollectionIterator.h b/include/QxCollection/QxCollectionIterator.h new file mode 100644 index 0000000..56dd4de --- /dev/null +++ b/include/QxCollection/QxCollectionIterator.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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_COLLECTION_ITERATOR_H_ +#define _QX_COLLECTION_ITERATOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxCollectionIterator.h + * \author XDL Team + * \ingroup QxCollection + * \brief Java-style iterator to iterate over a qx::QxCollection container + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxCollection + * \brief qx::QxCollectionIterator : Java-style iterator to iterate over a qx::QxCollection container + * + * Quick sample using qx::QxCollectionIterator Java-style iterator : + * \code + // iterate over a drugs container using 'qx::QxCollectionIterator' Java-style iterator + qx::QxCollectionIterator itr(lstDrugs); + while (itr.next()) + { + QString code = itr.key(); + qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc); + } + * \endcode + */ + template + class QxCollectionIterator + { + + private: + const QxCollection *m_pCollection; //!< Collection to iterate over + long m_lCurrIndex; //!< Current index (position) in the collection + + public: + QxCollectionIterator(const QxCollection &col); //!< Construct an iterator for traversing the collection. The iterator is set to be at the front of the list (before the first item) + ~QxCollectionIterator(); //!< Destroy the iterator + + inline const Key &key() const; //!< Return the 'key' at current position + inline const Value &value() const; //!< Return the 'value' at current position + + inline void toFirst(); //!< Move the iterator to the front of the container (before the first item) + inline void toLast(); //!< Move the iterator to the back of the container (after the last item) + + inline bool next(); //!< Advance the iterator by one position. Return 'true' if there is at least one item ahead of the iterator, i.e. the iterator is not at the back of the container; otherwise return 'false' + inline bool previous(); //!< Move the iterator back by one position. Return 'true' if there is at least one item behind the iterator, i.e. the iterator is not at the front of the container; otherwise return 'false' + + private: + QxCollectionIterator(const QxCollectionIterator &other) { Q_UNUSED(other); } + QxCollectionIterator &operator=(const QxCollectionIterator &other) + { + Q_UNUSED(other); + return (*this); + } + }; + +} // namespace qx + +#include "../../inl/QxCollection/QxCollectionIterator.inl" + +#endif // _QX_COLLECTION_ITERATOR_H_ diff --git a/include/QxCollection/QxForeach.h b/include/QxCollection/QxForeach.h new file mode 100644 index 0000000..2fb0e0a --- /dev/null +++ b/include/QxCollection/QxForeach.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_FOREACH_H_ +#define _QX_FOREACH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxForeach.h + * \author XDL Team + * \ingroup QxCollection + * \brief foreach-style (based on BOOST_FOREACH macro) to iterate over all stl, boost and Qt containers + qx::QxCollection QxOrm library container + * + * Quick sample using QX_FOREACH (or _foreach) macro : + * \code +// iterate over drugs container using QxOrm '_foreach' keyword +_foreach(drug_ptr p, lstDrugs) +{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); } + * \endcode + * + * \note QxOrm library provides also other macros to iterator over all containers : _foreach_reverse, _foreach_if, _foreach_reverse_if + */ + +#include + +#ifndef BOOST_FOREACH_ID +#define BOOST_FOREACH_ID(x) x +#endif + +#include + +namespace qx +{ + + namespace foreach + { + + template + struct qx_deref_boost_or_qx + { + typedef typename boost::foreach_detail_::foreach_reference::type type; + }; + + template + struct qx_deref_boost_or_qx + { + typedef typename T::type_pair_key_value::second_type type; + }; + + template + struct qx_deref_deduce + { + static inline typename qx::foreach::qx_deref_boost_or_qx::type + deref(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return boost::foreach_detail_::deref(cur, ptmp); + } + + static inline typename qx::foreach::qx_deref_boost_or_qx::type + rderef(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return boost::foreach_detail_::rderef(cur, ptmp); + } + }; + + template + struct qx_deref_deduce + { + static inline typename qx::foreach::qx_deref_boost_or_qx::type + deref(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return boost::foreach_detail_::deref(cur, ptmp).second; + } + + static inline typename qx::foreach::qx_deref_boost_or_qx::type + rderef(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return boost::foreach_detail_::rderef(cur, ptmp).second; + } + }; + + struct qx_deref + { + template + static inline typename qx::foreach::qx_deref_boost_or_qx::value>::type + deref(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return qx::foreach::qx_deref_deduce::value>::deref(cur, ptmp); + } + + template + static inline typename qx::foreach::qx_deref_boost_or_qx::value>::type + deref_reverse(boost::foreach_detail_::auto_any_t cur, boost::foreach_detail_::type2type *ptmp) + { + return qx::foreach::qx_deref_deduce::value>::rderef(cur, ptmp); + } + }; + + } // namespace foreach + +} // namespace qx + +#define QX_FOREACH_DEREF(COL) \ + qx::foreach::qx_deref::deref(BOOST_FOREACH_ID(_foreach_cur), BOOST_FOREACH_TYPEOF(COL)) + +#define QX_FOREACH_DEREF_REVERSE(COL) \ + qx::foreach::qx_deref::deref_reverse(BOOST_FOREACH_ID(_foreach_cur), BOOST_FOREACH_TYPEOF(COL)) + +#define QX_FOREACH(VAR, COL) \ + BOOST_FOREACH_PREAMBLE() \ + if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL)) \ + { \ + } \ + else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) \ + { \ + } \ + else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_END(COL)) \ + { \ + } \ + else \ + for (bool BOOST_FOREACH_ID(_foreach_continue) = true; \ + BOOST_FOREACH_ID(_foreach_continue) && !BOOST_FOREACH_DONE(COL); \ + BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_NEXT(COL) : (void)0) \ + if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue))) \ + { \ + } \ + else \ + for (VAR = QX_FOREACH_DEREF(COL); !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true) + +#define QX_FOREACH_REVERSE(VAR, COL) \ + BOOST_FOREACH_PREAMBLE() \ + if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL)) \ + { \ + } \ + else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_RBEGIN(COL)) \ + { \ + } \ + else if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_end) = BOOST_FOREACH_REND(COL)) \ + { \ + } \ + else \ + for (bool BOOST_FOREACH_ID(_foreach_continue) = true; \ + BOOST_FOREACH_ID(_foreach_continue) && !BOOST_FOREACH_RDONE(COL); \ + BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_RNEXT(COL) : (void)0) \ + if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue))) \ + { \ + } \ + else \ + for (VAR = QX_FOREACH_DEREF_REVERSE(COL); !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true) + +#ifdef _foreach +#undef _foreach +#endif // _foreach + +#ifdef _foreach_reverse +#undef _foreach_reverse +#endif // _foreach_reverse + +#ifdef _foreach_if +#undef _foreach_if +#endif // _foreach_if + +#ifdef _foreach_reverse_if +#undef _foreach_reverse_if +#endif // _foreach_reverse_if + +#define _foreach QX_FOREACH +#define _foreach_reverse QX_FOREACH_REVERSE + +#define _foreach_if(VAR, COL, COND) _foreach(VAR, COL) if (COND) +#define _foreach_reverse_if(VAR, COL, COND) _foreach_reverse(VAR, COL) if (COND) + +#endif // _QX_FOREACH_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxCommon/QxAny.h b/include/QxCommon/QxAny.h new file mode 100644 index 0000000..048b9f0 --- /dev/null +++ b/include/QxCommon/QxAny.h @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** 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_ANY_H_ +#define _QX_ANY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxAny.h + * \author XDL Team + * \ingroup QxCommon + * \brief qx::any : basic implementation of boost::any (written by Kevlin Henney) when boost dependency is not available + */ + +#ifndef _QX_NO_RTTI +#include +#define QX_TYPE_ID(T) typeid(T) +#else // _QX_NO_RTTI +#include +#include +#define QX_TYPE_ID(T) std::string(qx::trait::get_class_name::get()) +#endif // _QX_NO_RTTI + +#ifndef Q_OS_WIN +#if (__GNUC__ >= 4) +#define QX_ANY_FORCE_HIDDEN_VISIBILITY __attribute__((visibility("hidden"))) // To avoid a GCC warning : 'qx::any::holder' declared with greater visibility than the type of its field 'qx::any::holder::held' [-Wattributes] +#endif // (__GNUC__ >= 4) +#endif // Q_OS_WIN + +#ifndef QX_ANY_FORCE_HIDDEN_VISIBILITY +#define QX_ANY_FORCE_HIDDEN_VISIBILITY /* Nothing */ +#endif // QX_ANY_FORCE_HIDDEN_VISIBILITY + +namespace qx +{ + + class any; + template + ValueType *any_cast(any *); + template + ValueType *unsafe_any_cast(any *); + + class any + { + + template + friend ValueType *qx::any_cast(any *); + template + friend ValueType *qx::unsafe_any_cast(any *); + + public: +#ifndef _QX_NO_RTTI + typedef const std::type_info &type_check; +#else // _QX_NO_RTTI + typedef std::string type_check; +#endif // _QX_NO_RTTI + + any() : content(NULL) { ; } + any(const any &other) : content(other.content ? other.content->clone() : NULL) { ; } + ~any() + { + if (content) + { + delete content; + } + } + + template + any(const ValueType &value) : content(new holder::type>::type>(value)) { ; } + + any &swap(any &other) + { + std::swap(content, other.content); + return (*this); + } + + template + any &operator=(const ValueType &other) + { + any(other).swap(*this); + return (*this); + } + + any &operator=(any other) + { + any(other).swap(*this); + return (*this); + } + bool empty() const { return (!content); } + void clear() { any().swap(*this); } + type_check type() const { return (content ? content->type() : QX_TYPE_ID(void)); } + + private: + struct placeholder + { + virtual ~placeholder() { ; } + virtual type_check type() const = 0; + virtual placeholder *clone() const = 0; + }; + + template + struct QX_ANY_FORCE_HIDDEN_VISIBILITY holder : public placeholder + { + holder(const ValueType &value) : held(value) { ; } + virtual type_check type() const { return QX_TYPE_ID(ValueType); } + virtual placeholder *clone() const { return new holder(held); } + ValueType held; + + private: + holder &operator=(const holder &); + }; + + placeholder *content; + }; + + inline void swap(any &lhs, any &other) { lhs.swap(other); } + + struct bad_any_cast : public std::exception + { + virtual const char *what() const throw() { return "qx::bad_any_cast : failed conversion using qx::any_cast"; } + }; + + template + ValueType *any_cast(any *operand) + { + return ((operand && (operand->type() == QX_TYPE_ID(ValueType))) ? (&static_cast::type> *>(operand->content)->held) : NULL); + } + + template + const ValueType *any_cast(const any *operand) + { + return any_cast(const_cast(operand)); + } + + template + ValueType any_cast(any &operand) + { + typedef typename std::remove_reference::type nonref; + nonref *result = any_cast(&operand); + if (!result) + { + throw qx::bad_any_cast(); + } + return static_cast(*result); + } + + template + ValueType any_cast(const any &operand) + { + typedef typename std::remove_reference::type nonref; + return any_cast(const_cast(operand)); + } + + template + ValueType *unsafe_any_cast(any *operand) + { + return (&static_cast *>(operand->content)->held); + } + + template + const ValueType *unsafe_any_cast(const any *operand) + { + return unsafe_any_cast(const_cast(operand)); + } + +} // namespace qx + +#endif // _QX_ANY_H_ diff --git a/include/QxCommon/QxAnyCastDynamic.h b/include/QxCommon/QxAnyCastDynamic.h new file mode 100644 index 0000000..5015d03 --- /dev/null +++ b/include/QxCommon/QxAnyCastDynamic.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** 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_ANY_CAST_DYNAMIC_H_ +#define _QX_ANY_CAST_DYNAMIC_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxAnyCastDynamic.h + * \author XDL Team + * \ingroup QxCommon + * \brief qx::any_cast_dynamic::get() : provides a tool to use qx::any_cast and polymorphism + */ + +#include + +#include + +#include + +namespace qx +{ + + template + struct any_cast_dynamic + { + static T get(const qx::any &a) { return qx::any_cast(a); } + }; + + template + struct any_cast_dynamic + { + static T *get(const qx::any &a) + { + if (a.empty()) + { + return NULL; + } + qx::any *b = const_cast(&a); + T **t = qx::unsafe_any_cast(b); + if (!t) + { + return NULL; + } + return (*t); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct any_cast_dynamic> + { + static boost::shared_ptr get(const qx::any &a) + { + if (a.empty()) + { + return boost::shared_ptr(); + } + qx::any *b = const_cast(&a); + boost::shared_ptr *t = qx::unsafe_any_cast>(b); + if (!t) + { + return boost::shared_ptr(); + } + return (*t); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct any_cast_dynamic> + { + static QSharedPointer get(const qx::any &a) + { + if (a.empty()) + { + return QSharedPointer(); + } + qx::any *b = const_cast(&a); + QSharedPointer *t = qx::unsafe_any_cast>(b); + if (!t) + { + return QSharedPointer(); + } + return (*t); + } + }; + + template + struct any_cast_dynamic> + { + static qx::dao::ptr get(const qx::any &a) + { + if (a.empty()) + { + return qx::dao::ptr(); + } + qx::any *b = const_cast(&a); + qx::dao::ptr *t = qx::unsafe_any_cast>(b); + if (!t) + { + return qx::dao::ptr(); + } + return (*t); + } + }; + + template + struct any_cast_dynamic> + { + static std::shared_ptr get(const qx::any &a) + { + if (a.empty()) + { + return std::shared_ptr(); + } + qx::any *b = const_cast(&a); + std::shared_ptr *t = qx::unsafe_any_cast>(b); + if (!t) + { + return std::shared_ptr(); + } + return (*t); + } + }; + +} // namespace qx + +#endif // _QX_ANY_CAST_DYNAMIC_H_ diff --git a/include/QxCommon/QxBool.h b/include/QxCommon/QxBool.h new file mode 100644 index 0000000..a9be4e6 --- /dev/null +++ b/include/QxCommon/QxBool.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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_BOOL_H_ +#define _QX_BOOL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxBool.h + * \author XDL Team + * \ingroup QxCommon + * \brief qx_bool : QxOrm library boolean type with code and description message when an error occured + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace qx +{ + class QxBool; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxBool &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxBool &t) QX_USED; + +namespace qx +{ + + /*! + * \ingroup QxCommon + * \brief qx_bool : boolean type with code and description message when an error occured + */ + class QxBool + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxBool &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxBool &t); + + private: + bool m_bValue; //!< Data boolean value + long m_lCode; //!< Error code when value is false + QString m_sDesc; //!< Error description when value is false + + public: + QxBool() : m_bValue(false), m_lCode(0) { ; } + QxBool(bool b) : m_bValue(b), m_lCode(0) { qAssert(checkInitialized(b)); } + QxBool(long lCode, const QString &sDesc) : m_bValue(false), m_lCode(lCode), m_sDesc(sDesc) { ; } + QxBool(bool bValue, long lCode, const QString &sDesc) : m_bValue(bValue), m_lCode(lCode), m_sDesc(sDesc) { qAssert(checkInitialized(bValue)); } + QxBool(const QxBool &other) : m_bValue(other.getValue()), m_lCode(other.getCode()), m_sDesc(other.getDesc()) { ; } + ~QxBool() { ; } + + inline bool getValue() const { return m_bValue; } + inline long getCode() const { return m_lCode; } + inline QString getDesc() const { return m_sDesc; } + + inline void setValue(bool bValue) + { + m_bValue = bValue; + qAssert(checkInitialized(bValue)); + } + inline void setCode(long lCode) { m_lCode = lCode; } + inline void setDesc(const QString &sDesc) { m_sDesc = sDesc; } + + inline QxBool &operator=(const QxBool &other) + { + m_bValue = other.getValue(); + m_lCode = other.getCode(); + m_sDesc = other.getDesc(); + return (*this); + } + inline QxBool &operator=(const bool b) + { + m_bValue = b; + qAssert(checkInitialized(b)); + return (*this); + } + + inline operator bool() const { return (m_bValue != false); } + inline bool operator!() const { return (m_bValue == false); } + + inline bool operator==(const QxBool &other) const { return ((m_bValue == other.getValue()) && (m_lCode == other.getCode()) && (m_sDesc == other.getDesc())); } + inline bool operator==(const bool b) const + { + qAssert(checkInitialized(b)); + return (m_bValue == b); + } + inline bool operator!=(const QxBool &other) const { return ((m_bValue != other.getValue()) || (m_lCode != other.getCode()) || (m_sDesc != other.getDesc())); } + inline bool operator!=(const bool b) const + { + qAssert(checkInitialized(b)); + return (m_bValue != b); + } + inline bool operator&&(const QxBool &other) const { return (m_bValue && other.getValue()); } + inline bool operator&&(const bool b) const + { + qAssert(checkInitialized(b)); + return (m_bValue && b); + } + inline bool operator||(const QxBool &other) const { return (m_bValue || other.getValue()); } + inline bool operator||(const bool b) const + { + qAssert(checkInitialized(b)); + return (m_bValue || b); + } + + QString toString() const { return (QString(m_bValue ? "1" : "0") + "|" + QString::number(static_cast(m_lCode)) + "|" + m_sDesc); } + + void fromString(const QString &s) + { + if (s.trimmed().isEmpty()) + { + (*this) = QxBool(); + return; + } + bool bValue = s.startsWith("1"); + int iPos = s.indexOf("|", 2); + if (iPos == -1) + { + (*this) = QxBool(bValue); + return; + } + long lCode = s.mid(2, (iPos - 2)).toLong(); + QString sDesc = s.right(s.size() - (iPos + 1)); + (*this) = QxBool(bValue, lCode, sDesc); + } + + private: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("value", m_bValue); + ar &boost::serialization::make_nvp("code", m_lCode); + ar &boost::serialization::make_nvp("desc", m_sDesc); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + inline bool checkInitialized(const bool b) const { return ((static_cast(b) == 0) || (static_cast(b) == 1)); } + }; + +} // namespace qx + +typedef qx::QxBool qx_bool; +QX_REGISTER_CLASS_NAME(qx_bool) + +#endif // _QX_BOOL_H_ diff --git a/include/QxCommon/QxCache.h b/include/QxCommon/QxCache.h new file mode 100644 index 0000000..778ed36 --- /dev/null +++ b/include/QxCommon/QxCache.h @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** 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_CACHE_H_ +#define _QX_CACHE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxCache.h + * \author XDL Team + * \ingroup QxCache + * \brief qx::cache : based on singleton pattern, provide basic thread-safe cache feature to backup and restore any kind of objects (for example, object fetched from database) + */ + +#include +#include + +#include + +#include + +namespace qx +{ + namespace cache + { + namespace detail + { + + class QX_DLL_EXPORT QxCache : public qx::QxSingleton + { + + friend class qx::QxSingleton; + + protected: + typedef std::tuple type_qx_cache; + typedef qx::QxCollection type_qx_lst_cache; + + type_qx_lst_cache m_cache; //!< List of objects in cache under qx::any format + QMutex m_oMutexCache; //!< Mutex => 'QxCache' is thread-safe + long m_lMaxCost; //!< Max cost before deleting object in cache + long m_lCurrCost; //!< Current cost in cache + + public: + QxCache(); + virtual ~QxCache(); + + long getCurrCost() const; + long getMaxCost() const; + void setMaxCost(long l); + + long count() const; + long size() const; + bool isEmpty() const; + bool exist(const QString &sKey) const; + bool contains(const QString &sKey) const; + qx::any at(const QString &sKey); + long insertionCost(const QString &sKey); + QDateTime insertionDateTime(const QString &sKey); + void clear(); + + bool insert(const QString &sKey, const qx::any &anyObj, long lCost = 1, const QDateTime &dt = QDateTime()); + bool remove(const QString &sKey); + + private: + void updateCost(); + }; + + } // namespace detail + } // namespace cache +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::cache::detail::QxCache) + +namespace qx +{ + namespace cache + { + + /*! + * \ingroup QxCache + * \brief Set the maximum allowed total cost of the cache to l. If the current total cost is greater than l, some objects are deleted immediately + */ + inline void max_cost(long l) + { + qx::cache::detail::QxCache::getSingleton()->setMaxCost(l); + } + + /*! + * \ingroup QxCache + * \brief Return the maximum allowed total cost of the cache + */ + inline long max_cost() + { + return qx::cache::detail::QxCache::getSingleton()->getMaxCost(); + } + + /*! + * \ingroup QxCache + * \brief Return the current cost used by the cache + */ + inline long current_cost() + { + return qx::cache::detail::QxCache::getSingleton()->getCurrCost(); + } + + /*! + * \ingroup QxCache + * \brief Return the number of objects in the cache + */ + inline long count() + { + return qx::cache::detail::QxCache::getSingleton()->count(); + } + + /*! + * \ingroup QxCache + * \brief Return true if the cache contains no object; otherwise return false + */ + inline bool is_empty() + { + return qx::cache::detail::QxCache::getSingleton()->isEmpty(); + } + + /*! + * \ingroup QxCache + * \brief Delete all the objects in the cache + */ + inline void clear() + { + qx::cache::detail::QxCache::getSingleton()->clear(); + } + + /*! + * \ingroup QxCache + * \brief Return true if the cache contains an object associated with key sKey; otherwise return false + */ + inline bool exist(const QString &sKey) + { + return qx::cache::detail::QxCache::getSingleton()->exist(sKey); + } + + /*! + * \ingroup QxCache + * \brief Delete the object associated with key sKey. Return true if the object was found in the cache; otherwise return false + */ + inline bool remove(const QString &sKey) + { + return qx::cache::detail::QxCache::getSingleton()->remove(sKey); + } + + /*! + * \ingroup QxCache + * \brief Insert object t into the cache with key sKey, associated cost lCost and insertion date-time dt. Any object with the same key already in the cache will be removed + */ + template + inline bool set(const QString &sKey, T &t, long lCost = 1, const QDateTime &dt = QDateTime()) + { + qx::any obj(t); + return qx::cache::detail::QxCache::getSingleton()->insert(sKey, obj, lCost, dt); + } + + /*! + * \ingroup QxCache + * \brief Return the object of type T associated with key sKey, or return default instance of T() if the key does not exist in the cache + */ + template + inline T get(const QString &sKey) + { + qx::any obj = qx::cache::detail::QxCache::getSingleton()->at(sKey); + if (obj.empty()) + { + return T(); + } + try + { + return qx::any_cast(obj); + } + catch (const qx::bad_any_cast &err) + { + Q_UNUSED(err); + return T(); + } + catch (...) + { + return T(); + } + } + + /*! + * \ingroup QxCache + * \brief Return true if object t can be fetched with associated key sKey and insertion date-time dt; otherwise return false with an error description + */ + template + inline qx_bool get(const QString &sKey, T &t, QDateTime &dt) + { + dt = QDateTime(); + if (!qx::cache::exist(sKey)) + { + return qx_bool(false, 0, "[QxOrm] qx::cache : key doesn't exist in cache"); + } + qx::any obj = qx::cache::detail::QxCache::getSingleton()->at(sKey); + dt = qx::cache::detail::QxCache::getSingleton()->insertionDateTime(sKey); + try + { + t = qx::any_cast(obj); + return qx_bool(true); + } + catch (const qx::bad_any_cast &err) + { + Q_UNUSED(err); + return qx_bool(false, 0, "[QxOrm] qx::cache : bad any cast exception"); + } + catch (...) + { + return qx_bool(false, 0, "[QxOrm] qx::cache : unknown cast exception"); + } + } + + /*! + * \ingroup QxCache + * \brief Return true if object t can be fetched with associated key sKey; otherwise return false with an error description + */ + template + inline qx_bool get(const QString &sKey, T &t) + { + QDateTime dt; + return qx::cache::get(sKey, t, dt); + } + + } // namespace cache +} // namespace qx + +#endif // _QX_CACHE_H_ diff --git a/include/QxCommon/QxConfig.h b/include/QxCommon/QxConfig.h new file mode 100644 index 0000000..8484a1b --- /dev/null +++ b/include/QxCommon/QxConfig.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** 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_CONFIG_H_ +#define _QX_CONFIG_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxConfig.h + * \author XDL Team + * \ingroup QxCommon + * \brief List of parameters to compile and build QxOrm library + */ + +#define QX_VERSION 0x010500 +#define QX_VERSION_STR "1.5.0" + +#ifndef _QX_MODE_DEBUG +#ifndef _QX_MODE_RELEASE +#ifdef QT_NO_DEBUG +#define _QX_MODE_RELEASE +#else // QT_NO_DEBUG +#define _QX_MODE_DEBUG +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE +#endif // _QX_MODE_DEBUG + +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_XML +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#ifndef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#define _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#define _QX_ENABLE_BOOST_SERIALIZATION_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION_BINARY + +#ifndef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#undef _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_XML +#undef _QX_ENABLE_BOOST_SERIALIZATION_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#undef _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#endif // _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#undef _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#undef _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#undef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#undef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#undef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#define _QX_SERIALIZE_POLYMORPHIC 1 +#else // _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC +#define _QX_SERIALIZE_POLYMORPHIC 0 +#endif // _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#define _QX_SERIALIZE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_BINARY +#define _QX_SERIALIZE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#define _QX_SERIALIZE_TEXT (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_TEXT +#define _QX_SERIALIZE_TEXT (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_TEXT + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_XML +#define _QX_SERIALIZE_XML (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_XML +#define _QX_SERIALIZE_XML (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#define _QX_SERIALIZE_PORTABLE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY +#define _QX_SERIALIZE_PORTABLE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#define _QX_SERIALIZE_WIDE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY +#define _QX_SERIALIZE_WIDE_BINARY (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#define _QX_SERIALIZE_WIDE_TEXT (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT +#define _QX_SERIALIZE_WIDE_TEXT (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#define _QX_SERIALIZE_WIDE_XML (!_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML +#define _QX_SERIALIZE_WIDE_XML (!_QX_SERIALIZE_POLYMORPHIC && 0) +#endif // _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML + +#define _QX_AUTO_REGISTER_REPOSITORY 0 +#define _QX_USE_MEM_LEAK_DETECTION 0 +#define _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON 1 +#define _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER 0 +#define _QX_USE_MODIFY_BOOST_SERIALIZATION_EXPORT_HPP 0 +#define _QX_WRITE_BOOST_CLASS_EXPORT_IN_HPP_FILE 0 +#define _QX_WRITE_BOOST_CLASS_EXPORT_IN_CPP_FILE 1 +#define _QX_INCLUDE_BOOST_SERIALIZE_EXPORT_HPP_INTO_QX_MEM_LEAK_HPP 1 +#define _QX_INCLUDE_BOOST_SERIALIZE_ARCHIVE_IMPL_IPP 0 +#define _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE 1 +#define _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 0 +#define _QX_USE_QX_CONVERT_EXPORT 0 +#define _QX_USE_GCC_EXPORT_ALL_SYMBOLS 0 +#define _QX_USE_GCC_VISIBILITY 0 +#define _QX_USE_ASSERT 1 +#define _QX_SUPPORT_COVARIANT_RETURN_TYPE 1 +#define _QX_USE_QX_SINGLETON_X 1 + +#ifdef _MSC_VER +/* -- Link error with VC++ 9.0 => Qt uses "-Zc:wchar_t-" option to compile and boost serialization library is compiled without this option -- */ +#define _QX_USE_SERIALIZE_POLYMORPHIC_PATCH (_QX_SERIALIZE_POLYMORPHIC && 1) +#else // _MSC_VER +#define _QX_USE_SERIALIZE_POLYMORPHIC_PATCH 0 +#endif // _MSC_VER + +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) +#ifndef _QX_NO_JSON +#define _QX_NO_JSON +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + +#endif // _QX_CONFIG_H_ diff --git a/include/QxCommon/QxException.h b/include/QxCommon/QxException.h new file mode 100644 index 0000000..e7b257b --- /dev/null +++ b/include/QxCommon/QxException.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_EXCEPTION_H_ +#define _QX_EXCEPTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxException.h + * \author XDL Team + * \ingroup QxCommon + * \brief Exception with error code and error description + */ + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxCommon + * \brief qx::exception : exception with error code and error description + */ + class exception : public std::exception + { + + private: + long m_code; //!< Error code + QString m_desc; //!< Error description + QString m_what; //!< Formatted error : code + "^" + description + + public: + exception(const QString &desc) : std::exception(), m_code(0), m_desc(desc) { updateWhat(); } + exception(long code, const QString &desc) : std::exception(), m_code(code), m_desc(desc) { updateWhat(); } + virtual ~exception() throw() { ; } + + virtual const char *what() const throw() { return qPrintable(m_what); } + + long getCode() const { return m_code; } + QString getDescription() const { return m_desc; } + qx_bool toQxBool() const { return qx_bool(m_code, m_desc); } + + private: + void updateWhat() { m_what = (QString::number(m_code) + QString("^") + m_desc); } + }; + +} // namespace qx + +#endif // _QX_EXCEPTION_H_ diff --git a/include/QxCommon/QxExceptionCode.h b/include/QxCommon/QxExceptionCode.h new file mode 100644 index 0000000..091a7e3 --- /dev/null +++ b/include/QxCommon/QxExceptionCode.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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_EXCEPTION_CODE_H_ +#define _QX_EXCEPTION_CODE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxExceptionCode.h + * \author XDL Team + * \ingroup QxCommon + * \brief Some errors codes defined by QxOrm library + */ + +#include + +#define QX_ERROR_UNKNOWN 1 +#define QX_ERROR_SERVICE_NOT_SPECIFIED 2 +#define QX_ERROR_SERVICE_INVALID 3 +#define QX_ERROR_SERVER_NOT_FOUND 4 +#define QX_ERROR_SERVICE_WRITE_ERROR 5 +#define QX_ERROR_SERVICE_READ_ERROR 6 +#define QX_ERROR_SERVICE_SSL_ENCRYPTED 7 + +#define QX_EXCEPTION_UNKNOWN qx::exception(QX_ERROR_UNKNOWN, "unknown error") +#define QX_EXCEPTION_SERVICE_NOT_SPECIFIED qx::exception(QX_ERROR_SERVICE_NOT_SPECIFIED, "[QxOrm] empty service name") +#define QX_EXCEPTION_SERVICE_INVALID qx::exception(QX_ERROR_SERVICE_INVALID, "[QxOrm] invalid service") +#define QX_EXCEPTION_SERVER_NOT_FOUND qx::exception(QX_ERROR_SERVER_NOT_FOUND, "[QxOrm] unable to connect to server") +#define QX_EXCEPTION_SERVICE_WRITE_ERROR qx::exception(QX_ERROR_SERVICE_WRITE_ERROR, "[QxOrm] unable to write request to socket") +#define QX_EXCEPTION_SERVICE_READ_ERROR qx::exception(QX_ERROR_SERVICE_READ_ERROR, "[QxOrm] unable to read reply from socket") +#define QX_EXCEPTION_SERVICE_SSL_ENCRYPTED qx::exception(QX_ERROR_SERVICE_SSL_ENCRYPTED, "[QxOrm] SSL socket encrypted error") + +#endif // _QX_EXCEPTION_CODE_H_ diff --git a/include/QxCommon/QxHashValue.h b/include/QxCommon/QxHashValue.h new file mode 100644 index 0000000..df86314 --- /dev/null +++ b/include/QxCommon/QxHashValue.h @@ -0,0 +1,493 @@ +/**************************************************************************** +** +** 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_HASH_VALUE_H_ +#define _QX_HASH_VALUE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHashValue.h + * \author XDL Team + * \ingroup QxCommon + * \brief Specialize hash_value function for some Qt and boost types (used for example by qx::QxCollection container) + */ + +#include +#include +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#define qx_hash_result uint +#else // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#define qx_hash_result std::size_t +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +inline std::size_t hash_value(const QString &s) { return qHash(s); } +inline std::size_t hash_value(const QVariant &v) { return qHash(v.toString()); } +inline std::size_t hash_value(const QDate &d) { return qHash(d.toJulianDay()); } +inline std::size_t hash_value(const QTime &t) { return qHash(t.toString()); } +inline std::size_t hash_value(const QDateTime &dt) { return qHash(dt.toString()); } + +inline qx_hash_result qHash(const QVariant &v) { return static_cast(hash_value(v)); } + +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) +inline qx_hash_result qHash(const QDate &d) { return static_cast(hash_value(d)); } +inline qx_hash_result qHash(const QTime &t) { return static_cast(hash_value(t)); } +inline qx_hash_result qHash(const QDateTime &dt) { return static_cast(hash_value(dt)); } +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + +namespace qx +{ + template + inline void hash_combine(std::size_t &seed, const T &t) + { + seed ^= qHash(t) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } +} // namespace qx + +template +inline std::size_t hash_value(const QPair &p) +{ + std::size_t seed = 0; + qx::hash_combine(seed, p.first); + qx::hash_combine(seed, p.second); + return seed; +} + +#ifdef _QX_ENABLE_BOOST + +namespace boost +{ + namespace tuples + { + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + qx::hash_combine(seed, boost::get<5>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + qx::hash_combine(seed, boost::get<5>(tu)); + qx::hash_combine(seed, boost::get<6>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + qx::hash_combine(seed, boost::get<5>(tu)); + qx::hash_combine(seed, boost::get<6>(tu)); + qx::hash_combine(seed, boost::get<7>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + qx::hash_combine(seed, boost::get<5>(tu)); + qx::hash_combine(seed, boost::get<6>(tu)); + qx::hash_combine(seed, boost::get<7>(tu)); + qx::hash_combine(seed, boost::get<8>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const boost::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, boost::get<0>(tu)); + qx::hash_combine(seed, boost::get<1>(tu)); + qx::hash_combine(seed, boost::get<2>(tu)); + qx::hash_combine(seed, boost::get<3>(tu)); + qx::hash_combine(seed, boost::get<4>(tu)); + qx::hash_combine(seed, boost::get<5>(tu)); + qx::hash_combine(seed, boost::get<6>(tu)); + qx::hash_combine(seed, boost::get<7>(tu)); + qx::hash_combine(seed, boost::get<8>(tu)); + qx::hash_combine(seed, boost::get<9>(tu)); + return seed; + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const boost::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + } // namespace tuples +} // namespace boost + +#endif // _QX_ENABLE_BOOST + +// Compilation option '_QX_HASH_NO_STD_NAMESPACE' +// Try to avoid compilation error, something like : error: no matching function for call to 'qHash(const std::tuple<...>&)' +// This is due to C++ ADL to resolve specialized functions : qHash(T) should be implemented in the same namespace as T +// For 'std' classes, it should be NOT allowed : the behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std +// More details here : https://www.kdab.com/how-to-declare-a-qhash-overload/ +// And here : https://stackoverflow.com/questions/47460098/using-standard-library-types-as-keys-in-qhash-or-qset +#ifndef _QX_HASH_NO_STD_NAMESPACE +namespace std +{ +#endif // _QX_HASH_NO_STD_NAMESPACE + +#ifndef QT_NO_STL + inline qx_hash_result qHash(const std::string &s) + { + QString tmp = QString::fromStdString(s); + return qHash(tmp); + } + inline qx_hash_result qHash(const std::wstring &s) + { + QString tmp = QString::fromStdWString(s); + return qHash(tmp); + } +#else // QT_NO_STL +inline qx_hash_result qHash(const std::string &s) +{ + QString tmp = QString::fromLatin1(s.data(), int(s.size())); + return qHash(tmp); +} +inline qx_hash_result qHash(const std::wstring &s) +{ + qAssert(false); /* Need STL compatibility ! */ + return 0; +} +#endif // QT_NO_STL + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + qx::hash_combine(seed, std::get<5>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + qx::hash_combine(seed, std::get<5>(tu)); + qx::hash_combine(seed, std::get<6>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + qx::hash_combine(seed, std::get<5>(tu)); + qx::hash_combine(seed, std::get<6>(tu)); + qx::hash_combine(seed, std::get<7>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + qx::hash_combine(seed, std::get<5>(tu)); + qx::hash_combine(seed, std::get<6>(tu)); + qx::hash_combine(seed, std::get<7>(tu)); + qx::hash_combine(seed, std::get<8>(tu)); + return seed; + } + + template + inline std::size_t hash_value(const std::tuple &tu) + { + std::size_t seed = 0; + qx::hash_combine(seed, std::get<0>(tu)); + qx::hash_combine(seed, std::get<1>(tu)); + qx::hash_combine(seed, std::get<2>(tu)); + qx::hash_combine(seed, std::get<3>(tu)); + qx::hash_combine(seed, std::get<4>(tu)); + qx::hash_combine(seed, std::get<5>(tu)); + qx::hash_combine(seed, std::get<6>(tu)); + qx::hash_combine(seed, std::get<7>(tu)); + qx::hash_combine(seed, std::get<8>(tu)); + qx::hash_combine(seed, std::get<9>(tu)); + return seed; + } + +#if ((QT_VERSION < QT_VERSION_CHECK(5, 7, 0)) || ((QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(6, 2, 0)))) + template + inline qx_hash_result qHash(const std::pair &p) + { + std::size_t seed = 0; + qx::hash_combine(seed, p.first); + qx::hash_combine(seed, p.second); + return static_cast(seed); + } +#endif // ((QT_VERSION < QT_VERSION_CHECK(5, 7, 0)) || ((QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(6, 2, 0)))) + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + + template + inline qx_hash_result qHash(const std::tuple &tu) + { + return static_cast(hash_value(tu)); + } + +#ifndef _QX_HASH_NO_STD_NAMESPACE +} // namespace std +#endif // _QX_HASH_NO_STD_NAMESPACE + +#endif // _QX_HASH_VALUE_H_ diff --git a/include/QxCommon/QxMacro.h b/include/QxCommon/QxMacro.h new file mode 100644 index 0000000..90878ef --- /dev/null +++ b/include/QxCommon/QxMacro.h @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** 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_MACRO_H_ +#define _QX_MACRO_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxMacro.h + * \author XDL Team + * \ingroup QxCommon + * \brief List of common macros used by QxOrm library + */ + +#include + +#ifndef qAssert +#if _QX_USE_ASSERT +#define qAssert Q_ASSERT +#else // _QX_USE_ASSERT +#define qAssert(x) /* Nothing */ +#endif // _QX_USE_ASSERT +#endif // qAssert + +#ifndef qAssertMsg +#if _QX_USE_ASSERT +#define qAssertMsg(test, where, what) Q_ASSERT_X(test, where, what) +#else // _QX_USE_ASSERT +#define qAssertMsg(test, where, what) /* Nothing */ +#endif // _QX_USE_ASSERT +#endif // qAssertMsg + +#ifndef QX_PRAGMA +#ifdef __GNUC__ +#define QX_PRAGMA(x) _Pragma(#x) +#endif // __GNUC__ +#ifdef _MSC_VER +#define QX_PRAGMA(x) __pragma(x) +#endif // _MSC_VER +#ifndef QX_PRAGMA +#define QX_PRAGMA(x) /* Nothing */ +#endif // QX_PRAGMA +#endif // QX_PRAGMA + +#ifndef QX_DLL_EXPORT_HELPER +#ifdef Q_OS_WIN +#define QX_DLL_EXPORT_HELPER __declspec(dllexport) +#elif (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#define QX_DLL_EXPORT_HELPER __attribute__((visibility("default"))) +#else +#define QX_DLL_EXPORT_HELPER /* Nothing */ +#endif // Q_OS_WIN +#endif // QX_DLL_EXPORT_HELPER + +#ifndef QX_DLL_IMPORT_HELPER +#ifdef Q_OS_WIN +#define QX_DLL_IMPORT_HELPER __declspec(dllimport) +#elif (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#define QX_DLL_IMPORT_HELPER __attribute__((visibility("default"))) +#else +#define QX_DLL_IMPORT_HELPER /* Nothing */ +#endif // Q_OS_WIN +#endif // QX_DLL_IMPORT_HELPER + +#ifdef __GNUC__ +#if _QX_USE_GCC_EXPORT_ALL_SYMBOLS +#undef QX_DLL_EXPORT_HELPER +#undef QX_DLL_IMPORT_HELPER +#define QX_DLL_EXPORT_HELPER /* Nothing */ +#define QX_DLL_IMPORT_HELPER /* Nothing */ +#endif // _QX_USE_GCC_EXPORT_ALL_SYMBOLS +#endif // __GNUC__ + +#ifdef _QX_STATIC_BUILD +#undef QX_DLL_EXPORT_HELPER +#undef QX_DLL_IMPORT_HELPER +#define QX_DLL_EXPORT_HELPER /* Nothing */ +#define QX_DLL_IMPORT_HELPER /* Nothing */ +#endif // _QX_STATIC_BUILD + +#ifndef QX_DLL_INTERNAL_HELPER +#if (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#define QX_DLL_INTERNAL_HELPER __attribute__((visibility("hidden"))) +#else +#define QX_DLL_INTERNAL_HELPER /* Nothing */ +#endif // (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#endif // QX_DLL_INTERNAL_HELPER + +#ifndef QX_DLL_EXPORT_TEMPLATE_HELPER +#ifdef _MSC_VER +#define QX_DLL_EXPORT_TEMPLATE_HELPER QX_DLL_EXPORT_HELPER +#else // _MSC_VER +#define QX_DLL_EXPORT_TEMPLATE_HELPER /* Nothing */ +#endif // _MSC_VER +#endif // QX_DLL_EXPORT_TEMPLATE_HELPER + +#ifndef QX_DLL_IMPORT_TEMPLATE_HELPER +#ifdef _MSC_VER +#define QX_DLL_IMPORT_TEMPLATE_HELPER QX_DLL_IMPORT_HELPER +#else // _MSC_VER +#define QX_DLL_IMPORT_TEMPLATE_HELPER /* Nothing */ +#endif // _MSC_VER +#endif // QX_DLL_IMPORT_TEMPLATE_HELPER + +#ifndef QX_PRAGMA_VISIBILITY_BEGIN +#ifndef Q_OS_WIN +#if (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#define QX_PRAGMA_VISIBILITY_BEGIN QX_PRAGMA(GCC visibility push(default)) +#endif // (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#endif // Q_OS_WIN +#ifndef QX_PRAGMA_VISIBILITY_BEGIN +#define QX_PRAGMA_VISIBILITY_BEGIN /* Nothing */ +#endif // QX_PRAGMA_VISIBILITY_BEGIN +#endif // QX_PRAGMA_VISIBILITY_BEGIN + +#ifndef QX_PRAGMA_VISIBILITY_END +#ifndef Q_OS_WIN +#if (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#define QX_PRAGMA_VISIBILITY_END QX_PRAGMA(GCC visibility pop) +#endif // (_QX_USE_GCC_VISIBILITY && (__GNUC__ >= 4)) +#endif // Q_OS_WIN +#ifndef QX_PRAGMA_VISIBILITY_END +#define QX_PRAGMA_VISIBILITY_END /* Nothing */ +#endif // QX_PRAGMA_VISIBILITY_END +#endif // QX_PRAGMA_VISIBILITY_END + +#define QX_DLL_EXPORT_TEMPLATE_HPP(CL, T) \ + QX_PRAGMA_VISIBILITY_BEGIN extern template CL QX_DLL_IMPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(CL, T, P1) \ + QX_PRAGMA_VISIBILITY_BEGIN extern template CL QX_DLL_IMPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(CL, T, U, P1) \ + QX_PRAGMA_VISIBILITY_BEGIN extern template CL QX_DLL_IMPORT_TEMPLATE_HELPER T>; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(CL, T, P1, P2) \ + QX_PRAGMA_VISIBILITY_BEGIN extern template CL QX_DLL_IMPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(CL, T, U, P1, P2) \ + QX_PRAGMA_VISIBILITY_BEGIN extern template CL QX_DLL_IMPORT_TEMPLATE_HELPER T>; \ + QX_PRAGMA_VISIBILITY_END + +#define QX_DLL_EXPORT_TEMPLATE_CPP(CL, T) \ + QX_PRAGMA_VISIBILITY_BEGIN template CL QX_DLL_EXPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(CL, T, P1) \ + QX_PRAGMA_VISIBILITY_BEGIN template CL QX_DLL_EXPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(CL, T, U, P1) \ + QX_PRAGMA_VISIBILITY_BEGIN template CL QX_DLL_EXPORT_TEMPLATE_HELPER T>; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(CL, T, P1, P2) \ + QX_PRAGMA_VISIBILITY_BEGIN template CL QX_DLL_EXPORT_TEMPLATE_HELPER T; \ + QX_PRAGMA_VISIBILITY_END +#define QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(CL, T, U, P1, P2) \ + QX_PRAGMA_VISIBILITY_BEGIN template CL QX_DLL_EXPORT_TEMPLATE_HELPER T>; \ + QX_PRAGMA_VISIBILITY_END + +#define QX_TEMPLATE_T(T) T<> +#define QX_TEMPLATE_T_P1(T, P1) T +#define QX_TEMPLATE_T_P1_P2(T, P1, P2) T +#define QX_TEMPLATE_T_P1_P2_P3(T, P1, P2, P3) T +#define QX_TEMPLATE_T_U_P1(T, U, P1) T> +#define QX_TEMPLATE_T_U_P1_P2(T, U, P1, P2) T> +#define QX_TEMPLATE_T_U_P1_P2_P3(T, U, P1, P2, P3) T> + +#ifndef QX_DLL_EXPORT +#ifdef _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _QX_BUILDING_QX_ORM +#endif // QX_DLL_EXPORT + +#ifndef QX_DLL_EXPORT_QX_SINGLETON_HPP +#ifdef _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT_QX_SINGLETON_HPP(x) /* Nothing */ +#else // _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT_QX_SINGLETON_HPP(x) QX_DLL_EXPORT_TEMPLATE_HPP(class, qx::QxSingleton) +#endif // _QX_BUILDING_QX_ORM +#endif // QX_DLL_EXPORT_QX_SINGLETON_HPP + +#ifndef QX_DLL_EXPORT_QX_SINGLETON_CPP +#ifdef _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT_QX_SINGLETON_CPP(x) QX_DLL_EXPORT_TEMPLATE_CPP(class, qx::QxSingleton) +#else // _QX_BUILDING_QX_ORM +#define QX_DLL_EXPORT_QX_SINGLETON_CPP(x) /* Nothing */ +#endif // _QX_BUILDING_QX_ORM +#endif // QX_DLL_EXPORT_QX_SINGLETON_CPP + +#ifndef QX_DLL_EXPORT_INLINE_FCT +#ifdef _MSC_VER +#define QX_DLL_EXPORT_INLINE_FCT QX_DLL_EXPORT +#else // _MSC_VER +#define QX_DLL_EXPORT_INLINE_FCT /* Nothing */ +#endif // _MSC_VER +#endif // QX_DLL_EXPORT_INLINE_FCT + +#ifdef __GNUC__ +#define QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE inline +#elif (defined(_MSC_VER) && (_MSC_VER >= 1920)) // MSVC 2019 +#define QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE inline +#else +#define QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE /* Nothing */ +#endif // __GNUC__ + +#ifdef _MSC_VER +#define QX_STRNCPY strncpy_s +#define QX_VSPRINTF vsprintf_s +#else // _MSC_VER +#define QX_STRNCPY strncpy +#define QX_VSPRINTF vsprintf +#endif // _MSC_VER + +#ifdef _QX_MODE_RELEASE +#ifndef NDEBUG +#define NDEBUG +#endif // NDEBUG +#endif // _QX_MODE_RELEASE + +// From file (written by Robert Ramey) +#if !defined(_WIN32) && !defined(_WIN64) +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define QX_USED __attribute__((__used__)) +#elif defined(__IBMCPP__) && (__IBMCPP__ >= 1110) +#define QX_USED __attribute__((__used__)) +#elif defined(__INTEL_COMPILER) +#define QX_USED __attribute__((__used__)) +#endif +#endif // ! defined(_WIN32) && ! defined(_WIN64) + +#ifndef QX_USED +#define QX_USED /* Nothing */ +#endif // QX_USED + +#ifdef QT_NO_OPENSSL +#ifndef QT_NO_SSL +#define QT_NO_SSL /* Nothing */ +#endif // QT_NO_SSL +#endif // QT_NO_OPENSSL + +#ifndef Q_DECL_OVERRIDE +#define Q_DECL_OVERRIDE /* Nothing */ +#endif // Q_DECL_OVERRIDE + +#ifndef Q_DECL_FINAL +#define Q_DECL_FINAL /* Nothing */ +#endif // Q_DECL_FINAL + +#ifndef Q_DECL_HIDDEN +#define Q_DECL_HIDDEN /* Nothing */ +#endif // Q_DECL_HIDDEN + +#ifndef Q_DECL_NOEXCEPT +#define Q_DECL_NOEXCEPT /* Nothing */ +#endif // Q_DECL_NOEXCEPT + +#ifndef Q_NULLPTR +#define Q_NULLPTR NULL +#endif // Q_NULLPTR + +// From 'QtCore' directory, 'qtversionchecks.h' file +#ifndef QT_VERSION_CHECK +#define QT_VERSION_CHECK(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) +#endif // QT_VERSION_CHECK + +#endif // _QX_MACRO_H_ diff --git a/include/QxCommon/QxMainPage.h b/include/QxCommon/QxMainPage.h new file mode 100644 index 0000000..da3e06b --- /dev/null +++ b/include/QxCommon/QxMainPage.h @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +/* -- Main page for Doxygen documentation -- */ + +/*! + * \mainpage QxOrm - C++ Object Relational Mapping library + * + * QxOrm is a C++ library designed to provide Object Relational Mapping (ORM) feature to C++/Qt developers (like Hibernate in Java, or NHibernate in .Net).
+ * QxOrm engine is based on a simple and non intrusive mapping function per class to provide : + * + * - Persistence (based on QtSql Qt module) ; + * - Serialization (JSON, XML and binary, based on Qt and boost serialization engines) ; + * - Reflection or Introspection (invoke dynamically class methods and access to properties) ; + * - HTTP web server : standalone multi-threaded HTTP 1.1 web server (support SSL/TLS, persistent connections, cookies, sessions, chunked responses, URL dispatcher/routing) ; + * - JSON API : interoperability with other technology than C++/Qt (REST web services, QML applications, scripting language). + * + * QxOrm is developed by XDL Team, a software development engineer since 2003.
+ * QxOrm library has been accepted into the Qt Ambassador Program.
+ * QxOrm library is available on GitHub. + * + * For more information about QxOrm library (quick sample, tutorial and forum), please visit : https://www.qxorm.com/.
+ * A manual (user guide) to learn how to work with QxOrm library is available on QxOrm website. + *

+ * + * \section quick_sample Quick sample using QxOrm library + * + * 1- drug.h file : drug class definition with 3 properties : id, name and description + * \code +#ifndef _CLASS_DRUG_H_ +#define _CLASS_DRUG_H_ + +class drug +{ +public: + long id; + QString name; + QString description; + + drug() : id(0) { ; } + virtual ~drug() { ; } +}; + +QX_REGISTER_HPP_MY_TEST_EXE(drug, qx::trait::no_base_class_defined, 1) + +// This macro is necessary to register 'drug' class in QxOrm context +// param 1 : the current class to register => 'drug' +// param 2 : the base class, if no base class, use the qx trait => 'qx::trait::no_base_class_defined' +// param 3 : the class version used by serialization to provide 'ascendant compatibility' + +#endif // _CLASS_DRUG_H_ + * \endcode + * + *
+ * 2- drug.cpp file : setting function implementation - void qx::register_class() + * \code +#include "precompiled.h" // Precompiled-header with '#include ' and '#include "export.h"' +#include "drug.h" // Class definition 'drug' +#include // Automatic memory leak detection and boost serialization export macro + +QX_REGISTER_CPP_MY_TEST_EXE(drug) // This macro is necessary to register 'drug' class in QxOrm context + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& drug::id, "id"); // Register 'drug::id' <=> primary key in your database + t.data(& drug::name, "name", 1); // Register 'drug::name' property with key 'name' and version '1' + t.data(& drug::description, "desc"); // Register 'drug::description' property with key 'desc' +}} + * \endcode + * + *
+ * 3- main.cpp file : basic functionalities of QxOrm library with drug class + * \code +#include "precompiled.h" +#include "drug.h" +#include + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); // Qt application + + // Create 3 new drugs + // It is possible to use 'boost' and 'Qt' smart pointer : 'boost::shared_ptr', 'QSharedPointer', etc... + typedef std::shared_ptr drug_ptr; + drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1"; + drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2"; + drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3"; + + // Insert drugs into container + // It is possible to use a lot of containers from 'std', 'boost', 'Qt' and 'qx::QxCollection' + typedef std::vector type_lst_drug; + type_lst_drug lst_drug; + lst_drug.push_back(d1); + lst_drug.push_back(d2); + lst_drug.push_back(d3); + + // Init parameters to communicate with a database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + + // Create table 'drug' into database to store drugs + QSqlError daoError = qx::dao::create_table(); + + // Insert drugs from container to database + // 'id' property of 'd1', 'd2' and 'd3' are auto-updated + daoError = qx::dao::insert(lst_drug); + + // Modify and update the second drug into database + d2->name = "name2 modified"; + d2->description = "desc2 modified"; + daoError = qx::dao::update(d2); + + // Delete the first drug from database + daoError = qx::dao::delete_by_id(d1); + + // Count drugs into database + long lDrugCount = qx::dao::count(); + + // Fetch drug with id '3' into a new variable + drug_ptr d_tmp; d_tmp.reset(new drug()); + d_tmp->id = 3; + daoError = qx::dao::fetch_by_id(d_tmp); + + // Export drugs from container to a file under XML format (serialization) + qx::serialization::xml::to_file(lst_drug, "./export_drugs.xml"); + + // Import drugs from XML file into a new container + type_lst_drug lst_drug_tmp; + qx::serialization::xml::from_file(lst_drug_tmp, "./export_drugs.xml"); + + // Clone a drug + drug_ptr d_clone = qx::clone(* d1); + + // Create a new drug by class name (factory) + qx::any d_any = qx::create("drug"); + + // Insert drugs container into 'qx::cache' + qx::cache::set("drugs", lst_drug); + + // Remove all elements from 'qx::cache' + qx::cache::clear(); + + // Create a dummy memory leak + drug * pDummy = new drug(); + + return 0; +} + * \endcode + * + *
+ * 4- execute program and trace output debug + * \code +[QxOrm] qx::QxSqlDatabase : create new database connection in thread '3616' with key '{d315250c-b5c9-46e0-9402-f800368a6673}' +[QxOrm] sql query (78 ms) : CREATE TABLE drug (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, desc TEXT) +[QxOrm] sql query (63 ms) : INSERT INTO drug (name, desc) VALUES (:name, :desc) +[QxOrm] sql query (62 ms) : UPDATE drug SET id = :id, name = :name, desc = :desc WHERE id = :id_bis +[QxOrm] sql query (63 ms) : DELETE FROM drug WHERE id = :id +[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM drug +[QxOrm] sql query (0 ms) : SELECT drug.id AS drug_id_0, drug.name AS drug_name_0, drug.desc AS drug_desc_0 FROM drug WHERE drug_id_0 = :id +[QxOrm] Leaked object at 0xf52ad8 (size 16, src\main.cpp:74) +[QxOrm] **** 1 memory leaks found **** + * \endcode + * + *
+ * 5- export_drugs.xml file created by the program + * \code + + 3 + 1 + + + 1 + name1 + desc1 + + + + + 2 + name2 modified + desc2 modified + + + + + 3 + name3 + desc3 + + + + * \endcode + */ + +/*! + * \brief Root namespace for all QxOrm library features + */ +namespace qx +{ + + /*! + * \ingroup QxCache + * \brief Provide basic thread-safe cache feature to backup and restore any kind of objects (for example, object fetched from database) + */ + namespace cache + { + + /*! + * \ingroup QxCache + * \brief Internal helper tools for qx::cache namespace + */ + namespace detail + { + } // namespace detail + + } // namespace cache + + /*! + * \ingroup QxDao + * \brief Database communication used by persistence engine (ORM - Object Relational Mapping) + */ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief Internal helper tools for qx::dao namespace + */ + namespace detail + { + } // namespace detail + + } // namespace dao + + /*! + * \ingroup QxFunction + * \brief Register function into QxOrm context used by introspection engine + */ + namespace function + { + + /*! + * \ingroup QxFunction + * \brief Internal helper tools for qx::function namespace + */ + namespace detail + { + } // namespace detail + + } // namespace function + + /*! + * \ingroup QxMemLeak + * \brief QxOrm library memory leak detection (by Wu Yongwei) + */ + namespace memory + { + } // namespace memory + + /*! + * \ingroup QxSerialize + * \brief QxOrm library serialization engine based on boost::serialization library + */ + namespace serialization + { + + /*! + * \ingroup QxSerialize + * \brief Internal helper tools for qx::serialization namespace + */ + namespace detail + { + } // namespace detail + + /*! + * \ingroup QxSerialize + * \brief QxOrm library serialization engine for wide archive + */ + namespace wide + { + } // namespace wide + + } // namespace serialization + + /*! + * \ingroup QxService + * \brief QxOrm library services engine to provide easy and powerful way to create C++ application server (to transfer data over network) + */ + namespace service + { + } // namespace service + + /*! + * \ingroup QxTraits + * \brief QxOrm library traits (template metaprogramming) not available in boost::type_traits library + */ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief Internal helper tools for qx::trait namespace + */ + namespace detail + { + } // namespace detail + + } // namespace trait + + /*! + * \ingroup QxCollection + * \brief Foreach-style (based on BOOST_FOREACH macro) to iterate over all stl, boost and Qt containers + qx::QxCollection QxOrm library container + */ + namespace foreach + { + } // namespace foreach + + /*! + * \ingroup QxCommon + * \brief Provide global functions to convert any kind of objects to/from QString and QVariant format + */ + namespace cvt + { + + /*! + * \ingroup QxCommon + * \brief Internal helper tools for qx::cvt namespace + */ + namespace detail + { + } // namespace detail + + } // namespace cvt + +} // namespace qx diff --git a/include/QxCommon/QxPropertyBag.h b/include/QxCommon/QxPropertyBag.h new file mode 100644 index 0000000..44dafc5 --- /dev/null +++ b/include/QxCommon/QxPropertyBag.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_PROPERTY_BAG_H_ +#define _QX_PROPERTY_BAG_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxPropertyBag.h + * \author XDL Team + * \ingroup QxCommon + * \brief Used by introspection engine (IxClass, IxDataMember, IxFunction, etc.) to add meta-data (property bag) + */ + +#include +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxCommon + * \brief qx::QxPropertyBag : used by introspection engine (IxClass, IxDataMember, IxFunction, etc.) to add meta-data (property bag) + */ + class QxPropertyBag + { + + protected: + typedef QHash type_hash_prop_bag; + typedef std::shared_ptr type_hash_prop_bag_ptr; + + type_hash_prop_bag_ptr m_lstPropertyBag; //!< List of all properties in the bag (meta-data) + + public: + QxPropertyBag() { ; } + virtual ~QxPropertyBag() { ; } + + void setPropertyBag(const QString &key, const QVariant &value) + { + initPropertyBag(); + m_lstPropertyBag->insert(key, value); + } + QVariant getPropertyBag(const QString &key) const { return ((m_lstPropertyBag && m_lstPropertyBag->contains(key)) ? m_lstPropertyBag->value(key) : QVariant()); } + void removePropertyBag(const QString &key) + { + if (m_lstPropertyBag) + { + m_lstPropertyBag->remove(key); + } + } + void clearPropertyBag() + { + if (m_lstPropertyBag) + { + m_lstPropertyBag->clear(); + } + } + long countPropertyBag() const { return (m_lstPropertyBag ? m_lstPropertyBag->count() : 0); } + QList getAllPropertyBagKeys() const { return (m_lstPropertyBag ? m_lstPropertyBag->keys() : QList()); } + + private: + inline void initPropertyBag() + { + if (!m_lstPropertyBag) + { + m_lstPropertyBag = std::make_shared(); + } + } + }; + +} // namespace qx + +#endif // _QX_PROPERTY_BAG_H_ diff --git a/include/QxCommon/QxSimpleCrypt.h b/include/QxCommon/QxSimpleCrypt.h new file mode 100644 index 0000000..f4fc42b --- /dev/null +++ b/include/QxCommon/QxSimpleCrypt.h @@ -0,0 +1,250 @@ +/* +Copyright (c) 2011, Andre Somers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Rathenau Instituut, Andre Somers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _QX_SIMPLECRYPT_H_ +#define _QX_SIMPLECRYPT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSimpleCrypt.h + * \author Andre Somers + * \ingroup QxCommon + * \brief qx::QxSimpleCrypt : simple encryption and decryption of strings and byte arrays + */ + +#include +#include +#include +#include + +namespace qx { + +/** + @ingroup QxCommon + @short Simple encryption and decryption of strings and byte arrays + + This class provides a simple implementation of encryption and decryption + of strings and byte arrays : http://qt-project.org/wiki/Simple_encryption + + @warning The encryption provided by this class is NOT strong encryption. It may + help to shield things from curious eyes, but it will NOT stand up to someone + determined to break the encryption. Don't say you were not warned. + + The class uses a 64 bit key. Simply create an instance of the class, set the key, + and use the encryptToString() method to calculate an encrypted version of the input string. + To decrypt that string again, use an instance of QxSimpleCrypt initialized with + the same key, and call the decryptToString() method with the encrypted string. If the key + matches, the decrypted version of the string will be returned again. + + If you do not provide a key, or if something else is wrong, the encryption and + decryption function will return an empty string or will return a string containing nonsense. + lastError() will return a value indicating if the method was succesful, and if not, why not. + + QxSimpleCrypt is prepared for the case that the encryption and decryption + algorithm is changed in a later version, by prepending a version identifier to the cypertext. + */ +class QX_DLL_EXPORT QxSimpleCrypt +{ + +public: + + /** + CompressionMode describes if compression will be applied to the data to be + encrypted. + */ + enum CompressionMode { + CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */ + CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */ + CompressionNever /*!< Never apply compression. */ + }; + + /** + IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data + or wrong decryption keys. + + Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This + increases the length of the resulting cypertext, but makes it possible to check if the plaintext + appears to be valid after decryption. + */ + enum IntegrityProtectionMode { + ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */ + ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */ + ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */ + }; + + /** + Error describes the type of error that occured. + */ + enum Error { + ErrorNoError, /*!< No error occurred. */ + ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */ + ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */ + ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */ + }; + + /** + Constructor. + + Constructs a QxSimpleCrypt instance without a valid key set on it. + */ + QxSimpleCrypt(); + /** + Constructor. + + Constructs a QxSimpleCrypt instance and initializes it with the given @arg key. + */ + explicit QxSimpleCrypt(quint64 key); + + /** + (Re-) initializes the key with the given @arg key. + */ + void setKey(quint64 key); + /** + Returns true if QxSimpleCrypt has been initialized with a key. + */ + bool hasKey() const {return !m_keyParts.isEmpty();} + + /** + Sets the compression mode to use when encrypting data. The default mode is Auto. + + Note that decryption is not influenced by this mode, as the decryption recognizes + what mode was used when encrypting. + */ + void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;} + /** + Returns the CompressionMode that is currently in use. + */ + CompressionMode compressionMode() const {return m_compressionMode;} + + /** + Sets the integrity mode to use when encrypting data. The default mode is Checksum. + + Note that decryption is not influenced by this mode, as the decryption recognizes + what mode was used when encrypting. + */ + void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;} + /** + Returns the IntegrityProtectionMode that is currently in use. + */ + IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;} + + /** + Returns the last error that occurred. + */ + Error lastError() const {return m_lastError;} + + /** + Encrypts the @arg plaintext string with the key the class was initialized with, and returns + a cyphertext the result. The result is a base64 encoded version of the binary array that is the + actual result of the string, so it can be stored easily in a text format. + */ + QString encryptToString(const QString& plaintext) ; + /** + Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns + a cyphertext the result. The result is a base64 encoded version of the binary array that is the + actual result of the encryption, so it can be stored easily in a text format. + */ + QString encryptToString(QByteArray plaintext) ; + /** + Encrypts the @arg plaintext string with the key the class was initialized with, and returns + a binary cyphertext in a QByteArray the result. + + This method returns a byte array, that is useable for storing a binary format. If you need + a string you can store in a text file, use encryptToString() instead. + */ + QByteArray encryptToByteArray(const QString& plaintext) ; + /** + Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns + a binary cyphertext in a QByteArray the result. + + This method returns a byte array, that is useable for storing a binary format. If you need + a string you can store in a text file, use encryptToString() instead. + */ + QByteArray encryptToByteArray(QByteArray plaintext) ; + + /** + Decrypts a cyphertext string encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QString decryptToString(const QString& cyphertext) ; + /** + Decrypts a cyphertext string encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QByteArray decryptToByteArray(const QString& cyphertext) ; + /** + Decrypts a cyphertext binary encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QString decryptToString(QByteArray cypher) ; + /** + Decrypts a cyphertext binary encrypted with this class with the set key back to the + plain text version. + + If an error occured, such as non-matching keys between encryption and decryption, + an empty string or a string containing nonsense may be returned. + */ + QByteArray decryptToByteArray(QByteArray cypher) ; + + // enum to describe options that have been used for the encryption. Currently only one, but + // that only leaves room for future extensions like adding a cryptographic hash... + enum CryptoFlag{CryptoFlagNone = 0, + CryptoFlagCompression = 0x01, + CryptoFlagChecksum = 0x02, + CryptoFlagHash = 0x04 + }; + Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag); + +private: + + void splitKey(); + + quint64 m_key; + QVector m_keyParts; + CompressionMode m_compressionMode; + IntegrityProtectionMode m_protectionMode; + Error m_lastError; + +}; + +} // namespace qx + +Q_DECLARE_OPERATORS_FOR_FLAGS(qx::QxSimpleCrypt::CryptoFlags) + +#endif // _QX_SIMPLECRYPT_H_ diff --git a/include/QxConvert/QxConvert.h b/include/QxConvert/QxConvert.h new file mode 100644 index 0000000..e8850c1 --- /dev/null +++ b/include/QxConvert/QxConvert.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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_CONVERT_H_ +#define _QX_CONVERT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxConvert.h + * \author XDL Team + * \ingroup QxConvert + * \brief qx::cvt : namespace to provide global functions to convert any kind of objects to/from QString and QVariant format + */ + +#ifndef _QX_NO_JSON +#include +#include +#include +#include +#endif // _QX_NO_JSON + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToString; + template + struct QxConvert_FromString; + template + struct QxConvert_ToVariant; + template + struct QxConvert_FromVariant; + template + struct QxConvert_WithIndex_ToString; + template + struct QxConvert_WithIndex_FromString; + template + struct QxConvert_WithIndex_ToVariant; + template + struct QxConvert_WithIndex_FromVariant; + +#ifndef _QX_NO_JSON + template + struct QxConvert_ToJson; + template + struct QxConvert_FromJson; +#endif // _QX_NO_JSON + + } // namespace detail + + struct context + { + enum ctx_type + { + e_no_context, + e_database, + e_serialize_registered + }; + }; + + template + inline QString to_string(const T &t, const QString &format = QString(), int index = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) { return qx::cvt::detail::QxConvert_WithIndex_ToString::toString(t, format, index, ctx); } + template + inline qx_bool from_string(const QString &s, T &t, const QString &format = QString(), int index = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) { return qx::cvt::detail::QxConvert_WithIndex_FromString::fromString(t, s, format, index, ctx); } + template + inline QVariant to_variant(const T &t, const QString &format = QString(), int index = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) { return qx::cvt::detail::QxConvert_WithIndex_ToVariant::toVariant(t, format, index, ctx); } + template + inline qx_bool from_variant(const QVariant &v, T &t, const QString &format = QString(), int index = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) { return qx::cvt::detail::QxConvert_WithIndex_FromVariant::fromVariant(t, v, format, index, ctx); } + +#ifndef _QX_NO_JSON + template + inline QJsonValue to_json(const T &t, const QString &format = QString()) { return qx::cvt::detail::QxConvert_ToJson::toJson(t, format); } + template + inline qx_bool from_json(const QJsonValue &j, T &t, const QString &format = QString()) { return qx::cvt::detail::QxConvert_FromJson::fromJson(j, t, format); } +#endif // _QX_NO_JSON + + } // namespace cvt +} // namespace qx + +#endif // _QX_CONVERT_H_ diff --git a/include/QxConvert/QxConvert_Export.h b/include/QxConvert/QxConvert_Export.h new file mode 100644 index 0000000..301d7d1 --- /dev/null +++ b/include/QxConvert/QxConvert_Export.h @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** 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_CONVERT_EXPORT_H_ +#define _QX_CONVERT_EXPORT_H_ +#if _QX_USE_QX_CONVERT_EXPORT + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToString, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromString, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_ToVariant, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, qx::cvt::detail::QxConvert_FromVariant, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#endif // _QX_USE_QX_CONVERT_EXPORT +#endif // _QX_CONVERT_EXPORT_H_ diff --git a/include/QxConvert/QxConvert_Impl.h b/include/QxConvert/QxConvert_Impl.h new file mode 100644 index 0000000..c759d0b --- /dev/null +++ b/include/QxConvert/QxConvert_Impl.h @@ -0,0 +1,906 @@ +/**************************************************************************** +** +** 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_CONVERT_IMPL_H_ +#define _QX_CONVERT_IMPL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define QX_STR_CVT_QDATE_FORMAT "yyyyMMdd" +#define QX_STR_CVT_QTIME_FORMAT "hhmmsszzz" +#define QX_STR_CVT_QDATETIME_FORMAT "yyyyMMddhhmmsszzz" + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_CVT_DEFAULT_ARCHIVE qx::serialization::polymorphic_xml +#elif _QX_SERIALIZE_XML +#define QX_CVT_DEFAULT_ARCHIVE qx::serialization::xml +#elif _QX_SERIALIZE_TEXT +#define QX_CVT_DEFAULT_ARCHIVE qx::serialization::text +#elif _QX_SERIALIZE_BINARY +#define QX_CVT_DEFAULT_ARCHIVE qx::serialization::binary +#endif // _QX_SERIALIZE_XML +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_CVT_DEFAULT_ARCHIVE qx::serialization::qt +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_CVT_USING_ARCHIVE_IMPL(className) \ + namespace qx \ + { \ + namespace cvt \ + { \ + namespace detail \ + { \ + template <> \ + struct QxConvert_ToString \ + { \ + static inline QString toString(const className &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) \ + { \ + Q_UNUSED(format); \ + Q_UNUSED(index); \ + Q_UNUSED(ctx); \ + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); \ + } \ + }; \ + template <> \ + struct QxConvert_FromString \ + { \ + static inline qx_bool fromString(const QString &s, className &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) \ + { \ + Q_UNUSED(format); \ + Q_UNUSED(index); \ + Q_UNUSED(ctx); \ + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); \ + } \ + }; \ + template <> \ + struct QxConvert_ToVariant \ + { \ + static inline QVariant toVariant(const className &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) \ + { \ + Q_UNUSED(format); \ + Q_UNUSED(index); \ + Q_UNUSED(ctx); \ + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); \ + } \ + }; \ + template <> \ + struct QxConvert_FromVariant \ + { \ + static inline qx_bool fromVariant(const QVariant &v, className &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) \ + { \ + Q_UNUSED(format); \ + Q_UNUSED(index); \ + Q_UNUSED(ctx); \ + QString s = v.toString(); \ + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); \ + } \ + }; \ + } \ + } \ + } // namespace qx::cvt::detail + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) +#define QX_JSON_DATE_TIME_FORMAT Qt::ISODateWithMs +#define QX_JSON_DATE_TIME_FORMAT_SIZE 23 // yyyy-MM-ddTHH:mm:ss.zzz +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) +#define QX_JSON_DATE_TIME_FORMAT Qt::ISODate +#define QX_JSON_DATE_TIME_FORMAT_SIZE 19 // yyyy-MM-ddTHH:mm:ss +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + +namespace qx +{ + namespace cvt + { + namespace detail + { + namespace helper + { + + struct QxConvertHelper_Generic + { + }; + struct QxConvertHelper_Ptr + { + }; + struct QxConvertHelper_Registered + { + }; + struct QxConvertHelper_Persistable + { + }; + struct QxConvertHelper_Container + { + }; + struct QxConvertHelper_Enum + { + }; + + inline bool checkConvertQVariantToString(const QVariant &v) { return ((v.type() == QVariant::List) || (v.type() == QVariant::Map) || (v.type() == QVariant::Hash) || (v.type() == QVariant::StringList)); } + + } // namespace helper + + template + struct QxConvertHelper_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_ToString", "template must be specialized"); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString(); + } + }; + + template + struct QxConvertHelper_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_FromString", "template must be specialized"); + Q_UNUSED(s); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return qx_bool(); + } + }; + + template + struct QxConvertHelper_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_ToVariant", "template must be specialized"); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(); + } + }; + + template + struct QxConvertHelper_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_FromVariant", "template must be specialized"); + Q_UNUSED(v); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return qx_bool(); + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_ToJson", "template must be specialized"); + Q_UNUSED(t); + Q_UNUSED(format); + return QJsonValue(); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + qAssertMsg(false, "qx::cvt::detail::QxConvertHelper_FromJson", "template must be specialized"); + Q_UNUSED(j); + Q_UNUSED(t); + Q_UNUSED(format); + return qx_bool(); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + + enum + { + qx_need_to_specialize_template_convert_to_string_from_string = 0 + }; + + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + static_assert(qx_need_to_specialize_template_convert_to_string_from_string, "qx_need_to_specialize_template_convert_to_string_from_string"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_ToString< MyType >' + return QString(); + } + }; + + template + struct QxConvertHelper_FromString + { + + enum + { + qx_need_to_specialize_template_convert_to_string_from_string = 0 + }; + + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(s); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + static_assert(qx_need_to_specialize_template_convert_to_string_from_string, "qx_need_to_specialize_template_convert_to_string_from_string"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_FromString< MyType >' + return qx_bool(true); + } + }; + + template + struct QxConvertHelper_ToVariant + { + + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return cvtQVariant::value, 0>::toVariant(t, format, index, ctx); + } + + private: + template + struct cvtQVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::to_string(t, format, index, ctx); }; + }; + + template + struct cvtQVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + }; + }; + }; + + template + struct QxConvertHelper_FromVariant + { + + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return cvtQVariant::value, 0>::fromVariant(v, t, format, index, ctx); + } + + private: + template + struct cvtQVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::from_string(v.toString(), t, format, index, ctx); }; + }; + + template + struct cvtQVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.value(); + return qx_bool(true); + }; + }; + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + return QJsonValue::fromVariant(qx::cvt::detail::QxConvertHelper_ToVariant::toVariant(t, format, -1, qx::cvt::context::e_no_context)); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + QVariant v = j.toVariant(); + return qx::cvt::detail::QxConvertHelper_FromVariant::fromVariant(v, t, format, -1, qx::cvt::context::e_no_context); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + + enum + { + qx_need_to_specialize_template_convert_to_string_from_string = 0 + }; + + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); +#ifndef _QX_NO_JSON + return t.toJson(format); +#else // _QX_NO_JSON + static_assert(qx_need_to_specialize_template_convert_to_string_from_string, "qx_need_to_specialize_template_convert_to_string_from_string"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_ToString< MyType >' + return QString(); +#endif // _QX_NO_JSON + } + }; + + template + struct QxConvertHelper_FromString + { + + enum + { + qx_need_to_specialize_template_convert_to_string_from_string = 0 + }; + + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(s); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); +#ifndef _QX_NO_JSON + return t.fromJson(s, format); +#else // _QX_NO_JSON + static_assert(qx_need_to_specialize_template_convert_to_string_from_string, "qx_need_to_specialize_template_convert_to_string_from_string"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_FromString< MyType >' + return qx_bool(true); +#endif // _QX_NO_JSON + } + }; + + template + struct QxConvertHelper_ToVariant + { + + enum + { + qx_need_to_specialize_template_convert_to_variant_from_variant = 0 + }; + + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); +#ifndef _QX_NO_JSON + return QVariant(t.toJson(format)); +#else // _QX_NO_JSON + static_assert(qx_need_to_specialize_template_convert_to_variant_from_variant, "qx_need_to_specialize_template_convert_to_variant_from_variant"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_ToVariant< MyType >' + return QVariant(); +#endif // _QX_NO_JSON + } + }; + + template + struct QxConvertHelper_FromVariant + { + + enum + { + qx_need_to_specialize_template_convert_to_variant_from_variant = 0 + }; + + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(v); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); +#ifndef _QX_NO_JSON + return t.fromJson(v.toString(), format); +#else // _QX_NO_JSON + static_assert(qx_need_to_specialize_template_convert_to_variant_from_variant, "qx_need_to_specialize_template_convert_to_variant_from_variant"); // If a compilation error occurred here : you have to specialize template 'qx::cvt::detail::QxConvert_FromVariant< MyType >' + return qx_bool(true); +#endif // _QX_NO_JSON + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + const qx::IxPersistable *p = static_cast(&t); + return qx::cvt::to_json((*p), format); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + qx::IxPersistable *p = static_cast(&t); + return qx::cvt::from_json(j, (*p), format); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return (t ? qx::cvt::to_string((*t), format, index, ctx) : ""); + } + }; + + template + struct QxConvertHelper_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (!t) + { + qx::trait::construct_ptr::get(t); + }; + return (t ? qx::cvt::from_string(s, (*t), format, index, ctx) : qx_bool(false)); + } + }; + + template + struct QxConvertHelper_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return (t ? qx::cvt::to_variant((*t), format, index, ctx) : QVariant()); + } + }; + + template + struct QxConvertHelper_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (!t && !v.isNull()) + { + qx::trait::construct_ptr::get(t); + } + else if (v.isNull()) + { + qx::trait::construct_ptr::get(t, true); + }; + return (t ? qx::cvt::from_variant(v, (*t), format, index, ctx) : qx_bool(false)); + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + return (t ? qx::cvt::to_json((*t), format) : QJsonValue()); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + if (!t && !j.isNull()) + { + qx::trait::construct_ptr::get(t); + } + else if (j.isNull()) + { + qx::trait::construct_ptr::get(t, true); + }; + return (t ? qx::cvt::from_json(j, (*t), format) : qx_bool(false)); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_serialize_registered) + { + qx::IxDataMember *pId = qx::QxClass::getSingleton()->getDataMemberX()->getId_WithDaoStrategy(); + return (pId ? pId->toVariant((&t), format, index, ctx).toString() : QString()); + } + return qx::serialization::qt::to_string(t); + } + }; + + template + struct QxConvertHelper_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_serialize_registered) + { + qx::IxDataMember *pId = qx::QxClass::getSingleton()->getDataMemberX()->getId_WithDaoStrategy(); + QVariant tmp(s); + return (pId ? pId->fromVariant((&t), tmp, format, index, ctx) : qx_bool(false)); + } + return qx::serialization::qt::from_string(t, s); + } + }; + + template + struct QxConvertHelper_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_serialize_registered) + { + qx::IxDataMember *pId = qx::QxClass::getSingleton()->getDataMemberX()->getId_WithDaoStrategy(); + return (pId ? pId->toVariant((&t), format, index, ctx) : QVariant()); + } + return qx::serialization::qt::to_byte_array(t); + } + }; + + template + struct QxConvertHelper_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_serialize_registered) + { + qx::IxDataMember *pId = qx::QxClass::getSingleton()->getDataMemberX()->getId_WithDaoStrategy(); + return (pId ? pId->fromVariant((&t), v, format, index, ctx) : qx_bool(false)); + } + return qx::serialization::qt::from_byte_array(t, v.toByteArray()); + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + return qx::cvt::detail::QxSerializeJsonRegistered::save(t, format); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + return qx::cvt::detail::QxSerializeJsonRegistered::load(j, t, format); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvertHelper_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvertHelper_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvertHelper_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, v.toString()); + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + return QJsonValue::fromVariant(qx::cvt::detail::QxConvertHelper_ToVariant::toVariant(t, format, -1, qx::cvt::context::e_no_context)); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + QVariant v = j.toVariant(); + return qx::cvt::detail::QxConvertHelper_FromVariant::fromVariant(v, t, format, -1, qx::cvt::context::e_no_context); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::number(static_cast(t)); + } + }; + + template + struct QxConvertHelper_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(static_cast(s.toLongLong(&bOk))); + return bOk; + } + }; + + template + struct QxConvertHelper_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template + struct QxConvertHelper_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(static_cast(v.toLongLong(&bOk))); + return bOk; + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvertHelper_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template + struct QxConvertHelper_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(static_cast(qRound(j.toDouble()))); + return qx_bool(true); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvertHelper + { + + private: + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Persistable, qx::cvt::detail::helper::QxConvertHelper_Generic>::type type_str_cvt_helper_0; + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Ptr, type_str_cvt_helper_0>::type type_str_cvt_helper_1; + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Ptr, type_str_cvt_helper_1>::type type_str_cvt_helper_2; + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Container, type_str_cvt_helper_2>::type type_str_cvt_helper_3; + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Registered, type_str_cvt_helper_3>::type type_str_cvt_helper_4; + typedef typename std::conditional::value, qx::cvt::detail::helper::QxConvertHelper_Enum, type_str_cvt_helper_4>::type type_str_cvt_helper_5; + + public: + typedef typename QxConvertHelper::type_str_cvt_helper_5 type; + }; + + template + struct QxConvert_ToString + { + static inline QString toString(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return qx::cvt::detail::QxConvertHelper_ToString::type>::toString(t, format, index, ctx); + } + }; + + template + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return qx::cvt::detail::QxConvertHelper_FromString::type>::fromString(s, t, format, index, ctx); + } + }; + + template + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return qx::cvt::detail::QxConvertHelper_ToVariant::type>::toVariant(t, format, index, ctx); + } + }; + + template + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, T &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + return qx::cvt::detail::QxConvertHelper_FromVariant::type>::fromVariant(v, t, format, index, ctx); + } + }; + +#ifndef _QX_NO_JSON + + template + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const T &t, const QString &format) + { + return qx::cvt::detail::QxConvertHelper_ToJson::type>::toJson(t, format); + } + }; + + template + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, T &t, const QString &format) + { + return qx::cvt::detail::QxConvertHelper_FromJson::type>::fromJson(j, t, format); + } + }; + +#endif // _QX_NO_JSON + + } // namespace detail + } // namespace cvt +} // namespace qx + +#include "../../inl/QxConvert/QxConvert_WithIndex.inl" +#include "../../inl/QxConvert/QxConvert_ToString.inl" +#include "../../inl/QxConvert/QxConvert_FromString.inl" +#include "../../inl/QxConvert/QxConvert_ToVariant.inl" +#include "../../inl/QxConvert/QxConvert_FromVariant.inl" +#include "../../inl/QxConvert/QxConvert_ToJson.inl" +#include "../../inl/QxConvert/QxConvert_FromJson.inl" +#include "../../inl/QxConvert/QxConvert_Qt.inl" + +#endif // _QX_CONVERT_IMPL_H_ diff --git a/include/QxDao/IxDao_Helper.h b/include/QxDao/IxDao_Helper.h new file mode 100644 index 0000000..034d7e0 --- /dev/null +++ b/include/QxDao/IxDao_Helper.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** 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 _IX_DAO_HELPER_H_ +#define _IX_DAO_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxDao_Helper.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to communicate with database + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include + +namespace qx +{ + template + QxInvalidValueX validate(T &t, const QString &group); + class QxSession; +} // namespace qx + +namespace qx +{ + namespace dao + { + namespace detail + { + + struct IxDao_Timer; + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::IxDao_Helper : helper class to communicate with database + */ + class QX_DLL_EXPORT IxDao_Helper + { + + friend struct IxDao_Timer; + + public: + enum timer_type + { + timer_none, + timer_total, + timer_db_exec, + timer_db_next, + timer_db_prepare, + timer_cpp_build_hierarchy, + timer_cpp_build_instance, + timer_cpp_read_instance, + timer_build_sql, + timer_db_open, + timer_db_transaction + }; + + private: + struct IxDao_HelperImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + protected: + IxDao_Helper(qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery = NULL); + virtual ~IxDao_Helper(); + + public: + bool isValid() const; + bool hasFeature(QSqlDriver::DriverFeature ft) const; + + QSqlDatabase &database(); + const QSqlDatabase &database() const; + QSqlQuery &query(); + const QSqlQuery &query() const; + QSqlError &error(); + const QSqlError &error() const; + qx::QxSqlQuery &qxQuery(); + const qx::QxSqlQuery &qxQuery() const; + qx::IxSqlQueryBuilder &builder(); + const qx::IxSqlQueryBuilder &builder() const; + qx::IxDataMemberX *getDataMemberX() const; + long getDataCount() const; + qx::IxDataMember *getDataId() const; + qx::IxDataMember *nextData(long &l) const; + QString sql() const; + qx::QxSqlRelationLinked *getSqlRelationLinked() const; + qx::QxSession *getSession() const; + QString getIgnoreSoftDeleteHash() const; + bool getCartesianProduct() const; + QStringList getSqlColumns() const; + void setSqlColumns(const QStringList &lst); + bool getUseExecBatch() const; + void setUseExecBatch(bool b); + qx::QxCollection &getListExecBatch(); + IxSqlGenerator *getSqlGenerator() const; + void addInvalidValues(const qx::QxInvalidValueX &lst); + bool getAddAutoIncrementIdToUpdateQuery() const; + QStringList &itemsAsJson(); + bool isReadOnly() const; + bool isMongoDB() const; + bool isDistinct() const; + QVariant getIdFromQuery(int iNameIndex = -1) const; + + QSqlError errFailed(bool bPrepare = false); + QSqlError errEmpty(); + QSqlError errNoData(); + QSqlError errInvalidId(); + QSqlError errInvalidRelation(); + QSqlError errReadOnly(); + + bool transaction(); + bool nextRecord(); + void quiet(); + bool exec(bool bForceEmptyExec = false); + bool prepare(QString &sql); + + QSqlError updateError(const QSqlError &error); + bool updateSqlRelationX(const QStringList &relation); + void addQuery(bool bResolve); + void dumpRecord() const; + void resolveQuery(); + + template + inline bool isValidPrimaryKey(const U &u) + { + return (getDataId() && qx::trait::is_valid_primary_key(getDataId()->toVariant((&u), -1, qx::cvt::context::e_database))); + } + + template + inline void updateLastInsertId(U &u) + { + if (getDataId() && getDataId()->getAutoIncrement() && this->hasFeature(QSqlDriver::LastInsertId)) + { + getDataId()->fromVariant((&u), query().lastInsertId(), -1, qx::cvt::context::e_database); + } + } + + template + inline bool validateInstance(U &u) + { + qx::QxInvalidValueX invalidValues = qx::validate(u, ""); + this->addInvalidValues(invalidValues); + return (invalidValues.count() <= 0); + } + + protected: + void dumpBoundValues() const; + QSqlError updateError(const QString &sError); + void timerStart(IxDao_Helper::timer_type timer); + qint64 timerElapsed(IxDao_Helper::timer_type timer); + void init(QSqlDatabase *pDatabase, const QString &sContext); + void terminate(); + }; + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::IxDao_Timer : scoped timer to measure database elapsed times (using C++ RAII) + */ + struct IxDao_Timer + { + + IxDao_Helper *m_pDaoHelper; //!< Pointer to dao helper class + IxDao_Helper::timer_type m_eTimerType; //!< Timer type (database or C++ action) + + IxDao_Timer(IxDao_Helper *pDaoHelper, IxDao_Helper::timer_type timer) : m_pDaoHelper(pDaoHelper), m_eTimerType(timer) + { + if (m_pDaoHelper) + { + m_pDaoHelper->timerStart(m_eTimerType); + } + } + ~IxDao_Timer() + { + if (m_pDaoHelper) + { + m_pDaoHelper->timerElapsed(m_eTimerType); + } + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _IX_DAO_HELPER_H_ diff --git a/include/QxDao/IxPersistable.h b/include/QxDao/IxPersistable.h new file mode 100644 index 0000000..34edef4 --- /dev/null +++ b/include/QxDao/IxPersistable.h @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** 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 _IX_PERSISTABLE_H_ +#define _IX_PERSISTABLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxPersistable.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface (abstract class) for persistents classes using QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros + */ + +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + class IxPersistableCollection; + + /*! + * \ingroup QxDao + * \brief qx::IxPersistable : common interface (abstract class) for persistents classes using QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros + * + * To use this common interface for persistents classes :
+ * 1- inherit your persistent class from qx::IxPersistable ;
+ * 2- into your class definition (myClass.h for example), add QX_PERSISTABLE_HPP(myClass) macro ;
+ * 3- into your class implementation (myClass.cpp for example), add QX_PERSISTABLE_CPP(myClass) macro. + * + * Note : for a list of objects (qxFetchAll() method or qxFetchByQuery() method), use qx::QxCollection> type. + * Or just use qx::QxPersistableCollectionHelper::type to retrieve your persistent collection type. + * A convenient way to fetch a list of objects is to use following static methods qxFetchAll() and qxFetchByQuery() : + * \code + std::shared_ptr lst = qx::IxPersistable::qxFetchAll("myClass"); + for (long l = 0; l < lst->_count(); l++) + { qx::IxPersistable_ptr ptr = lst->_get(l); etc... } + * \endcode + */ + class QX_DLL_EXPORT IxPersistable + { + + public: + IxPersistable(); + virtual ~IxPersistable(); + + /*! + * \brief Return the number of lines in the table (database) mapped to the current C++ class (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * + * qx::IxPersistable * p = ...;
+ * p->qxCount(...) execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + XXX_JOINS_XXX + WHERE my_query... + */ + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) = 0; + + /*! + * \brief Return the number of lines in the table (database) mapped to the current C++ class (registered into QxOrm context) and filtered by a user SQL query + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * + * qx::IxPersistable * p = ...;
+ * p->qxCount(...) execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + XXX_JOINS_XXX + WHERE my_query... + */ + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) = 0; + + /*! + * \brief Fetch current instance (retrieve all its properties) mapped to a table in the database (current instance must have a valid id before to be fetched without error, or pass the id to the first parameter of this method) + * \param id Unique id to fetch properties from database (if empty, check id of current instance) + * \param columns List of database table columns (mapped to properties of C++ class) to fetch (if empty, all columns are fetched) + * \param relation List of relationships keys to fetch (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxFetchById(...) execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + virtual QSqlError qxFetchById(const QVariant &id = QVariant(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Fetch a list of objects (retrieve all elements and properties associated) of current type (container registered into QxOrm context) mapped to a table in the database + * \param list Container to fetch all items (retrieve all elements and properties associated); list is cleared before executing SQL query + * \param columns List of database table columns (mapped to properties of C++ class) to fetch (if empty, all columns are fetched) + * \param relation List of relationships keys to fetch (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * std::shared_ptr lst = p->qxNewPersistableCollection();
+ * p->qxFetchAll(& lst, ...) execute following SQL query :
+ * SELECT * FROM my_table + */ + virtual QSqlError qxFetchAll(qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Fetch a list of objects (retrieve all elements and properties associated) of current type (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param list Container to fetch all items (retrieve all elements and properties associated); list is cleared before executing SQL query + * \param columns List of database table columns (mapped to properties of C++ class) to fetch (if empty, all columns are fetched) + * \param relation List of relationships keys to fetch (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * std::shared_ptr lst = p->qxNewPersistableCollection();
+ * p->qxFetchByQuery(my_query, & lst, ...) execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Insert current instance into database + * \param relation List of relationships keys to insert in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance inserting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxInsert(...) execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + + /*! + * \brief Update current instance into database (you can add a user SQL query to the default SQL query builded by QxOrm library) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param columns List of database table columns (mapped to properties of C++ class) to update (if empty, all columns are updated) + * \param relation List of relationships keys to update in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxUpdate(...) execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + + /*! + * \brief Insert (if no exist) or update (if already exist) current instance into database + * \param relation List of relationships keys to insert or update in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param eSaveRecursiveMode Parameter to call qx::dao::save_with_relation_recursive function + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxSave(...) execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, qx::dao::save_mode::e_save_mode eSaveRecursiveMode = qx::dao::save_mode::e_none) = 0; + + /*! + * \brief Delete current instance from database + * \param id Unique id to delete from database (if empty, check id of current instance) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance deleting a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDeleteById(...) execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ?
+ *
+ * If a soft delete behavior is defined for current class, p->qxDeleteById(...) execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' WHERE my_id = ? + */ + virtual QSqlError qxDeleteById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + + /*! + * \brief Delete all lines of a table (database) mapped to current C++ class (registered into QxOrm context) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDeleteAll(...) execute following SQL query :
+ * DELETE FROM my_table
+ *
+ * If a soft delete behavior is defined for current class, p->qxDeleteAll(...) execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + */ + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Delete all lines of a table (database) mapped to current C++ class (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDeleteByQuery(...) execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query...
+ *
+ * If a soft delete behavior is defined for current class, p->qxDeleteByQuery(...) execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + WHERE my_query... + */ + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Delete current instance from database + * \param id Unique id to delete from database (if empty, check id of current instance) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance destroying a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDestroyById(...) execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ?
+ */ + virtual QSqlError qxDestroyById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + + /*! + * \brief Delete all lines of a table (database) mapped to current C++ class (registered into QxOrm context) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDestroyAll(...) execute following SQL query :
+ * DELETE FROM my_table
+ */ + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Delete all lines of a table (database) mapped to current C++ class (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxDestroyByQuery(...) execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query...
+ */ + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Execute a custom SQL query or a stored procedure, all columns that can be mapped to the instance of type T will be fetched automatically + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Execute a custom SQL query or a stored procedure, all columns that can be mapped to the instance of type T will be fetched automatically + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param list Container to fetch all items (retrieve all elements and properties associated); list is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Search if current instance already exists into database + * \param id Unique id to check into database (if empty, check id of current instance) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class + * \return Return true if element already exists into database; otherwise return false; if an error occurred, qx_bool object contains a description of database error executing SQL query + * + * qx::IxPersistable * p = ...;
+ * p->qxExist(...) execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + virtual qx_bool qxExist(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL) = 0; + + /*! + * \brief Check if current instance is valid or not + * \param groups List of groups to check (defined into QxValidator module for current class) + * \return Return list of invalid values (if empty, current instance is valid) + * + * For more details about QxValidator module : https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) = 0; + + /*! + * \brief Create a new collection smart-pointer to fetch a list of items of current class type + * \param bAsList If true, returns a list (array) of persistent instances instead of key/value hash-map + * \return Return a new collection smart-pointer to fetch a list of items of current class type + */ + virtual std::shared_ptr qxNewPersistableCollection(bool bAsList = false) const = 0; + + /*! + * \brief Access to introspection engine (or reflection engine) of QxOrm library + * \return Return a qx::IxClass pointer to access to introspection engine (or reflection engine) of QxOrm library, and get some informations about current class (properties, methods, etc...) + */ + virtual qx::IxClass *qxClass() const = 0; + +#ifndef _QX_NO_JSON + virtual QString toJson(const QString &format = QString()) const = 0; + virtual QJsonValue toJson_(const QString &format = QString()) const = 0; + virtual qx_bool fromJson(const QString &json, const QString &format = QString()) = 0; + virtual qx_bool fromJson_(const QJsonValue &json, const QString &format = QString()) = 0; +#endif // _QX_NO_JSON + + public: + static std::shared_ptr qxFetchAll(const QString &className, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bAsList = false); + static std::shared_ptr qxFetchByQuery(const QString &className, const qx::QxSqlQuery &query, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bAsList = false); + static std::shared_ptr qxExecuteQuery(const QString &className, qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL, bool bAsList = false); + }; + + typedef std::shared_ptr IxPersistable_ptr; + +} // namespace qx + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_ix_persistable::value : return true if T implements qx::IxPersistable interface, otherwise return false + */ + template + struct is_ix_persistable + { + enum + { + value = std::is_base_of::value + }; + }; + + } // namespace trait +} // namespace qx + +#ifndef _QX_NO_JSON +#define QX_PERSISTABLE_JSON_HPP(className) \ + virtual QString toJson(const QString &format = QString()) const; \ + virtual QJsonValue toJson_(const QString &format = QString()) const; \ + virtual qx_bool fromJson(const QString &json, const QString &format = QString()); \ + virtual qx_bool fromJson_(const QJsonValue &json, const QString &format = QString()); +#else // _QX_NO_JSON +#define QX_PERSISTABLE_JSON_HPP(className) /* Nothing */ +#endif // _QX_NO_JSON + +#define QX_PERSISTABLE_HPP(className) \ +public: \ + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()); \ + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()); \ + virtual QSqlError qxFetchById(const QVariant &id = QVariant(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxFetchAll(qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false); \ + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false); \ + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, qx::dao::save_mode::e_save_mode eSaveRecursiveMode = qx::dao::save_mode::e_none); \ + virtual QSqlError qxDeleteById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false); \ + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxDestroyById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false); \ + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); \ + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, QSqlDatabase *pDatabase = NULL); \ + virtual qx_bool qxExist(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL); \ + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()); \ + virtual std::shared_ptr qxNewPersistableCollection(bool bAsList = false) const; \ + virtual qx::IxClass *qxClass() const; \ + QX_PERSISTABLE_JSON_HPP(className) + +#ifdef _QX_NO_RTTI +#define QX_PERSISTABLE_CAST_COLLECTION(className) \ + if (!list) \ + { \ + return QSqlError(); \ + } \ + qx::QxPersistableCollectionHelper::type_coll *list_typed = static_cast::type *>(list); +#else // _QX_NO_RTTI +#define QX_PERSISTABLE_CAST_COLLECTION(className) \ + if (!list) \ + { \ + return QSqlError(); \ + } \ + qx::QxPersistableCollectionHelper::type_coll *list_typed = dynamic_cast::type *>(list); +#endif // _QX_NO_RTTI + +#ifndef _QX_NO_JSON +#define QX_PERSISTABLE_JSON_CPP(className) \ + QString className::toJson(const QString &format) const { return qx::serialization::json::to_string((*this), 1, format); } \ + QJsonValue className::toJson_(const QString &format) const { return qx::cvt::to_json((*this), format); } \ + qx_bool className::fromJson(const QString &json, const QString &format) { return qx::serialization::json::from_string((*this), json, 1, format); } \ + qx_bool className::fromJson_(const QJsonValue &json, const QString &format) { return qx::cvt::from_json(json, (*this), format); } +#else // _QX_NO_JSON +#define QX_PERSISTABLE_JSON_CPP(className) /* Nothing */ +#endif // _QX_NO_JSON + +#define QX_PERSISTABLE_CPP(className) \ + \ + long className::qxCount(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase, const QStringList &relation) \ + { \ + if (relation.count() == 0) \ + { \ + return qx::dao::count(query, pDatabase); \ + } \ + else \ + { \ + long lCount(0); \ + qx::dao::count_with_relation(lCount, relation, query, pDatabase); \ + return lCount; \ + } \ + } \ + \ + QSqlError className::qxCount(long &lCount, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase, const QStringList &relation) \ + { \ + if (relation.count() == 0) \ + { \ + return qx::dao::count(lCount, query, pDatabase); \ + } \ + else \ + { \ + return qx::dao::count_with_relation(lCount, relation, query, pDatabase); \ + } \ + } \ + \ + QSqlError className::qxFetchById(const QVariant &id, const QStringList &columns, const QStringList &relation, QSqlDatabase *pDatabase) \ + { \ + if (id.isValid()) \ + { \ + qx::IxDataMemberX *pDataMemberX = qx::QxClass::getSingleton()->getDataMemberX(); \ + qx::IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); \ + if (!pDataMemberId) \ + { \ + qDebug("[QxOrm] problem with 'qxFetchById()' method : '%s'", "data member id not registered"); \ + qAssert(false); \ + } \ + if (!pDataMemberId) \ + { \ + return QSqlError("[QxOrm] problem with 'qxFetchById()' method : 'data member id not registered'", "", QSqlError::UnknownError); \ + } \ + pDataMemberId->fromVariant(this, id, -1, qx::cvt::context::e_database); \ + } \ + QSqlError err; \ + if (relation.count() == 0) \ + { \ + err = qx::dao::fetch_by_id((*this), pDatabase, columns); \ + } \ + else \ + { \ + err = qx::dao::fetch_by_id_with_relation(relation, (*this), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxFetchAll(qx::IxPersistableCollection *list, const QStringList &columns, const QStringList &relation, QSqlDatabase *pDatabase) \ + { \ + QX_PERSISTABLE_CAST_COLLECTION(className) \ + if (!list_typed) \ + { \ + qDebug("[QxOrm] problem with 'qxFetchAll()' method : '%s'", "dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >"); \ + qAssert(false); \ + } \ + if (!list_typed) \ + { \ + return QSqlError("[QxOrm] problem with 'qxFetchAll()' method : 'dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >'", "", QSqlError::UnknownError); \ + } \ + QSqlError err; \ + if (relation.count() == 0) \ + { \ + err = qx::dao::fetch_all((*list_typed), pDatabase, columns); \ + } \ + else \ + { \ + err = qx::dao::fetch_all_with_relation(relation, (*list_typed), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxFetchByQuery(const qx::QxSqlQuery &query, qx::IxPersistableCollection *list, const QStringList &columns, const QStringList &relation, QSqlDatabase *pDatabase) \ + { \ + QX_PERSISTABLE_CAST_COLLECTION(className) \ + if (!list_typed) \ + { \ + qDebug("[QxOrm] problem with 'qxFetchByQuery()' method : '%s'", "dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >"); \ + qAssert(false); \ + } \ + if (!list_typed) \ + { \ + return QSqlError("[QxOrm] problem with 'qxFetchByQuery()' method : 'dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >'", "", QSqlError::UnknownError); \ + } \ + QSqlError err; \ + if (relation.count() == 0) \ + { \ + err = qx::dao::fetch_by_query(query, (*list_typed), pDatabase, columns); \ + } \ + else \ + { \ + err = qx::dao::fetch_by_query_with_relation(relation, query, (*list_typed), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxInsert(const QStringList &relation, QSqlDatabase *pDatabase, bool bUseExecBatch) \ + { \ + QSqlError err; \ + if (relation.count() == 0) \ + { \ + err = qx::dao::insert((*this), pDatabase, bUseExecBatch); \ + } \ + else \ + { \ + err = qx::dao::insert_with_relation(relation, (*this), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxUpdate(const qx::QxSqlQuery &query, const QStringList &columns, const QStringList &relation, QSqlDatabase *pDatabase, bool bUseExecBatch) \ + { \ + QSqlError err; \ + if (relation.count() == 0) \ + { \ + err = qx::dao::update_by_query(query, (*this), pDatabase, columns, bUseExecBatch); \ + } \ + else \ + { \ + err = qx::dao::update_by_query_with_relation(relation, query, (*this), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxSave(const QStringList &relation, QSqlDatabase *pDatabase, qx::dao::save_mode::e_save_mode eSaveRecursiveMode) \ + { \ + QSqlError err; \ + if (eSaveRecursiveMode != qx::dao::save_mode::e_none) \ + { \ + err = qx::dao::save_with_relation_recursive((*this), eSaveRecursiveMode, pDatabase); \ + } \ + else if (relation.count() == 0) \ + { \ + err = qx::dao::save((*this), pDatabase); \ + } \ + else \ + { \ + err = qx::dao::save_with_relation(relation, (*this), pDatabase); \ + } \ + return err; \ + } \ + \ + QSqlError className::qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase, bool bUseExecBatch) \ + { \ + if (id.isValid()) \ + { \ + qx::IxDataMemberX *pDataMemberX = qx::QxClass::getSingleton()->getDataMemberX(); \ + qx::IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); \ + if (!pDataMemberId) \ + { \ + qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); \ + qAssert(false); \ + } \ + if (!pDataMemberId) \ + { \ + return QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); \ + } \ + pDataMemberId->fromVariant(this, id, -1, qx::cvt::context::e_database); \ + } \ + return qx::dao::delete_by_id((*this), pDatabase, bUseExecBatch); \ + } \ + \ + QSqlError className::qxDeleteAll(QSqlDatabase *pDatabase) \ + { \ + return qx::dao::delete_all(pDatabase); \ + } \ + \ + QSqlError className::qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase) \ + { \ + return qx::dao::delete_by_query(query, pDatabase); \ + } \ + \ + QSqlError className::qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase, bool bUseExecBatch) \ + { \ + if (id.isValid()) \ + { \ + qx::IxDataMemberX *pDataMemberX = qx::QxClass::getSingleton()->getDataMemberX(); \ + qx::IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); \ + if (!pDataMemberId) \ + { \ + qDebug("[QxOrm] problem with 'qxDestroyById()' method : '%s'", "data member id not registered"); \ + qAssert(false); \ + } \ + if (!pDataMemberId) \ + { \ + return QSqlError("[QxOrm] problem with 'qxDestroyById()' method : 'data member id not registered'", "", QSqlError::UnknownError); \ + } \ + pDataMemberId->fromVariant(this, id, -1, qx::cvt::context::e_database); \ + } \ + return qx::dao::destroy_by_id((*this), pDatabase, bUseExecBatch); \ + } \ + \ + QSqlError className::qxDestroyAll(QSqlDatabase *pDatabase) \ + { \ + return qx::dao::destroy_all(pDatabase); \ + } \ + \ + QSqlError className::qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase) \ + { \ + return qx::dao::destroy_by_query(query, pDatabase); \ + } \ + \ + QSqlError className::qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase) \ + { \ + return qx::dao::execute_query(query, (*this), pDatabase); \ + } \ + \ + QSqlError className::qxExecuteQuery(qx::QxSqlQuery &query, qx::IxPersistableCollection *list, QSqlDatabase *pDatabase) \ + { \ + QX_PERSISTABLE_CAST_COLLECTION(className) \ + if (!list_typed) \ + { \ + qDebug("[QxOrm] problem with 'qxExecuteQuery()' method : '%s'", "dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >"); \ + qAssert(false); \ + } \ + if (!list_typed) \ + { \ + return QSqlError("[QxOrm] problem with 'qxExecuteQuery()' method : 'dynamic_cast failed using collection qx::QxCollection< type_primary_key, std::shared_ptr >'", "", QSqlError::UnknownError); \ + } \ + return qx::dao::execute_query(query, (*list_typed), pDatabase); \ + } \ + \ + qx_bool className::qxExist(const QVariant &id, QSqlDatabase *pDatabase) \ + { \ + if (id.isValid()) \ + { \ + qx::IxDataMemberX *pDataMemberX = qx::QxClass::getSingleton()->getDataMemberX(); \ + qx::IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); \ + if (!pDataMemberId) \ + { \ + qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered"); \ + qAssert(false); \ + } \ + if (!pDataMemberId) \ + { \ + return qx_bool(false); \ + } \ + pDataMemberId->fromVariant(this, id, -1, qx::cvt::context::e_database); \ + } \ + return qx::dao::exist((*this), pDatabase); \ + } \ + \ + qx::QxInvalidValueX className::qxValidate(const QStringList &groups) \ + { \ + return qx::validate((*this), groups); \ + } \ + \ + std::shared_ptr className::qxNewPersistableCollection(bool bAsList) const \ + { \ + if (bAsList) \ + { \ + std::shared_ptr coll = std::make_shared>(); \ + return coll; \ + } \ + else \ + { \ + std::shared_ptr coll = std::make_shared::type>(); \ + return coll; \ + } \ + } \ + \ + qx::IxClass *className::qxClass() const \ + { \ + return qx::QxClass::getSingleton(); \ + } \ + \ + QX_PERSISTABLE_JSON_CPP(className) + +QX_REGISTER_CLASS_NAME(qx::IxPersistable) + +#include + +#endif // _IX_PERSISTABLE_H_ diff --git a/include/QxDao/IxPersistableCollection.h b/include/QxDao/IxPersistableCollection.h new file mode 100644 index 0000000..6a31a17 --- /dev/null +++ b/include/QxDao/IxPersistableCollection.h @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** 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 _IX_PERSISTABLE_COLLECTION_H_ +#define _IX_PERSISTABLE_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxPersistableCollection.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface (abstract class) for collection persistent classes based on qx::IxPersistable and qx::IxCollection + */ + +#include + +#include + +#include +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::IxPersistableCollection : common interface (abstract class) for collection persistent classes based on qx::IxPersistable and qx::IxCollection + */ + class QX_DLL_EXPORT IxPersistableCollection : public qx::IxPersistable + { + + public: + IxPersistableCollection(); + virtual ~IxPersistableCollection(); + + virtual long __count() const = 0; + virtual void __clear() = 0; + virtual bool __remove(long idx) = 0; + virtual qx::IxPersistable_ptr __at(long idx) const = 0; + }; + + typedef std::shared_ptr IxPersistableCollection_ptr; + + /*! + * \ingroup QxDao + * \brief qx::QxPersistableCollection : concrete class for collection persistent classes based on qx::IxPersistableCollection and qx::QxCollection + */ + template + class QxPersistableCollection : public qx::IxPersistableCollection, public qx::QxCollection + { + + enum + { + qx_is_valid = qx::trait::is_qx_registered::value + }; + + public: + QxPersistableCollection() : qx::IxPersistableCollection(), qx::QxCollection() { static_assert(qx_is_valid, "qx_is_valid"); } + virtual ~QxPersistableCollection() { ; } + + virtual long __count() const + { + const qx::QxCollection *coll = this; + return coll->count(); + } + virtual void __clear() + { + qx::QxCollection *coll = this; + coll->clear(); + } + virtual bool __remove(long idx) + { + qx::QxCollection *coll = this; + return coll->removeByIndex(idx); + } + virtual qx::IxPersistable_ptr __at(long idx) const + { + const qx::QxCollection *coll = this; + Value val = coll->getByIndex(idx); + return std::static_pointer_cast(val); + } + + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) + { + if (relation.count() == 0) + { + return qx::dao::count(query, pDatabase); + } + else + { + long lCount(0); + qx::dao::count_with_relation(lCount, relation, query, pDatabase); + return lCount; + } + } + + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) + { + if (relation.count() == 0) + { + return qx::dao::count(lCount, query, pDatabase); + } + else + { + return qx::dao::count_with_relation(lCount, relation, query, pDatabase); + } + } + + virtual QSqlError qxFetchById(const QVariant &id = QVariant(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(id); + QSqlError err; + qx::QxCollection *coll = this; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id((*coll), pDatabase, columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxFetchAll(qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + QSqlError err; + qx::QxCollection *coll = this; + if (relation.count() == 0) + { + err = qx::dao::fetch_all((*coll), pDatabase, columns); + } + else + { + err = qx::dao::fetch_all_with_relation(relation, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + QSqlError err; + qx::QxCollection *coll = this; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_query(query, (*coll), pDatabase, columns); + } + else + { + err = qx::dao::fetch_by_query_with_relation(relation, query, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err; + qx::QxCollection *coll = this; + if (relation.count() == 0) + { + err = qx::dao::insert((*coll), pDatabase, bUseExecBatch); + } + else + { + err = qx::dao::insert_with_relation(relation, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err; + qx::QxCollection *coll = this; + if (relation.count() == 0) + { + err = qx::dao::update_by_query(query, (*coll), pDatabase, columns, bUseExecBatch); + } + else + { + err = qx::dao::update_by_query_with_relation(relation, query, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, qx::dao::save_mode::e_save_mode eSaveRecursiveMode = qx::dao::save_mode::e_none) + { + QSqlError err; + qx::QxCollection *coll = this; + if (eSaveRecursiveMode != qx::dao::save_mode::e_none) + { + err = qx::dao::save_with_relation_recursive((*coll), eSaveRecursiveMode, pDatabase); + } + else if (relation.count() == 0) + { + err = qx::dao::save((*coll), pDatabase); + } + else + { + err = qx::dao::save_with_relation(relation, (*coll), pDatabase); + } + return err; + } + + virtual QSqlError qxDeleteById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(id); + qx::QxCollection *coll = this; + return qx::dao::delete_by_id((*coll), pDatabase, bUseExecBatch); + } + + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::delete_all(pDatabase); + } + + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::delete_by_query(query, pDatabase); + } + + virtual QSqlError qxDestroyById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(id); + qx::QxCollection *coll = this; + return qx::dao::destroy_by_id((*coll), pDatabase, bUseExecBatch); + } + + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::destroy_all(pDatabase); + } + + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::destroy_by_query(query, pDatabase); + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + qx::QxCollection *coll = this; + return qx::dao::execute_query(query, (*coll), pDatabase); + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + return qxExecuteQuery(query, pDatabase); + } + + virtual qx_bool qxExist(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(id); + qx::QxCollection *coll = this; + return qx::dao::exist((*coll), pDatabase); + } + + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) + { + qx::QxCollection *coll = this; + return qx::validate((*coll), groups); + } + + virtual std::shared_ptr qxNewPersistableCollection(bool bAsList = false) const + { + Q_UNUSED(bAsList); + std::shared_ptr coll = std::make_shared>(); + return coll; + } + + virtual qx::IxClass *qxClass() const + { + return qx::QxClass::getSingleton(); + } + +#ifndef _QX_NO_JSON + + virtual QString toJson(const QString &format = QString()) const + { + const qx::QxCollection *coll = this; + return qx::serialization::json::to_string((*coll), 1, format); + } + + virtual QJsonValue toJson_(const QString &format = QString()) const + { + const qx::QxCollection *coll = this; + return qx::cvt::to_json((*coll), format); + } + + virtual qx_bool fromJson(const QString &json, const QString &format = QString()) + { + qx::QxCollection *coll = this; + return qx::serialization::json::from_string((*coll), json, 1, format); + } + + virtual qx_bool fromJson_(const QJsonValue &json, const QString &format = QString()) + { + qx::QxCollection *coll = this; + return qx::cvt::from_json(json, (*coll), format); + } + +#endif // _QX_NO_JSON + }; + + /*! + * \ingroup QxDao + * \brief qx::QxPersistableCollectionHelper::type : return the collection type used by qx::IxPersistable interface, qx::QxPersistableCollection> + */ + template + class QxPersistableCollectionHelper + { + + private: + typedef typename qx::trait::get_primary_key::type qx_type_primary_key; + typedef std::shared_ptr qx_type_ptr; + + public: + typedef qx::QxPersistableCollection type; + typedef qx::QxCollection type_coll; + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::IxPersistableCollection) +QX_REGISTER_CLASS_NAME_TEMPLATE_3(qx::QxPersistableCollection) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(qx::QxPersistableCollectionHelper) + +#endif // _IX_PERSISTABLE_COLLECTION_H_ diff --git a/include/QxDao/IxPersistableList.h b/include/QxDao/IxPersistableList.h new file mode 100644 index 0000000..6edac02 --- /dev/null +++ b/include/QxDao/IxPersistableList.h @@ -0,0 +1,311 @@ +/**************************************************************************** +** +** 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 _IX_PERSISTABLE_LIST_H_ +#define _IX_PERSISTABLE_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxPersistableList.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface (abstract class) for list persistent classes based on qx::IxPersistable + */ + +#include +#include + +#include +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxPersistableList : concrete class for list persistent classes based on qx::IxPersistableCollection (as an array instead of key/value hash-map) + */ + template + class QxPersistableList : public qx::IxPersistableCollection + { + + enum + { + qx_is_valid = qx::trait::is_qx_registered::value + }; + + protected: + QList> m_list; //!< List of persistable instances + + public: + QxPersistableList() : qx::IxPersistableCollection() { static_assert(qx_is_valid, "qx_is_valid"); } + virtual ~QxPersistableList() { ; } + + virtual long __count() const { return static_cast(m_list.size()); } + virtual void __clear() { m_list.clear(); } + virtual bool __remove(long idx) + { + if ((idx < 0) || (idx >= static_cast(m_list.size()))) + { + return false; + } + m_list.removeAt(idx); + return true; + } + virtual qx::IxPersistable_ptr __at(long idx) const + { + if ((idx < 0) || (idx >= static_cast(m_list.size()))) + { + return qx::IxPersistable_ptr(); + } + return std::static_pointer_cast(m_list.at(idx)); + } + + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) + { + if (relation.count() == 0) + { + return qx::dao::count(query, pDatabase); + } + else + { + long lCount(0); + qx::dao::count_with_relation(lCount, relation, query, pDatabase); + return lCount; + } + } + + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL, const QStringList &relation = QStringList()) + { + if (relation.count() == 0) + { + return qx::dao::count(lCount, query, pDatabase); + } + else + { + return qx::dao::count_with_relation(lCount, relation, query, pDatabase); + } + } + + virtual QSqlError qxFetchById(const QVariant &id = QVariant(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(id); + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id(m_list, pDatabase, columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxFetchAll(qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_all(m_list, pDatabase, columns); + } + else + { + err = qx::dao::fetch_all_with_relation(relation, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_query(query, m_list, pDatabase, columns); + } + else + { + err = qx::dao::fetch_by_query_with_relation(relation, query, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::insert(m_list, pDatabase, bUseExecBatch); + } + else + { + err = qx::dao::insert_with_relation(relation, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::update_by_query(query, m_list, pDatabase, columns, bUseExecBatch); + } + else + { + err = qx::dao::update_by_query_with_relation(relation, query, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, qx::dao::save_mode::e_save_mode eSaveRecursiveMode = qx::dao::save_mode::e_none) + { + QSqlError err; + if (eSaveRecursiveMode != qx::dao::save_mode::e_none) + { + err = qx::dao::save_with_relation_recursive(m_list, eSaveRecursiveMode, pDatabase); + } + else if (relation.count() == 0) + { + err = qx::dao::save(m_list, pDatabase); + } + else + { + err = qx::dao::save_with_relation(relation, m_list, pDatabase); + } + return err; + } + + virtual QSqlError qxDeleteById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(id); + return qx::dao::delete_by_id(m_list, pDatabase, bUseExecBatch); + } + + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::delete_all(pDatabase); + } + + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::delete_by_query(query, pDatabase); + } + + virtual QSqlError qxDestroyById(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(id); + return qx::dao::destroy_by_id(m_list, pDatabase, bUseExecBatch); + } + + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::destroy_all(pDatabase); + } + + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::destroy_by_query(query, pDatabase); + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::execute_query(query, m_list, pDatabase); + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, qx::IxPersistableCollection *list = NULL, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(list); + return qxExecuteQuery(query, pDatabase); + } + + virtual qx_bool qxExist(const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(id); + return qx::dao::exist(m_list, pDatabase); + } + + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) + { + return qx::validate(m_list, groups); + } + + virtual std::shared_ptr qxNewPersistableCollection(bool bAsList = false) const + { + Q_UNUSED(bAsList); + std::shared_ptr coll = std::make_shared>(); + return coll; + } + + virtual qx::IxClass *qxClass() const + { + return qx::QxClass::getSingleton(); + } + +#ifndef _QX_NO_JSON + + virtual QString toJson(const QString &format = QString()) const + { + return qx::serialization::json::to_string(m_list, 1, format); + } + + virtual QJsonValue toJson_(const QString &format = QString()) const + { + return qx::cvt::to_json(m_list, format); + } + + virtual qx_bool fromJson(const QString &json, const QString &format = QString()) + { + return qx::serialization::json::from_string(m_list, json, 1, format); + } + + virtual qx_bool fromJson_(const QJsonValue &json, const QString &format = QString()) + { + return qx::cvt::from_json(json, m_list, format); + } + +#endif // _QX_NO_JSON + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(qx::QxPersistableList) + +#endif // _IX_PERSISTABLE_LIST_H_ diff --git a/include/QxDao/IxSqlQueryBuilder.h b/include/QxDao/IxSqlQueryBuilder.h new file mode 100644 index 0000000..075c594 --- /dev/null +++ b/include/QxDao/IxSqlQueryBuilder.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 _IX_SQL_QUERY_BUILDER_H_ +#define _IX_SQL_QUERY_BUILDER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxSqlQueryBuilder.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface to build SQL queries to communicate with database + */ + +#include + +#include +#include +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + class IxDao_Helper; + + } // namespace detail + } // namespace dao +} // namespace qx + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::IxSqlQueryBuilder : common interface to build SQL queries to communicate with database + */ + class QX_DLL_EXPORT IxSqlQueryBuilder + { + + private: + struct IxSqlQueryBuilderImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + IxSqlQueryBuilder(); + virtual ~IxSqlQueryBuilder() = 0; + + IxDataMemberX *getDataMemberX() const; + QxCollection *getLstDataMember() const; + IxSqlRelationX *getLstRelation() const; + qx::dao::detail::IxDao_Helper *getDaoHelper() const; + void setDaoHelper(qx::dao::detail::IxDao_Helper *p); + + void setHashRelation(const QString &s); + void setCartesianProduct(bool b); + QString getSqlQuery() const; + QString getHashRelation() const; + QString table() const; + QxSoftDelete getSoftDelete() const; + bool getCartesianProduct() const; + long getDataCount() const; + long getRelationCount() const; + IxDataMember *getDataId() const; + IxDataMember *nextData(long &l) const; + IxSqlRelation *nextRelation(long &l) const; + QString &getCurrentBuildingSql() const; + + void initIdX(long lAllRelationCount); + bool insertIdX(long lIndex, const QVariant &idOwner, const QVariant &idData, void *ptr); + void *existIdX(long lIndex, const QVariant &idOwner, const QVariant &idData); + void setSqlQuery(const QString &sql, const QString &key = QString()); + void addSqlQueryAlias(const QString &sql, const QString &sqlAlias); + bool getAddAutoIncrementIdToUpdateQuery() const; + void replaceSqlQueryAlias(QString &sql) const; + + virtual void init(); + virtual void clone(const IxSqlQueryBuilder &other); + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) = 0; + + static QString addSqlCondition(const QString &sql) { return (sql.contains(" WHERE ") ? " AND " : " WHERE "); } + + static void sql_CreateTable(QString &sql, IxSqlQueryBuilder &builder); + static void sql_DeleteById(QString &sql, IxSqlQueryBuilder &builder, bool bSoftDelete); + static void sql_Exist(QString &sql, IxSqlQueryBuilder &builder); + static void sql_FetchAll(QString &sql, IxSqlQueryBuilder &builder); + static void sql_FetchAll(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns); + static void sql_FetchAll_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder); + static void sql_FetchById(QString &sql, IxSqlQueryBuilder &builder); + static void sql_FetchById(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns); + static void sql_FetchById_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder); + static void sql_Insert(QString &sql, IxSqlQueryBuilder &builder); + static void sql_Update(QString &sql, IxSqlQueryBuilder &builder); + static void sql_Update(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns); + static void sql_Count_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder); + + static void resolveOutput_FetchAll(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder); + static void resolveOutput_FetchAll(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder, const QStringList &columns); + static void resolveOutput_FetchAll_WithRelation(qx::QxSqlRelationLinked *pRelationX, void *t, QSqlQuery &query, IxSqlQueryBuilder &builder); + + static void resolveInput_Insert(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder); + static void resolveInput_Update(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder); + static void resolveInput_Update(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder, const QStringList &columns); + static void resolveInput_DeleteById(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder); + + protected: + bool verifyColumns(const QStringList &columns) const QX_USED; + + bool isInitDone() const; + QxSoftDelete &softDelete(); + const QxSoftDelete &softDelete() const; + void setSoftDelete(const QxSoftDelete &o); + void setDataMemberX(IxDataMemberX *p); + bool findSqlQuery(const QString &key); + bool findSqlAlias(const QString &key); + void insertSqlAlias(const QString &key); + }; + + typedef std::shared_ptr IxSqlQueryBuilder_ptr; + +} // namespace qx + +#include + +#endif // _IX_SQL_QUERY_BUILDER_H_ diff --git a/include/QxDao/IxSqlRelation.h b/include/QxDao/IxSqlRelation.h new file mode 100644 index 0000000..81225f2 --- /dev/null +++ b/include/QxDao/IxSqlRelation.h @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** 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 _IX_SQL_RELATION_H_ +#define _IX_SQL_RELATION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxSqlRelation.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface for all relationships defined between 2 classes (or between 2 tables in database) + */ + +#include + +#include +#include +#include + +#include + +namespace qx +{ + + class IxClass; + class IxDataMember; + class IxDataMemberX; + class IxSqlRelation; + + typedef QxCollection IxSqlRelationX; + typedef std::shared_ptr IxSqlRelationX_ptr; + + /*! + * \ingroup QxDao + * \brief qx::IxSqlRelation : common interface for all relationships defined between 2 classes (or between 2 tables in database) + */ + class QX_DLL_EXPORT IxSqlRelation : public qx::QxPropertyBag + { + + private: + struct IxSqlRelationImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + enum relation_type + { + no_relation, + one_to_one, + one_to_many, + many_to_one, + many_to_many + }; + + IxSqlRelation(IxDataMember *p); + virtual ~IxSqlRelation() = 0; + + QxCollection *getLstDataMember() const; + IxSqlRelationX *getLstRelation() const; + + void setSqlJoinType(qx::dao::sql_join::join_type e); + qx::dao::sql_join::join_type getSqlJoinType() const; + relation_type getRelationType() const; + IxClass *getClass() const; + IxClass *getClassOwner() const; + IxDataMember *getDataMember() const; + IxDataMemberX *getDataMemberX() const; + IxDataMember *getDataId() const; + IxDataMember *getDataIdOwner() const; + + void linkRelationKeyTo(IxDataMember *p); + IxDataMember *getLinkRelationKey() const; + + QString getKey() const; + QString getForeignKey() const; + QString getForeignKeyOwner() const; + QString getForeignKeyDataType() const; + QString getExtraTable() const; + long getDataCount() const; + long getRelationCount() const; + IxDataMember *getDataByKey(const QString &sKey) const; + IxDataMember *nextData(long &lIndex) const; + IxSqlRelation *nextRelation(long &lIndex) const; + QString table() const; + QString tableAlias(QxSqlRelationParams ¶ms) const; + QString tableAliasOwner(QxSqlRelationParams ¶ms) const; + QString getSqlJoin(qx::dao::sql_join::join_type e = qx::dao::sql_join::no_join) const; + bool traceSqlQuery() const; + + virtual void init(); + virtual QString getDescription() const = 0; + virtual QString createExtraTable() const = 0; + virtual bool getCartesianProduct() const = 0; + virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const = 0; + virtual void updateOffset(bool bEager, QxSqlRelationParams ¶ms) const = 0; + virtual void createTable(QxSqlRelationParams ¶ms) const = 0; + virtual void lazySelect(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerSelect(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyFrom(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerFrom(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyJoin(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerJoin(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyWhere(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerWhere(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyWhereSoftDelete(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerWhereSoftDelete(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyFetch_ResolveInput(QxSqlRelationParams ¶ms) const = 0; + virtual void eagerFetch_ResolveInput(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyFetch_ResolveOutput(QxSqlRelationParams ¶ms) const = 0; + virtual void *eagerFetch_ResolveOutput(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyInsert(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyInsert_Values(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyUpdate(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyInsert_ResolveInput(QxSqlRelationParams ¶ms) const = 0; + virtual void lazyUpdate_ResolveInput(QxSqlRelationParams ¶ms) const = 0; + virtual QSqlError onBeforeSave(QxSqlRelationParams ¶ms) const = 0; + virtual QSqlError onAfterSave(QxSqlRelationParams ¶ms) const = 0; + + bool verifyOffset(QxSqlRelationParams ¶ms, bool bId) const QX_USED; + + static void setTraceRelationInit(bool bTrace); + + protected: + QVariant getIdFromQuery_ManyToMany(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const; + QVariant getIdFromQuery_ManyToOne(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const; + QVariant getIdFromQuery_OneToMany(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const; + QVariant getIdFromQuery_OneToOne(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const; + + void updateOffset_ManyToMany(bool bEager, QxSqlRelationParams ¶ms) const; + void updateOffset_ManyToOne(bool bEager, QxSqlRelationParams ¶ms) const; + void updateOffset_OneToMany(bool bEager, QxSqlRelationParams ¶ms) const; + void updateOffset_OneToOne(bool bEager, QxSqlRelationParams ¶ms) const; + + void eagerSelect_ManyToMany(QxSqlRelationParams ¶ms) const; + void eagerSelect_ManyToOne(QxSqlRelationParams ¶ms) const; + void eagerSelect_OneToMany(QxSqlRelationParams ¶ms) const; + void eagerSelect_OneToOne(QxSqlRelationParams ¶ms) const; + + void eagerJoin_ManyToMany(QxSqlRelationParams ¶ms) const; + void eagerJoin_ManyToOne(QxSqlRelationParams ¶ms) const; + void eagerJoin_OneToMany(QxSqlRelationParams ¶ms) const; + void eagerJoin_OneToOne(QxSqlRelationParams ¶ms) const; + + void eagerWhereSoftDelete_ManyToMany(QxSqlRelationParams ¶ms) const; + void eagerWhereSoftDelete_ManyToOne(QxSqlRelationParams ¶ms) const; + void eagerWhereSoftDelete_OneToMany(QxSqlRelationParams ¶ms) const; + void eagerWhereSoftDelete_OneToOne(QxSqlRelationParams ¶ms) const; + + void lazySelect_ManyToOne(QxSqlRelationParams ¶ms) const; + void lazyInsert_ManyToOne(QxSqlRelationParams ¶ms) const; + void lazyInsert_Values_ManyToOne(QxSqlRelationParams ¶ms) const; + void lazyUpdate_ManyToOne(QxSqlRelationParams ¶ms) const; + + void createTable_ManyToOne(QxSqlRelationParams ¶ms) const; + QSqlError deleteFromExtraTable_ManyToMany(QxSqlRelationParams ¶ms) const; + QString createExtraTable_ManyToMany() const; + + bool addLazyRelation(QxSqlRelationParams ¶ms, IxSqlRelation *pRelation) const; + + bool canInit() const; + void setIsSameDataOwner(int i); + void setClass(IxClass *pClass, IxClass *pClassOwner); + void setRelationType(relation_type e); + void setForeignKey(const QString &s) const; + void setForeignKeyOwner(const QString &s) const; + void setForeignKeyDataType(const QString &s) const; + void setExtraTable(const QString &s) const; + }; + +} // namespace qx + +#endif // _IX_SQL_RELATION_H_ diff --git a/include/QxDao/QxDao.h b/include/QxDao/QxDao.h new file mode 100644 index 0000000..bc531d0 --- /dev/null +++ b/include/QxDao/QxDao.h @@ -0,0 +1,938 @@ +/**************************************************************************** +** +** 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_H_ +#define _QX_DAO_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDao.h + * \author XDL Team + * \ingroup QxDao + * \brief Provide template functions to map C++ class registered into QxOrm context with table database (ORM - Object Relational Mapping) + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace qx +{ + class QxSqlRelationParams; + namespace dao + { + + namespace detail + { + class IxDao_Helper; + template + struct QxDao_Count; + template + struct QxDao_Count_WithRelation; + template + struct QxDao_FetchById; + template + struct QxDao_FetchById_WithRelation; + template + struct QxDao_FetchAll; + template + struct QxDao_FetchAll_WithRelation; + template + struct QxDao_Insert; + template + struct QxDao_Insert_WithRelation; + template + struct QxDao_Update; + template + struct QxDao_Update_Optimized; + template + struct QxDao_Update_WithRelation; + template + struct QxDao_Save; + template + struct QxDao_Save_WithRelation; + template + struct QxDao_Save_WithRelation_Recursive; + template + struct QxDao_DeleteById; + template + struct QxDao_DeleteAll; + template + struct QxDao_Exist; + template + struct QxDao_CreateTable; + template + struct QxDao_Trigger; + template + struct QxDao_ExecuteQuery; + } // namespace detail + + /*! + * \ingroup QxDao + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * + * qx::dao::count() execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + WHERE my_query... + */ + template + inline long count(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Count::count(query, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * + * qx::dao::count() execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + WHERE my_query... + */ + template + inline QSqlError count(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Count::count(lCount, query, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query (with possibility to add relations to SQL query) + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * + * qx::dao::count_with_relation() execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + XXX_JOINS_XXX + WHERE my_query... + */ + template + inline QSqlError count_with_relation(long &lCount, const QStringList &relation, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Count_WithRelation::count(lCount, relation, query, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert an element or a list of elements into database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance inserting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::insert() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline QSqlError insert(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_Insert::insert(t, pDatabase, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element or a list of elements into database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::save() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError save(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Save::save(t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Delete a line (or list of lines) of a table (database) mapped to a C++ object of type T (registered into QxOrm context) + * \param t Element (or list of elements) to be deleted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance deleting a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::delete_by_id() execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ?
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::delete_by_id() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' WHERE my_id = ? + */ + template + inline QSqlError delete_by_id(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_DeleteById::deleteById(t, pDatabase, true, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Destroy a line (or list of lines) of a table (database) mapped to a C++ object of type T (registered into QxOrm context), even if a soft delete behavior is defined for class T + * \param t Element (or list of elements) to be destroyed into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance destroying a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::destroy_by_id() execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ? + */ + template + inline QSqlError destroy_by_id(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_DeleteById::deleteById(t, pDatabase, false, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::delete_all() execute following SQL query :
+ * DELETE FROM my_table
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::delete_all() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + */ + template + inline QSqlError delete_all(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_DeleteAll::deleteAll("", pDatabase, true); + } + + /*! + * \ingroup QxDao + * \brief Destroy all lines of a table (database) mapped to a C++ class T (registered into QxOrm context), even if a soft delete behavior is defined for class T + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::destroy_all() execute following SQL query :
+ * DELETE FROM my_table + */ + template + inline QSqlError destroy_all(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_DeleteAll::deleteAll("", pDatabase, false); + } + + /*! + * \ingroup QxDao + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::delete_by_query() execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query...
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::delete_by_query() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + WHERE my_query... + */ + template + inline QSqlError delete_by_query(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_DeleteAll::deleteAll(query, pDatabase, true); + } + + /*! + * \ingroup QxDao + * \brief Destroy all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query, even if a soft delete behavior is defined for class T + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::destroy_by_query() execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query... + */ + template + inline QSqlError destroy_by_query(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_DeleteAll::deleteAll(query, pDatabase, false); + } + + /*! + * \ingroup QxDao + * \brief Create a table into database (with all columns) mapped to a C++ class T (registered into QxOrm context) : be careful, this function can be used only with a SQLite database to create examples or prototypes; For other databases, it is recommended to use QxEntityEditor application or to manage the database schema with an external tool provided by the SGBD (SQLite Manager for SQLite, pgAdmin for PostgreSQL, MySQL Workbench for MySQL, etc...) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::create_table() execute following SQL query :
+ * CREATE TABLE my_table (my_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, my_column_1 TEXT, my_column_2 TEXT, etc.) + */ + template + inline QSqlError create_table(QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_CreateTable::createTable(pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Search if an element (or list of elements) already exists into database + * \param t Element (or list of elements) to be searched into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Return true if element already exists into database; otherwise return false; if an error occurred, qx_bool object contains a description of database error executing SQL query + * + * qx::dao::exist() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline qx_bool exist(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Exist::exist(t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_id_with_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline QSqlError fetch_by_id_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchById_WithRelation::fetchById(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_id_with_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline QSqlError fetch_by_id_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchById_WithRelation::fetchById(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties and relationships) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param t Instance (with a valid id) to be fetched (retrieve all properties and relationships from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_id_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline QSqlError fetch_by_id_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchById_WithRelation::fetchById("*", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_all_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline QSqlError fetch_all_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_all_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline QSqlError fetch_all_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties + all relationships associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param t Container to be fetched (retrieve all elements and properties + all relationships associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_all_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline QSqlError fetch_all_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll("*", "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_query_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline QSqlError fetch_by_query_with_relation(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_query_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline QSqlError fetch_by_query_with_relation(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties + all relationships associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties + all relationships associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_query_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline QSqlError fetch_by_query_with_all_relation(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll("*", query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::insert_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline QSqlError insert_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Insert_WithRelation::insert(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted in others tables of database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::insert_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline QSqlError insert_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Insert_WithRelation::insert(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::insert_with_all_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline QSqlError insert_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Insert_WithRelation::insert("*", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError update_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update(relation, "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param relation List of relationships keys to be updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_by_query_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline QSqlError update_by_query_with_relation(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update(relation, query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be updated in others tables of database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError update_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update(relation, "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param relation List of relationships keys to be updated in others tables of database + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_by_query_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline QSqlError update_by_query_with_relation(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update(relation, query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_with_all_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError update_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update("*", "", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Update an element and all its relationships (or a list of elements + all relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_by_query_with_all_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline QSqlError update_by_query_with_all_relation(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Update_WithRelation::update("*", query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted or updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::save_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError save_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Save_WithRelation::save(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted or updated in others tables of database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::save_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError save_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Save_WithRelation::save(relation, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::save_with_all_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError save_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_Save_WithRelation::save("*", t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) recursively an element and all levels of relationships (or a list of elements + all levels of relationships) into database, useful to save a tree structure for example + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param eSaveMode To improve performance, use this parameter to indicate if you just want to insert or update all elements in database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param pRelationParams Keep this parameter as NULL, it is used internally by QxOrm library to iterate over each level of relationship + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::save_with_relation_recursive() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc.
+ *
+ * Note : to improve performance, and if you know that you are just inserting or updating items in database, you can use the parameter eSaveMode :
+ * - qx::dao::save_mode::e_check_insert_or_update : check before saving if item already exists in database ;
+ * - qx::dao::save_mode::e_insert_only : only insert items in database (use only 1 SQL query to insert collection of items) ;
+ * - qx::dao::save_mode::e_update_only : only update items in database (use only 1 SQL query to update collection of items). + */ + template + inline QSqlError save_with_relation_recursive(T &t, qx::dao::save_mode::e_save_mode eSaveMode = qx::dao::save_mode::e_check_insert_or_update, QSqlDatabase *pDatabase = NULL, qx::QxSqlRelationParams *pRelationParams = NULL) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive::save(t, eSaveMode, pDatabase, pRelationParams); + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_id() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline QSqlError fetch_by_id(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + return qx::dao::detail::QxDao_FetchById::fetchById(t, pDatabase, columns); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_all() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline QSqlError fetch_all(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + return qx::dao::detail::QxDao_FetchAll::fetchAll("", t, pDatabase, columns); + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::fetch_by_query() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline QSqlError fetch_by_query(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + return qx::dao::detail::QxDao_FetchAll::fetchAll(query, t, pDatabase, columns); + } + + /*! + * \ingroup QxDao + * \brief Update an element or a list of elements into database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be updated (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError update(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList(), bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_Update::update("", t, pDatabase, columns, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Update an element or a list of elements into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be updated (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_by_query() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline QSqlError update_by_query(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList(), bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_Update::update(query, t, pDatabase, columns, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Update only modified fields/properties of an element or a list of elements into database (using is dirty pattern and qx::dao::ptr smart-pointer) + * \param ptr Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_optimized() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline QSqlError update_optimized(qx::dao::ptr &ptr, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_Update_Optimized::update_optimized("", ptr, pDatabase, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Update only modified fields/properties of an element or a list of elements into database (using is dirty pattern and qx::dao::ptr smart-pointer), adding a user SQL query to the default SQL query builded by QxOrm library + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param ptr Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + * + * qx::dao::update_optimized_by_query() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline QSqlError update_optimized_by_query(const qx::QxSqlQuery &query, qx::dao::ptr &ptr, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + return qx::dao::detail::QxDao_Update_Optimized::update_optimized(query, ptr, pDatabase, bUseExecBatch); + } + + /*! + * \ingroup QxDao + * \brief Execute a custom SQL query or a stored procedure, all columns that can be mapped to the instance of type T will be fetched automatically + * \param query Define a custom SQL query or a stored procedure to call + * \param t Instance of type T, all columns that can be mapped to this instance will be fetched automatically + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + template + inline QSqlError execute_query(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + return qx::dao::detail::QxDao_ExecuteQuery::executeQuery(query, t, pDatabase); + } + + /*! + * \ingroup QxDao + * \brief Callback before inserting an object into database (here is an example using QxOrm Trigger) + */ + template + inline void on_before_insert(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onBeforeInsert(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback before updating an object into database (here is an example using QxOrm Trigger) + */ + template + inline void on_before_update(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onBeforeUpdate(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback before deleting an object into database (here is an example using QxOrm Trigger) + */ + template + inline void on_before_delete(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onBeforeDelete(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback before fetching an object from database (here is an example using QxOrm Trigger) + */ + template + inline void on_before_fetch(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onBeforeFetch(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback after inserting an object into database (here is an example using QxOrm Trigger) + */ + template + inline void on_after_insert(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onAfterInsert(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback after updating an object into database (here is an example using QxOrm Trigger) + */ + template + inline void on_after_update(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onAfterUpdate(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback after deleting an object into database (here is an example using QxOrm trigger) + */ + template + inline void on_after_delete(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onAfterDelete(t, dao); + } + + /*! + * \ingroup QxDao + * \brief Callback after fetching an object from database (here is an example using QxOrm trigger) + */ + template + inline void on_after_fetch(T *t, qx::dao::detail::IxDao_Helper *dao) + { + qx::dao::detail::QxDao_Trigger::onAfterFetch(t, dao); + } + + } // namespace dao +} // namespace qx + +#endif // _QX_DAO_H_ diff --git a/include/QxDao/QxDaoAsync.h b/include/QxDao/QxDaoAsync.h new file mode 100644 index 0000000..830aee3 --- /dev/null +++ b/include/QxDao/QxDaoAsync.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** 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_ASYNC_H_ +#define _QX_DAO_ASYNC_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDaoAsync.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to execute SQL queries in another thread (asynchronous way) using qx::IxPersistable interface + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#include + +#ifndef Q_MOC_RUN +#include +#include +#endif // Q_MOC_RUN + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxDaoAsyncParams : all parameters for qx::QxDaoAsync class to execute queries + */ + struct QxDaoAsyncParams + { + + enum dao_action + { + dao_none, + dao_count, + dao_fetch_by_id, + dao_fetch_all, + dao_fetch_by_query, + dao_insert, + dao_update, + dao_save, + dao_delete_by_id, + dao_delete_all, + dao_delete_by_query, + dao_destroy_by_id, + dao_destroy_all, + dao_destroy_by_query, + dao_execute_query, + dao_call_query + }; + + dao_action daoAction; //!< Action to execute into the thread (asynchronous way) + QString className; //!< Classname parameter to execute action (must implement qx::IxPersistable interface) + qx::QxSqlQuery query; //!< Query parameter to execute action + QSqlDatabase *pDatabase; //!< Database parameter to execute action + IxPersistable_ptr pInstance; //!< Current instance parameter to execute action + IxPersistableCollection_ptr pListOfInstances; //!< List of instances fetched by query + QStringList listColumns; //!< List of columns parameter to execute action + QStringList listRelations; //!< List of relationships parameter to execute action + QVariant id; //!< Current instance id parameter to execute action + long daoCount; //!< Dao count value returned by qx::dao::count query + bool useExecBatch; //!< If true then use the QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + + QxDaoAsyncParams() : daoAction(dao_none), pDatabase(NULL), daoCount(0), useExecBatch(false) { ; } + ~QxDaoAsyncParams() { ; } + }; + + typedef std::shared_ptr QxDaoAsyncParams_ptr; + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxDaoAsyncRunner : class with a slot to execute queries in another thread + */ + class QX_DLL_EXPORT QxDaoAsyncRunner : public QObject + { + + Q_OBJECT + + public: + QxDaoAsyncRunner(); + virtual ~QxDaoAsyncRunner(); + + protected: + QSqlError runQuery(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + + Q_SIGNALS: + + void queryFinished(const QSqlError &daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + + public Q_SLOTS: + + void onQueryStarted(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + }; + + } // namespace detail + } // namespace dao + + /*! + * \ingroup QxDao + * \brief qx::QxDaoAsync : helper class to execute SQL queries in another thread (asynchronous way) using qx::IxPersistable interface + * + * To use qx::QxDaoAsync helper class : + * 1- be careful to work only with classes implementing qx::IxPersistable interface ; + * 2- create an instance of qx::QxDaoAsync type (for example, a property of a QWidget derived class) ; + * 3- connect a SLOT to the qx::QxDaoAsync::queryFinished() SIGNAL (for example, a SLOT of a QWidget derived class) ; + * 4- run a query using one of qx::QxDaoAsync::asyncXXXX() methods. + * + * For example, with a MyWidget class : + * \code + class MyWidget : public QWidget + { + Q_OBJECT + //... + qx::QxDaoAsync m_daoAsync; + //... + Q_SLOTS: + void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + //... + }; + * \endcode + * And here is the implementation of MyWidget class : + * \code + MyWidget::MyWidget() : QObject() + { + //... + QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr))); + //... + } + void MyWidget::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams) + { + if (! pDaoParams) { return; } + qx::QxSqlQuery query = pDaoParams->query; + if (! daoError.isValid()) { ; } + // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method + qx::IxPersistable_ptr ptr = pDaoParams->pInstance; + // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method + qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances; + //... + } + * \endcode + */ + class QX_DLL_EXPORT QxDaoAsync : public QThread + { + + Q_OBJECT + + protected: + QMutex m_mutex; //!< Mutex => qx::QxDaoAsync is thread-safe + qx::dao::detail::QxDaoAsyncParams_ptr m_pDaoParams; //!< Parameters to execute query + + public: + QxDaoAsync(); + virtual ~QxDaoAsync(); + + bool asyncCount(const QString &className, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL); + bool asyncFetchById(IxPersistable_ptr pToFetch, const QVariant &id = QVariant(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncFetchAll(const QString &className, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncFetchByQuery(const QString &className, const qx::QxSqlQuery &query, const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncInsert(IxPersistable_ptr pToInsert, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncUpdate(IxPersistable_ptr pToUpdate, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncSave(IxPersistable_ptr pToSave, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL); + bool asyncDeleteById(IxPersistable_ptr pToDelete, const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL); + bool asyncDeleteAll(const QString &className, QSqlDatabase *pDatabase = NULL); + bool asyncDeleteByQuery(const QString &className, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + bool asyncDestroyById(IxPersistable_ptr pToDestroy, const QVariant &id = QVariant(), QSqlDatabase *pDatabase = NULL); + bool asyncDestroyAll(const QString &className, QSqlDatabase *pDatabase = NULL); + bool asyncDestroyByQuery(const QString &className, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + bool asyncExecuteQuery(const QString &className, qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + bool asyncCallQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + + bool isQueryRunning() const { return (m_pDaoParams.get() != NULL); } + + protected: + virtual void run(); + + void startQuery(); + + Q_SIGNALS: + + void queryStarted(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + void queryFinished(const QSqlError &daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + + private Q_SLOTS: + + void onQueryFinished(const QSqlError &daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + }; + + typedef std::shared_ptr QxDaoAsync_ptr; + +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::dao::detail::QxDaoAsyncParams &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::dao::detail::QxDaoAsyncParams &t) QX_USED; + +#endif // _QX_DAO_ASYNC_H_ diff --git a/include/QxDao/QxDaoPointer.h b/include/QxDao/QxDaoPointer.h new file mode 100644 index 0000000..e84f604 --- /dev/null +++ b/include/QxDao/QxDaoPointer.h @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** 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_ diff --git a/include/QxDao/QxDaoStrategy.h b/include/QxDao/QxDaoStrategy.h new file mode 100644 index 0000000..caef20c --- /dev/null +++ b/include/QxDao/QxDaoStrategy.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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_STRATEGY_H_ +#define _QX_DAO_STRATEGY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDaoStrategy.h + * \author XDL Team + * \ingroup QxDao + * \brief Class inheritance strategy and database (Concrete Table Inheritance is the default strategy used by QxOrm library) + */ + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief qx::dao::strategy : class inheritance strategy and database (Concrete Table Inheritance is the default strategy used by QxOrm library) + * + * With ORM tools, there is usually 3 strategies to manage inheritance and database : + * - Single Table Inheritance + * - Class Table Inheritance + * - Concrete Table Inheritance + * + * QxOrm works by default with Concrete Table Inheritance strategy (others are not supported yet). + * Many tutorials and forums are available on internet to more details about ORM inheritance and database. + * You can find a sample in the directory ./test/qxDllSample/dll2/ with the class BaseClassTrigger. + */ + struct strategy + { + + enum inheritance + { + single_table_inheritance, + class_table_inheritance, + concrete_table_inheritance + }; + }; + + } // namespace dao +} // namespace qx + +#endif // _QX_DAO_STRATEGY_H_ diff --git a/include/QxDao/QxDaoThrowable.h b/include/QxDao/QxDaoThrowable.h new file mode 100644 index 0000000..d9272a2 --- /dev/null +++ b/include/QxDao/QxDaoThrowable.h @@ -0,0 +1,955 @@ +/**************************************************************************** +** +** 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_THROWABLE_H_ +#define _QX_DAO_THROWABLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDaoThrowable.h + * \author XDL Team + * \ingroup QxDao + * \brief Same functions as qx::dao namespace, but throw a qx::dao::sql_error exception when a SQL error occurred (instead of returning a QSqlError instance) + */ + +#include +#include + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief Same functions as qx::dao namespace, but throw a qx::dao::sql_error exception when a SQL error occurred (instead of returning a QSqlError instance) + */ + namespace throwable + { + + /// @cond TO_AVOID_DOXYGEN_WARNINGS + + /*! + * \ingroup QxDao + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * + * qx::dao::throwable::count() execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + WHERE my_query... + */ + template + inline void count(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Count::count(lCount, query, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query (with possibility to add relations to SQL query) + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * + * qx::dao::throwable::count_with_relation() execute following SQL query :
+ * SELECT COUNT(*) FROM my_table + XXX_JOINS_XXX + WHERE my_query... + */ + template + inline void count_with_relation(long &lCount, const QStringList &relation, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Count_WithRelation::count(lCount, relation, query, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert an element or a list of elements into database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance inserting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::insert() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline void insert(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_Insert::insert(t, pDatabase, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element or a list of elements into database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::save() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void save(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Save::save(t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Delete a line (or list of lines) of a table (database) mapped to a C++ object of type T (registered into QxOrm context) + * \param t Element (or list of elements) to be deleted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance deleting a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::delete_by_id() execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ?
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::throwable::delete_by_id() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' WHERE my_id = ? + */ + template + inline void delete_by_id(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_DeleteById::deleteById(t, pDatabase, true, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Destroy a line (or list of lines) of a table (database) mapped to a C++ object of type T (registered into QxOrm context), even if a soft delete behavior is defined for class T + * \param t Element (or list of elements) to be destroyed into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance destroying a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::destroy_by_id() execute following SQL query :
+ * DELETE FROM my_table WHERE my_id = ? + */ + template + inline void destroy_by_id(T &t, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_DeleteById::deleteById(t, pDatabase, false, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::delete_all() execute following SQL query :
+ * DELETE FROM my_table
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::throwable::delete_all() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + */ + template + inline void delete_all(QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_DeleteAll::deleteAll("", pDatabase, true); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Destroy all lines of a table (database) mapped to a C++ class T (registered into QxOrm context), even if a soft delete behavior is defined for class T + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::destroy_all() execute following SQL query :
+ * DELETE FROM my_table + */ + template + inline void destroy_all(QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_DeleteAll::deleteAll("", pDatabase, false); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::delete_by_query() execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query...
+ *
+ * If a soft delete behavior is defined for class T, qx::dao::throwable::delete_by_query() execute following SQL query :
+ * UPDATE my_table SET is_deleted='1' + WHERE my_query... + */ + template + inline void delete_by_query(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_DeleteAll::deleteAll(query, pDatabase, true); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Destroy all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query, even if a soft delete behavior is defined for class T + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::destroy_by_query() execute following SQL query :
+ * DELETE FROM my_table + WHERE my_query... + */ + template + inline void destroy_by_query(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_DeleteAll::deleteAll(query, pDatabase, false); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Create a table into database (with all columns) mapped to a C++ class T (registered into QxOrm context) : be careful, this function can be used only with a SQLite database to create examples or prototypes; For other databases, it is recommended to use QxEntityEditor application or to manage the database schema with an external tool provided by the SGBD (SQLite Manager for SQLite, pgAdmin for PostgreSQL, MySQL Workbench for MySQL, etc...) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::create_table() execute following SQL query :
+ * CREATE TABLE my_table (my_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, my_column_1 TEXT, my_column_2 TEXT, etc.) + */ + template + inline void create_table(QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_CreateTable::createTable(pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_id_with_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline void fetch_by_id_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchById_WithRelation::fetchById(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_id_with_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline void fetch_by_id_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchById_WithRelation::fetchById(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties and relationships) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param t Instance (with a valid id) to be fetched (retrieve all properties and relationships from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_id_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline void fetch_by_id_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchById_WithRelation::fetchById("*", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_all_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline void fetch_all_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_all_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline void fetch_all_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties + all relationships associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param t Container to be fetched (retrieve all elements and properties + all relationships associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_all_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline void fetch_all_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll("*", "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_query_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline void fetch_by_query_with_relation(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_query_with_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline void fetch_by_query_with_relation(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll(relation, query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties + all relationships associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties + all relationships associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_query_with_all_relation() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline void fetch_by_query_with_all_relation(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll_WithRelation::fetchAll("*", query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::insert_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline void insert_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Insert_WithRelation::insert(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted in others tables of database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::insert_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline void insert_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Insert_WithRelation::insert(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be inserted into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::insert_with_all_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + */ + template + inline void insert_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Insert_WithRelation::insert("*", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void update_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update(relation, "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param relation List of relationships keys to be updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_by_query_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline void update_by_query_with_relation(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update(relation, query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be updated in others tables of database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void update_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update(relation, "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and its relationships (or a list of elements + relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param relation List of relationships keys to be updated in others tables of database + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_by_query_with_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline void update_by_query_with_relation(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update(relation, query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_with_all_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void update_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update("*", "", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element and all its relationships (or a list of elements + all relationships) into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_by_query_with_all_relation() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline void update_by_query_with_all_relation(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Update_WithRelation::update("*", query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted or updated in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::save_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void save_with_relation(const QString &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Save_WithRelation::save(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and its relationships (or a list of elements + relationships) into database + * \param relation List of relationships keys to be inserted or updated in others tables of database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::save_with_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void save_with_relation(const QStringList &relation, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Save_WithRelation::save(relation, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) an element and all its relationships (or a list of elements + all relationships) into database + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::save_with_all_relation() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void save_with_all_relation(T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Save_WithRelation::save("*", t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Insert (if no exist) or update (if already exist) recursively an element and all levels of relationships (or a list of elements + all levels of relationships) into database, useful to save a tree structure for example + * \param t Element (or list of elements) to be inserted (if no exist) or updated (if already exist) into database + * \param eSaveMode To improve performance, use this parameter to indicate if you just want to insert or update all elements in database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param pRelationParams Keep this parameter as NULL, it is used internally by QxOrm library to iterate over each level of relationship + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::save_with_relation_recursive() execute following SQL query :
+ * INSERT INTO my_table (my_column_1, my_column_2, etc.) VALUES (?, ?, etc.) + *
or (if already exist into database) :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc.
+ *
+ * Note : to improve performance, and if you know that you are just inserting or updating items in database, you can use the parameter eSaveMode :
+ * - qx::dao::save_mode::e_check_insert_or_update : check before saving if item already exists in database ;
+ * - qx::dao::save_mode::e_insert_only : only insert items in database (use only 1 SQL query to insert collection of items) ;
+ * - qx::dao::save_mode::e_update_only : only update items in database (use only 1 SQL query to update collection of items). + */ + template + inline void save_with_relation_recursive(T &t, qx::dao::save_mode::e_save_mode eSaveMode = qx::dao::save_mode::e_check_insert_or_update, QSqlDatabase *pDatabase = NULL, qx::QxSqlRelationParams *pRelationParams = NULL) + { + QSqlError err = qx::dao::detail::QxDao_Save_WithRelation_Recursive::save(t, eSaveMode, pDatabase, pRelationParams); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch an object t (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database (t must have a valid id before to be fetched without error) + * \param t Instance (with a valid id) to be fetched (retrieve all properties from database) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_id() execute following SQL query :
+ * SELECT * FROM my_table WHERE my_id = ? + */ + template + inline void fetch_by_id(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + QSqlError err = qx::dao::detail::QxDao_FetchById::fetchById(t, pDatabase, columns); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_all() execute following SQL query :
+ * SELECT * FROM my_table + */ + template + inline void fetch_all(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll::fetchAll("", t, pDatabase, columns); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Container to be fetched (retrieve all elements and properties associated); t is cleared before executing SQL query + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be fetched (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::fetch_by_query() execute following SQL query :
+ * SELECT * FROM my_table + WHERE my_query... + */ + template + inline void fetch_by_query(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList()) + { + QSqlError err = qx::dao::detail::QxDao_FetchAll::fetchAll(query, t, pDatabase, columns); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element or a list of elements into database + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be updated (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void update(T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList(), bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_Update::update("", t, pDatabase, columns, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update an element or a list of elements into database (adding a user SQL query to the default SQL query builded by QxOrm library) + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param t Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param columns List of database table columns (mapped to properties of C++ class T) to be updated (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_by_query() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline void update_by_query(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL, const QStringList &columns = QStringList(), bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_Update::update(query, t, pDatabase, columns, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update only modified fields/properties of an element or a list of elements into database (using is dirty pattern and qx::dao::ptr smart-pointer) + * \param ptr Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_optimized() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + */ + template + inline void update_optimized(qx::dao::ptr &ptr, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_Update_Optimized::update_optimized("", ptr, pDatabase, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Update only modified fields/properties of an element or a list of elements into database (using is dirty pattern and qx::dao::ptr smart-pointer), adding a user SQL query to the default SQL query builded by QxOrm library + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param ptr Element (or list of elements) to be updated into database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + * + * qx::dao::throwable::update_optimized_by_query() execute following SQL query :
+ * UPDATE my_table SET my_column_1 = ?, my_column_2 = ?, etc. + WHERE my_query... + */ + template + inline void update_optimized_by_query(const qx::QxSqlQuery &query, qx::dao::ptr &ptr, QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::detail::QxDao_Update_Optimized::update_optimized(query, ptr, pDatabase, bUseExecBatch); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /*! + * \ingroup QxDao + * \brief Execute a custom SQL query or a stored procedure, all columns that can be mapped to the instance of type T will be fetched automatically + * \param query Define a custom SQL query or a stored procedure to call + * \param t Instance of type T, all columns that can be mapped to this instance will be fetched automatically + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Throw a qx::dao::sql_error exception when a SQL error occurred + */ + template + inline void execute_query(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::detail::QxDao_ExecuteQuery::executeQuery(query, t, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + inline void call_query(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + QSqlError err = qx::dao::call_query(query, pDatabase); + if (err.isValid()) + { + throw qx::dao::sql_error(err); + } + } + + /// @endcond + + } // namespace throwable + } // namespace dao +} // namespace qx + +#endif // _QX_DAO_THROWABLE_H_ diff --git a/include/QxDao/QxDao_Impl.h b/include/QxDao/QxDao_Impl.h new file mode 100644 index 0000000..24b9808 --- /dev/null +++ b/include/QxDao/QxDao_Impl.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_IMPL_H_ +#define _QX_DAO_IMPL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _QX_ENABLE_MONGODB +#include +#ifndef _QX_NO_JSON +#include +#include +#endif // _QX_NO_JSON +#endif // _QX_ENABLE_MONGODB + +#include "../../inl/QxDao/QxDao_Helper.inl" +#include "../../inl/QxDao/QxDao_Count.inl" +#include "../../inl/QxDao/QxDao_FetchById.inl" +#include "../../inl/QxDao/QxDao_FetchById_WithRelation.inl" +#include "../../inl/QxDao/QxDao_FetchAll.inl" +#include "../../inl/QxDao/QxDao_FetchAll_WithRelation.inl" +#include "../../inl/QxDao/QxDao_Insert.inl" +#include "../../inl/QxDao/QxDao_Insert_WithRelation.inl" +#include "../../inl/QxDao/QxDao_Update.inl" +#include "../../inl/QxDao/QxDao_Update_Optimized.inl" +#include "../../inl/QxDao/QxDao_Update_WithRelation.inl" +#include "../../inl/QxDao/QxDao_Save.inl" +#include "../../inl/QxDao/QxDao_Save_WithRelation.inl" +#include "../../inl/QxDao/QxDao_Save_WithRelation_Recursive.inl" +#include "../../inl/QxDao/QxDao_DeleteById.inl" +#include "../../inl/QxDao/QxDao_DeleteAll.inl" +#include "../../inl/QxDao/QxDao_Exist.inl" +#include "../../inl/QxDao/QxDao_CreateTable.inl" +#include "../../inl/QxDao/QxDao_Trigger.inl" +#include "../../inl/QxDao/QxDao_ExecuteQuery.inl" + +#endif // _QX_DAO_IMPL_H_ diff --git a/include/QxDao/QxDao_IsDirty.h b/include/QxDao/QxDao_IsDirty.h new file mode 100644 index 0000000..230b471 --- /dev/null +++ b/include/QxDao/QxDao_IsDirty.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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_IS_DIRTY_H_ +#define _QX_DAO_IS_DIRTY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include +#include + +#include +#include +#include +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + inline void is_dirty(const T &obj1, const T &obj2, QStringList &lstDiff); + + template + struct QxDao_IsDirty_Generic + { + + static void compare(const T &obj1, const T &obj2, QStringList &lstDiff) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + + qx::QxSqlQueryBuilder_Count builder; + builder.init(); + qx::IxDataMember *pId = builder.getDataId(); + if (pId && (!pId->isEqual((&obj1), (&obj2)))) + { + lstDiff.append(pId->getKey()); + } + + long l = 0; + qx::IxDataMember *p = NULL; + while ((p = builder.nextData(l))) + { + if (p && (!p->isEqual((&obj1), (&obj2)))) + { + lstDiff.append(p->getKey()); + } + } + } + }; + + template + struct QxDao_IsDirty_Container + { + + static void compare(const T &obj1, const T &obj2, QStringList &lstDiff) + { + if (qx::trait::generic_container::size(obj1) <= 0) + { + return; + } + if (qx::trait::generic_container::size(obj1) != qx::trait::generic_container::size(obj2)) + { + lstDiff.append("*"); + return; + } + + long lCurrIndex = 0; + typename T::const_iterator it2 = obj2.begin(); + + for (typename T::const_iterator it1 = obj1.begin(); it1 != obj1.end(); ++it1) + { + QStringList lstDiffItem; + qx::dao::detail::is_dirty((*it1), (*it2), lstDiffItem); + if (lstDiffItem.count() > 0) + { + lstDiff.append(QString::number(lCurrIndex) + "|" + lstDiffItem.join("|")); + } + ++lCurrIndex; + ++it2; + } + } + }; + + template + struct QxDao_IsDirty_Ptr + { + + static void compare(const T &obj1, const T &obj2, QStringList &lstDiff) + { + qx::dao::detail::is_dirty((*obj1), (*obj2), lstDiff); + } + }; + + template + struct QxDao_IsDirty + { + + static void compare(const T &obj1, const T &obj2, QStringList &lstDiff) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_IsDirty_Ptr, qx::dao::detail::QxDao_IsDirty_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_IsDirty_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_IsDirty_Container, type_dao_2>::type type_dao_3; + type_dao_3::compare(obj1, obj2, lstDiff); + } + }; + + template + inline void is_dirty(const T &obj1, const T &obj2, QStringList &lstDiff) + { + return qx::dao::detail::QxDao_IsDirty::compare(obj1, obj2, lstDiff); + } + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_DAO_IS_DIRTY_H_ diff --git a/include/QxDao/QxDateNeutral.h b/include/QxDao/QxDateNeutral.h new file mode 100644 index 0000000..c15725b --- /dev/null +++ b/include/QxDao/QxDateNeutral.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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_DATE_NEUTRAL_H_ +#define _QX_DATE_NEUTRAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDateNeutral.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to store a date value into database under neutral format (YYYYMMDD) => cross database compatibility + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include + +#include + +#include + +namespace qx +{ + class QxDateNeutral; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxDateNeutral &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxDateNeutral &t) QX_USED; + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxDateNeutral : helper class to store a date value into database under neutral format (YYYYMMDD) => cross database compatibility + */ + class QxDateNeutral + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxDateNeutral &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxDateNeutral &t); + + private: + QDate m_date; //!< Data value under QDate format from Qt library + QString m_neutral; //!< Data value under neutral format 'yyyyMMdd' + + public: + QxDateNeutral() { ; } + explicit QxDateNeutral(const QDate &date) : m_date(date) { update(); } + explicit QxDateNeutral(const QString &neutral) : m_neutral(neutral) { update(); } + virtual ~QxDateNeutral() { ; } + + inline QDate toDate() const { return m_date; } + inline QString toNeutral() const { return m_neutral; } + inline bool isValid() const { return m_date.isValid(); } + + inline void setDate(const QDate &date) + { + m_neutral = ""; + m_date = date; + update(); + } + inline void setNeutral(const QString &neutral) + { + m_date = QDate(); + m_neutral = neutral; + update(); + } + + static QxDateNeutral fromDate(const QDate &date) { return QxDateNeutral(date); } + static QxDateNeutral fromNeutral(const QString &neutral) { return QxDateNeutral(neutral); } + + private: + static inline const char *format() { return "yyyyMMdd"; } + + void update() + { + if (m_neutral.isEmpty() && !m_date.isValid()) + { + return; + } + else if (m_date.isValid()) + { + m_neutral = m_date.toString(format()); + } + else + { + qAssert(m_neutral.size() == QString(format()).size()); + m_date = QDate::fromString(m_neutral, format()); + qAssert(m_date.isValid()); + } + } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("date_neutral", m_neutral); + if (Archive::is_loading::value) + { + m_date = QDate(); + update(); + } + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::QxDateNeutral) + +#endif // _QX_DATE_NEUTRAL_H_ diff --git a/include/QxDao/QxDateTimeNeutral.h b/include/QxDao/QxDateTimeNeutral.h new file mode 100644 index 0000000..1f487a3 --- /dev/null +++ b/include/QxDao/QxDateTimeNeutral.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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_DATE_TIME_NEUTRAL_H_ +#define _QX_DATE_TIME_NEUTRAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDateTimeNeutral.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to store a date-time value into database under neutral format (YYYYMMDDHHMMSS) => cross database compatibility + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include + +#include + +#include + +namespace qx +{ + class QxDateTimeNeutral; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxDateTimeNeutral &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxDateTimeNeutral &t) QX_USED; + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxDateTimeNeutral : helper class to store a date-time value into database under neutral format (YYYYMMDDHHMMSS) => cross database compatibility + */ + class QxDateTimeNeutral + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxDateTimeNeutral &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxDateTimeNeutral &t); + + private: + QDateTime m_dt; //!< Data value under QDateTime format from Qt library + QString m_neutral; //!< Data value under neutral format 'yyyyMMddhhmmss' + + public: + QxDateTimeNeutral() { ; } + explicit QxDateTimeNeutral(const QDateTime &dt) : m_dt(dt) { update(); } + explicit QxDateTimeNeutral(const QString &neutral) : m_neutral(neutral) { update(); } + virtual ~QxDateTimeNeutral() { ; } + + inline QDateTime toDateTime() const { return m_dt; } + inline QString toNeutral() const { return m_neutral; } + inline bool isValid() const { return m_dt.isValid(); } + + inline void setDateTime(const QDateTime &dt) + { + m_neutral = ""; + m_dt = dt; + update(); + } + inline void setNeutral(const QString &neutral) + { + m_dt = QDateTime(); + m_neutral = neutral; + update(); + } + + static QxDateTimeNeutral fromDateTime(const QDateTime &dt) { return QxDateTimeNeutral(dt); } + static QxDateTimeNeutral fromNeutral(const QString &neutral) { return QxDateTimeNeutral(neutral); } + + private: + static inline const char *format() { return "yyyyMMddhhmmss"; } + + void update() + { + if (m_neutral.isEmpty() && !m_dt.isValid()) + { + return; + } + else if (m_dt.isValid()) + { + m_neutral = m_dt.toString(format()); + } + else + { + qAssert(m_neutral.size() == QString(format()).size()); + m_dt = QDateTime::fromString(m_neutral, format()); + qAssert(m_dt.isValid()); + } + } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("dt_neutral", m_neutral); + if (Archive::is_loading::value) + { + m_dt = QDateTime(); + update(); + } + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::QxDateTimeNeutral) + +#endif // _QX_DATE_TIME_NEUTRAL_H_ diff --git a/include/QxDao/QxMongoDB/QxMongoDB_Helper.h b/include/QxDao/QxMongoDB/QxMongoDB_Helper.h new file mode 100644 index 0000000..d4e671b --- /dev/null +++ b/include/QxDao/QxMongoDB/QxMongoDB_Helper.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_MONGODB +#ifndef _QX_DAO_MONGODB_HELPER_H_ +#define _QX_DAO_MONGODB_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxMongoDB_Helper.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to store all QxOrm registered classes in a MongoDB database : qx::QxSqlDatabase::getSingleton()->setDriverName("QXMONGODB"); + */ + +#include + +#include + +namespace qx +{ + + class IxClass; + class QxSqlQuery; + +} // namespace qx + +namespace qx +{ + namespace dao + { + namespace detail + { + + class IxDao_Helper; + + } // namespace detail + } // namespace dao +} // namespace qx + +namespace qx +{ + namespace dao + { + namespace mongodb + { + + struct QxMongoDB_Fetcher; + + /*! + * \ingroup QxDao + * \brief qx::dao::mongodb::QxMongoDB_Helper : helper class to store all QxOrm registered classes in a MongoDB database : qx::QxSqlDatabase::getSingleton()->setDriverName("QXMONGODB"); + */ + class QX_DLL_EXPORT QxMongoDB_Helper : public QxSingleton + { + + friend class QxSingleton; + + public: + enum opts + { + opts_collection_insert_one, + opts_collection_insert_many, + opts_collection_update_one, + opts_collection_update_many, + opts_collection_delete_one, + opts_collection_delete_many, + opts_collection_find, + opts_collection_command, + opts_collection_count, + opts_collection_create_bulk_operation, + opts_bulk_operation_update_one, + opts_bulk_operation_remove_one, + opts_collection_aggregate + }; + + private: + struct QxMongoDB_HelperImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + QxMongoDB_Helper(); + virtual ~QxMongoDB_Helper(); + + public: + static QSqlError insertOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, QString &insertedId); + static QSqlError insertMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, QStringList &insertedId); + static QSqlError updateOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query = NULL); + static QSqlError updateMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query = NULL); + static QSqlError deleteOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query = NULL); + static QSqlError deleteMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query = NULL); + static QSqlError findOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QString &json, const qx::QxSqlQuery *query = NULL); + static QSqlError findMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query = NULL, QxMongoDB_Fetcher *pFetcher = NULL); + static QSqlError aggregate(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query = NULL, const QString &lookup = QString(), QxMongoDB_Fetcher *pFetcher = NULL); + static QSqlError count(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, long &cnt, const qx::QxSqlQuery *query = NULL); + static QSqlError executeCommand(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, qx::QxSqlQuery *query); + + static QSqlError autoCreateIndexes(bool log = true); + static bool setOptions(opts e, const QString &optsAsJson); + static void setLogDatabaseReply(bool b); + static void setLogDatabaseInfo(bool b); + static void clearPoolConnection(); + }; + + /*! + * \ingroup QxDao + * \brief qx::dao::mongodb::QxMongoDB_Fetcher : used to fetch a list of items from MongoDB database without having to put them in a buffer before fetching + */ + struct QX_DLL_EXPORT QxMongoDB_Fetcher + { + + QxMongoDB_Fetcher(); + virtual ~QxMongoDB_Fetcher(); + + virtual void fetch(const QString &json) = 0; + }; + + } // namespace mongodb + } // namespace dao +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::dao::mongodb::QxMongoDB_Helper) + +#endif // _QX_DAO_MONGODB_HELPER_H_ +#endif // _QX_ENABLE_MONGODB diff --git a/include/QxDao/QxRepository/IxRepository.h b/include/QxDao/QxRepository/IxRepository.h new file mode 100644 index 0000000..1286b2e --- /dev/null +++ b/include/QxDao/QxRepository/IxRepository.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** 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 _IX_REPOSITORY_H_ +#define _IX_REPOSITORY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxRepository.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface for all repositories to provide access to database by introspection using QObject class or qx::IxCollection class + */ + +#include +#include +#include +#include + +#include + +#include + +#include + +namespace qx +{ + + class IxClass; + class QxSession; + + /*! + * \ingroup QxDao + * \brief qx::IxRepository : common interface for all repositories to provide access to database by introspection using QObject class or qx::IxCollection class + * + * There is a type verification at runtime using dynamic_cast function. + * For example, if you are working with a class named MyType, you can call all methods of qx::IxRepository interface using : + * - MyType * for a single object, if MyType inherits from QObject ; + * - qx::QxCollection< Key, QSharedPointer > * for a list of objects, where Key is the primary key type defined for MyType class (long by default). + * + * Note : if a bad type is detected at runtime, an exception of type qx::dao::sql_error is thrown. + */ + class QX_DLL_EXPORT IxRepository + { + + protected: + bool m_bRegister; //!< Register repository into QxRepositoryX collection + QString m_sKeyRepository; //!< Repository key used by QxRepositoryX collection + QSqlDatabase m_database; //!< Database connection associated to the repository + QxSession *m_pSession; //!< Session associated to the repository + + public: + IxRepository(bool bRegister, const QString &sKey); + IxRepository(bool bRegister, const QString &sKey, const QSqlDatabase &database); + IxRepository(bool bRegister, const QString &sKey, QxSession *pSession); + virtual ~IxRepository(); + + QSqlDatabase *database(); + QxSession *session() const; + + virtual long _count(const qx::QxSqlQuery &query = qx::QxSqlQuery()) = 0; + virtual void *_fetchById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchById(QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchById(qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchAll(QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchAll(qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchByQuery(const qx::QxSqlQuery &query, QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _fetchByQuery(const qx::QxSqlQuery &query, qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _insert(QObject *p, const QStringList &relation = QStringList()) = 0; + virtual QSqlError _insert(qx::IxCollection *p, const QStringList &relation = QStringList()) = 0; + virtual QSqlError _update(QObject *p, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _update(qx::IxCollection *p, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) = 0; + virtual QSqlError _save(QObject *p, const QStringList &relation = QStringList()) = 0; + virtual QSqlError _save(qx::IxCollection *p, const QStringList &relation = QStringList()) = 0; + virtual QSqlError _deleteById(const QVariant &id) = 0; + virtual QSqlError _deleteById(QObject *p) = 0; + virtual QSqlError _deleteById(qx::IxCollection *p) = 0; + virtual QSqlError _deleteAll() = 0; + virtual QSqlError _deleteByQuery(const qx::QxSqlQuery &query) = 0; + virtual QSqlError _destroyById(const QVariant &id) = 0; + virtual QSqlError _destroyById(QObject *p) = 0; + virtual QSqlError _destroyById(qx::IxCollection *p) = 0; + virtual QSqlError _destroyAll() = 0; + virtual QSqlError _destroyByQuery(const qx::QxSqlQuery &query) = 0; + virtual qx_bool _exist(QObject *p) = 0; + virtual qx_bool _exist(qx::IxCollection *p) = 0; + virtual qx::IxCollection_ptr _newCollection() const = 0; + virtual qx::IxClass *_getClass() const = 0; + + public: + static qx::IxCollection_ptr _fetchAll(const QString &repositoryKey, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()); + static qx::IxCollection_ptr _fetchByQuery(const QString &repositoryKey, const qx::QxSqlQuery &query, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()); + }; + +} // namespace qx + +#endif // _IX_REPOSITORY_H_ diff --git a/include/QxDao/QxRepository/QxRepository.h b/include/QxDao/QxRepository/QxRepository.h new file mode 100644 index 0000000..510d9bc --- /dev/null +++ b/include/QxDao/QxRepository/QxRepository.h @@ -0,0 +1,606 @@ +/**************************************************************************** +** +** 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_REPOSITORY_H_ +#define _QX_REPOSITORY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxRepository.h + * \author XDL Team + * \ingroup QxDao + * \brief Repository to provide a common interface to communicate with database + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#define QX_REPOSITORY_COLLECTION_DYNAMIC_CAST_ERROR QSqlError("[QxOrm] qx::QxRepository : 'invalid collection pointer, dynamic_cast failed'", "", QSqlError::UnknownError) +#define QX_REPOSITORY_POINTER_DYNAMIC_CAST_ERROR QSqlError("[QxOrm] qx::QxRepository : 'invalid pointer, dynamic_cast failed'", "", QSqlError::UnknownError) +#define QX_REPOSITORY_QOBJECT_BASE_CLASS_ERROR QSqlError("[QxOrm] qx::QxRepository : 'invalid pointer, need to inherit from QObject class to use qx::IxRepository interface'", "", QSqlError::UnknownError) + +#ifndef _QX_NO_RTTI +#define QX_REPOSITORY_CAST_COLLECTION \ + type_collection_qt *x = dynamic_cast(p); \ + type_collection_boost *y = (x ? NULL : dynamic_cast(p)); \ + if (!x && !y) \ + { \ + throw qx::dao::sql_error(QX_REPOSITORY_COLLECTION_DYNAMIC_CAST_ERROR); \ + } +#else // _QX_NO_RTTI +#define QX_REPOSITORY_CAST_COLLECTION \ + type_collection_qt *x = NULL; \ + type_collection_boost *y = static_cast(p); +#endif // _QX_NO_RTTI + +namespace qx +{ + + template + inline void register_repository(const QString &sKey); + + /*! + * \ingroup QxDao + * \brief qx::QxRepository : repository to provide a common interface to communicate with database + */ + template + class QxRepository : public IxRepository + { + + template + friend inline void register_repository(const QString &sKey); + + private: + QxRepository(const QString &sKey) : IxRepository(true, sKey) { ; } + + public: + QxRepository() : IxRepository(false, QString("")) { ; } + QxRepository(const QSqlDatabase &database) : IxRepository(false, QString(""), database) { ; } + QxRepository(QxSession *pSession) : IxRepository(false, QString(""), pSession) { ; } + virtual ~QxRepository() { ; } + + long count(const qx::QxSqlQuery &query = qx::QxSqlQuery()) + { + return qx::dao::count(query, this->database()); + } + + T *fetchById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return NULL; + } + T *t = new T(); + QSqlError err; + pDataMemberId->fromVariant(t, id, -1, qx::cvt::context::e_database); + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id((*t), this->database(), columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, (*t), this->database()); + } + if (err.isValid() && m_pSession) + { + delete t; + t = NULL; + (*m_pSession) += err; + } + else if (err.isValid()) + { + delete t; + t = NULL; + } + return t; + } + + template + QSqlError fetchById(U &u, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id(u, this->database(), columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError fetchAll(U &u, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_all(u, this->database(), columns); + } + else + { + err = qx::dao::fetch_all_with_relation(relation, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError fetchByQuery(const qx::QxSqlQuery &query, U &u, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_query(query, u, this->database(), columns); + } + else + { + err = qx::dao::fetch_by_query_with_relation(relation, query, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError insert(U &u, const QStringList &relation = QStringList(), bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::insert(u, this->database(), bUseExecBatch); + } + else + { + err = qx::dao::insert_with_relation(relation, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError update(U &u, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::update_by_query(query, u, this->database(), columns, bUseExecBatch); + } + else + { + err = qx::dao::update_by_query_with_relation(relation, query, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError save(U &u, const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::save(u, this->database()); + } + else + { + err = qx::dao::save_with_relation(relation, u, this->database()); + } + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError deleteById(const QVariant &id) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return QSqlError(); + } + std::shared_ptr t = std::make_shared(); + pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database); + QSqlError err = qx::dao::delete_by_id((*t), this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError deleteById(U &u, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::delete_by_id(u, this->database(), bUseExecBatch); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError deleteAll() + { + QSqlError err = qx::dao::delete_all(this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError deleteByQuery(const qx::QxSqlQuery &query) + { + QSqlError err = qx::dao::delete_by_query(query, this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError destroyById(const QVariant &id) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return QSqlError(); + } + std::shared_ptr t = std::make_shared(); + pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database); + QSqlError err = qx::dao::destroy_by_id((*t), this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + QSqlError destroyById(U &u, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::destroy_by_id(u, this->database(), bUseExecBatch); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError destroyAll() + { + QSqlError err = qx::dao::destroy_all(this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + QSqlError destroyByQuery(const qx::QxSqlQuery &query) + { + QSqlError err = qx::dao::destroy_by_query(query, this->database()); + if (err.isValid() && m_pSession) + { + (*m_pSession) += err; + } + return err; + } + + template + qx_bool exist(U &u) + { + return qx::dao::exist(u, this->database()); + } + + private: + typedef typename qx::trait::get_primary_key::type type_primary_key; + typedef qx::QxCollection> type_collection_qt; + typedef qx::QxCollection> type_collection_boost; + + template + struct qxVerifyPointer + { + static inline T *get(QObject *p) + { + Q_UNUSED(p); + throw qx::dao::sql_error(QX_REPOSITORY_QOBJECT_BASE_CLASS_ERROR); + return NULL; + } + }; + + template + struct qxVerifyPointer +#ifdef _QX_NO_RTTI + { + static inline T *get(QObject *p) + { + T *t = qobject_cast(p); + if (!t) + { + throw qx::dao::sql_error(QX_REPOSITORY_POINTER_DYNAMIC_CAST_ERROR); + }; + return t; + } + }; +#else // _QX_NO_RTTI + { + static inline T *get(QObject *p) + { + T *t = dynamic_cast(p); + if (!t) + { + throw qx::dao::sql_error(QX_REPOSITORY_POINTER_DYNAMIC_CAST_ERROR); + }; + return t; + } + }; +#endif // _QX_NO_RTTI + + public: + virtual long _count(const qx::QxSqlQuery &query = qx::QxSqlQuery()) + { + return this->count(query); + } + + virtual void *_fetchById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + return static_cast(this->fetchById(id, columns, relation)); + } + + virtual QSqlError _fetchById(QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->fetchById((*t), columns, relation); + } + + virtual QSqlError _fetchById(qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->fetchById((*x), columns, relation) : this->fetchById((*y), columns, relation)); + } + + virtual QSqlError _fetchAll(QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->fetchAll((*t), columns, relation); + } + + virtual QSqlError _fetchAll(qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->fetchAll((*x), columns, relation) : this->fetchAll((*y), columns, relation)); + } + + virtual QSqlError _fetchByQuery(const qx::QxSqlQuery &query, QObject *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->fetchByQuery(query, (*t), columns, relation); + } + + virtual QSqlError _fetchByQuery(const qx::QxSqlQuery &query, qx::IxCollection *p, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->fetchByQuery(query, (*x), columns, relation) : this->fetchByQuery(query, (*y), columns, relation)); + } + + virtual QSqlError _insert(QObject *p, const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->insert((*t), relation); + } + + virtual QSqlError _insert(qx::IxCollection *p, const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->insert((*x), relation) : this->insert((*y), relation)); + } + + virtual QSqlError _update(QObject *p, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->update((*t), query, columns, relation); + } + + virtual QSqlError _update(qx::IxCollection *p, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->update((*x), query, columns, relation) : this->update((*y), query, columns, relation)); + } + + virtual QSqlError _save(QObject *p, const QStringList &relation = QStringList()) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->save((*t), relation); + } + + virtual QSqlError _save(qx::IxCollection *p, const QStringList &relation = QStringList()) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->save((*x), relation) : this->save((*y), relation)); + } + + virtual QSqlError _deleteById(const QVariant &id) + { + return this->deleteById(id); + } + + virtual QSqlError _deleteById(QObject *p) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->deleteById(*t); + } + + virtual QSqlError _deleteById(qx::IxCollection *p) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->deleteById(*x) : this->deleteById(*y)); + } + + virtual QSqlError _deleteAll() + { + return this->deleteAll(); + } + + virtual QSqlError _deleteByQuery(const qx::QxSqlQuery &query) + { + return this->deleteByQuery(query); + } + + virtual QSqlError _destroyById(const QVariant &id) + { + return this->destroyById(id); + } + + virtual QSqlError _destroyById(QObject *p) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->destroyById(*t); + } + + virtual QSqlError _destroyById(qx::IxCollection *p) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->destroyById(*x) : this->destroyById(*y)); + } + + virtual QSqlError _destroyAll() + { + return this->destroyAll(); + } + + virtual QSqlError _destroyByQuery(const qx::QxSqlQuery &query) + { + return this->destroyByQuery(query); + } + + virtual qx_bool _exist(QObject *p) + { + T *t = qxVerifyPointer::value, 0>::get(p); + return this->exist(*t); + } + + virtual qx_bool _exist(qx::IxCollection *p) + { + QX_REPOSITORY_CAST_COLLECTION + return (x ? this->exist(*x) : this->exist(*y)); + } + + virtual qx::IxCollection_ptr _newCollection() const + { + qx::IxCollection_ptr lst = std::make_shared(); + return lst; + } + + virtual qx::IxClass *_getClass() const + { + return qx::QxClass::getSingleton(); + } + + public: + static T *getById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return NULL; + } + T *t = new T(); + QSqlError err; + pDataMemberId->fromVariant(t, id, -1, qx::cvt::context::e_database); + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id((*t), NULL, columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, (*t), NULL); + } + if (err.isValid()) + { + delete t; + t = NULL; + } + return t; + } + }; + + template + inline void register_repository(const QString &sKey) + { + // 'pNewRepository' instance will be destroyed by 'qx::QxRepositoryX::unregisterRepository()' method + qx::QxRepository *pNewRepository = new qx::QxRepository(sKey); + Q_UNUSED(pNewRepository); + } + +} // namespace qx + +#endif // _QX_REPOSITORY_H_ diff --git a/include/QxDao/QxRepository/QxRepositoryX.h b/include/QxDao/QxRepository/QxRepositoryX.h new file mode 100644 index 0000000..d9bb42d --- /dev/null +++ b/include/QxDao/QxRepository/QxRepositoryX.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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_REPOSITORY_X_H_ +#define _QX_REPOSITORY_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxRepositoryX.h + * \author XDL Team + * \ingroup QxDao + * \brief List of all repositories registered using qx::register_repository function + */ + +#include +#include + +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxRepositoryX : list of all repositories registered using qx::register_repository function + * + * Note : you can register automatically all repositories using the macro _QX_AUTO_REGISTER_REPOSITORY into QxConfig.h file. + */ + class QX_DLL_EXPORT QxRepositoryX : public QxSingleton + { + + friend class IxRepository; + friend class QxSingleton; + + protected: + QHash m_mapRepositoryX; //!< Collection of all 'IxRepository' pointer + QMutex m_oMutexRepositoryX; //!< Mutex -> 'QxRepositoryX' is thread-safe + bool m_bUnregisterAllRepository; //!< Flag to know if collection is clearing + + private: + QxRepositoryX() : QxSingleton("qx::QxRepositoryX"), m_bUnregisterAllRepository(false) { ; } + virtual ~QxRepositoryX() { unregisterAllRepository(); } + + void registerRepository(const QString &sKey, IxRepository *pRepository); + void unregisterRepository(const QString &sKey); + void unregisterAllRepository(); + + public: + static IxRepository *get(const QString &sKey); + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxRepositoryX) + +#endif // _QX_REPOSITORY_X_H_ diff --git a/include/QxDao/QxSession.h b/include/QxDao/QxSession.h new file mode 100644 index 0000000..791072d --- /dev/null +++ b/include/QxDao/QxSession.h @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** 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_SESSION_H_ +#define _QX_DAO_SESSION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSession.h + * \author XDL Team + * \ingroup QxDao + * \brief Define a session to manage automatically database transactions (using C++ RAII) + */ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSession : define a session to manage automatically database transactions (using C++ RAII) + * + * A database transaction is a sequence of operations performed as a single logical unit of work. + * If no errors occurred during the execution of the transaction then the system commits the transaction. + * If an error occurs during the transaction, or if the user specifies a rollback operation, the data manipulations within the transaction are not persisted to the database. + * + * The qx::QxSession class of QxOrm library is designed to manage automatically database transactions (using C++ RAII) : + * \code + { // Start a scope where a new session is instantiated + + // Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened + qx::QxSession session; + + // Execute some operations with database (using += operator of qx::QxSession class and session database connexion) + session += qx::dao::insert(my_object, session.database()); + session += qx::dao::update(my_object, session.database()); + session += qx::dao::fetch_by_id(my_object, session.database()); + session += qx::dao::delete_by_id(my_object, session.database()); + + // If the session is not valid (so an error occured) => display first error + if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); } + + } // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error) + * \endcode + * + * Note : a session can throw a qx::dao::sql_error exception when a SQL error occured (by default, there is no exception). + * You can setup this feature using : + * - qx::QxSession constructor (for a specific session) ; + * - qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b) parameter (for all sessions). + * + * Other note : don't forget to pass the session database connexion to each qx::dao::xxx functions (using session.database() method). + * Moreover, you can manage your own database connexion (from a connexion pool for example) using constructor of qx::QxSession class. + * + * qx::QxSession class provides also persistent methods (CRUD) to make easier to write C++ code. + * Here is the same example using methods of qx::QxSession class instead of functions into namespace qx::dao : + * \code + { // Start a scope where a new session is instantiated + + // Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened + qx::QxSession session; + + // Execute some operations with database + session.insert(my_object); + session.update(my_object); + session.fetchById(my_object); + session.deleteById(my_object); + + // If the session is not valid (so an error occured) => display first error + if (! session.isValid()) { qDebug("[QxOrm] session error : '%s'", qPrintable(session.firstError().text())); } + + } // End of scope : session is destroyed (transaction => automatically commit or rollback if there is an error) + * \endcode + */ + class QX_DLL_EXPORT QxSession + { + + private: + struct QxSessionImpl; + std::shared_ptr m_pImpl; //!< Private implementation idiom (use std::shared_ptr instead of std::unique_ptr because of incomplete type) + + public: + QxSession(); + QxSession(const QSqlDatabase &database); + QxSession(const QSqlDatabase &database, bool bOpenTransaction); + QxSession(const QSqlDatabase &database, bool bOpenTransaction, bool bThrowable, bool bAutoRollbackWhenDestroyed = false); + virtual ~QxSession(); + + bool isThrowable() const; + bool isOpened() const; + bool isValid() const; + bool isAutoRollbackWhenDestroyed() const; + void setAutoRollbackWhenDestroyed(bool b); + QSqlError firstError() const; + QSqlError lastError() const; + QList allErrors() const; + const QSqlDatabase *database() const; + QSqlDatabase *database(); + + bool open(); + bool close(); + bool commit(); + bool rollback(); + + QxSession &operator+=(const QSqlError &err); + + static QxSession *getActiveSession(QSqlDatabase *db); + + void ignoreSoftDelete(bool bIgnoreSoftDelete = true, const QStringList &classesToIgnore = QStringList()); + bool checkIgnoreSoftDelete(const QString &classKey) const; + QString getIgnoreSoftDeleteHash() const; + + template + long count(const qx::QxSqlQuery &query = qx::QxSqlQuery()) + { + return qx::dao::count(query, this->database()); + } + + template + QSqlError count(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery()) + { + return qx::dao::count(lCount, query, this->database()); + } + + template + T *fetchById(const QVariant &id, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return NULL; + } + T *t = new T(); + QSqlError err; + pDataMemberId->fromVariant(t, id, -1, qx::cvt::context::e_database); + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id((*t), this->database(), columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, (*t), this->database()); + } + if (err.isValid()) + { + delete t; + t = NULL; + (*this) += err; + } + return t; + } + + template + QSqlError fetchById(T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_id(t, this->database(), columns); + } + else + { + err = qx::dao::fetch_by_id_with_relation(relation, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError fetchAll(T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_all(t, this->database(), columns); + } + else + { + err = qx::dao::fetch_all_with_relation(relation, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError fetchByQuery(const qx::QxSqlQuery &query, T &t, const QStringList &columns = QStringList(), const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::fetch_by_query(query, t, this->database(), columns); + } + else + { + err = qx::dao::fetch_by_query_with_relation(relation, query, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError insert(T &t, const QStringList &relation = QStringList(), bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::insert(t, this->database(), bUseExecBatch); + } + else + { + err = qx::dao::insert_with_relation(relation, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError update(T &t, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &columns = QStringList(), const QStringList &relation = QStringList(), bool bUseExecBatch = false) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::update_by_query(query, t, this->database(), columns, bUseExecBatch); + } + else + { + err = qx::dao::update_by_query_with_relation(relation, query, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError save(T &t, const QStringList &relation = QStringList()) + { + QSqlError err; + if (relation.count() == 0) + { + err = qx::dao::save(t, this->database()); + } + else + { + err = qx::dao::save_with_relation(relation, t, this->database()); + } + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError deleteById(const QVariant &id) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return QSqlError(); + } + std::shared_ptr t = std::make_shared(); + pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database); + QSqlError err = qx::dao::delete_by_id((*t), this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError deleteById(T &t, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::delete_by_id(t, this->database(), bUseExecBatch); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError deleteAll() + { + QSqlError err = qx::dao::delete_all(this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError deleteByQuery(const qx::QxSqlQuery &query) + { + QSqlError err = qx::dao::delete_by_query(query, this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError destroyById(const QVariant &id) + { + IxDataMemberX *pDataMemberX = QxClass::getSingleton()->getDataMemberX(); + IxDataMember *pDataMemberId = (pDataMemberX ? pDataMemberX->getId_WithDaoStrategy() : NULL); + if (!pDataMemberId) + { + qAssert(false); + return QSqlError(); + } + std::shared_ptr t = std::make_shared(); + pDataMemberId->fromVariant(t.get(), id, -1, qx::cvt::context::e_database); + QSqlError err = qx::dao::destroy_by_id((*t), this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError destroyById(T &t, bool bUseExecBatch = false) + { + QSqlError err = qx::dao::destroy_by_id(t, this->database(), bUseExecBatch); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError destroyAll() + { + QSqlError err = qx::dao::destroy_all(this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError destroyByQuery(const qx::QxSqlQuery &query) + { + QSqlError err = qx::dao::destroy_by_query(query, this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + QSqlError executeQuery(qx::QxSqlQuery &query, T &t) + { + QSqlError err = qx::dao::execute_query(query, t, this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + QSqlError callQuery(qx::QxSqlQuery &query) + { + QSqlError err = qx::dao::call_query(query, this->database()); + if (err.isValid()) + { + (*this) += err; + } + return err; + } + + template + qx_bool exist(T &t) + { + return qx::dao::exist(t, this->database()); + } + + private: + QxSession(const QxSession &other) { Q_UNUSED(other); } + QxSession &operator=(const QxSession &other) + { + Q_UNUSED(other); + return (*this); + } + }; + +} // namespace qx + +#endif // _QX_DAO_SESSION_H_ diff --git a/include/QxDao/QxSoftDelete.h b/include/QxDao/QxSoftDelete.h new file mode 100644 index 0000000..a5eb5a6 --- /dev/null +++ b/include/QxDao/QxSoftDelete.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** 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_SOFT_DELETE_H_ +#define _QX_SOFT_DELETE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSoftDelete.h + * \author XDL Team + * \ingroup QxDao + * \brief Soft delete (or logical delete) behavior to update a row into database (flag it as deleted) instead of delete it from database + */ + +#define QX_DAO_SOFT_DELETE_QDATETIME_FORMAT "yyyyMMddhhmmsszzz" + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSoftDelete : soft delete (or logical delete) behavior to update a row into database (flag it as deleted) instead of delete it from database + * + * A soft delete doesn't remove rows from database (this is not a physical delete) : a new column is added to the table definition to flag a row as deleted or not. + * This column can contain a boolean (1 means row deleted, 0 or NULL means row not deleted), or can contain deletion date-time (if empty or NULL, row is not deleted). + * So you can reactivate a deleted row by setting NULL or empty value into database. + * + * To define a soft delete behavior with QxOrm library, you have to use the class qx::QxSoftDelete in function mapping by class qx::register_class. + * Here is an example with the class Bar containing 2 properties m_id and m_desc : + * \code + namespace qx { + template <> void register_class(QxClass & t) + { + t.setSoftDelete(qx::QxSoftDelete("deleted_at")); + + t.id(& Bar::m_id, "id"); + t.data(& Bar::m_desc, "desc"); + }} + * \endcode + * + * SQL queries builded by QxOrm library will take into account this soft delete parameter to add conditions (don't fetch deleted item, don't delete physically a row, etc.). + * For example, if you execute this code with the class Bar : + * \code + Bar_ptr pBar; pBar.reset(new Bar()); + pBar->setId(5); + QSqlError daoError = qx::dao::delete_by_id(pBar); qAssert(! daoError.isValid()); + qx_bool bDaoExist = qx::dao::exist(pBar); qAssert(! bDaoExist); + daoError = qx::dao::delete_all(); qAssert(! daoError.isValid()); + long lBarCount = qx::dao::count(); qAssert(lBarCount == 0); + daoError = qx::dao::destroy_all(); qAssert(! daoError.isValid()); + * \endcode + * + * You will obtain following output trace : + * \code + [QxOrm] sql query (93 ms) : UPDATE Bar SET deleted_at = '20110617115148615' WHERE id = :id + [QxOrm] sql query (0 ms) : SELECT Bar.id AS Bar_id_0, Bar.deleted_at FROM Bar WHERE Bar.id = :id AND (Bar.deleted_at IS NULL OR Bar.deleted_at = '') + [QxOrm] sql query (78 ms) : UPDATE Bar SET deleted_at = '20110617115148724' + [QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM Bar WHERE (Bar.deleted_at IS NULL OR Bar.deleted_at = '') + [QxOrm] sql query (110 ms) : DELETE FROM Bar + * \endcode + * + * Note : To delete physically a row from database, you have to use followings functions : qx::dao::destroy_by_id() and qx::dao::destroy_all(). + * + * Other note : it is recommended to define into database an index on column deleted_at to optimize execution of SQL queries. + */ + class QX_DLL_EXPORT QxSoftDelete + { + + public: + enum mode + { + mode_flag, + mode_date_time + }; + + private: + QString m_sTable; //!< Table name where soft delete behavior is applied + QString m_sColumn; //!< Column name to store soft delete information + QString m_sSqlQueryToFetch; //!< Overrided user SQL query to fetch an item, if empty QxOrm library builds a default SQL query + QString m_sSqlQueryToUpdate; //!< Overrided user SQL query to update an item, if empty QxOrm library builds a default SQL query + QString m_sSqlQueryToCreateTable; //!< Overrided user SQL query to create table, if empty QxOrm library builds a default SQL query + mode m_eMode; //!< Soft delete mode : 'mode_flag' with a boolean column, 'mode_date_time' with a date-time column containing deletion date-time + bool m_bFetchInJoin; //!< Add SQL condition to fetch in the JOIN part (default value), for backward compatibility with previous versions of QxOrm library set this value to false (means fetch in the WHERE part) + + public: + QxSoftDelete(); + QxSoftDelete(const QString &sColumn); + QxSoftDelete(const QString &sColumn, mode eMode); + ~QxSoftDelete(); + + QString getTableName() const; + QString getColumnName() const; + QString getSqlQueryToFetch() const; + QString getSqlQueryToUpdate() const; + QString getSqlQueryToCreateTable() const; + mode getMode() const; + bool getSqlFetchInJoin() const; + + void setTableName(const QString &sTable); + void setColumnName(const QString &sColumn); + void setSqlQueryToFetch(const QString &s); + void setSqlQueryToUpdate(const QString &s); + void setSqlQueryToCreateTable(const QString &s); + void setMode(mode eMode); + void setSqlFetchInJoin(bool b); + + bool isEmpty() const; + + QString buildSqlTablePointName(const QString &sTable = QString()) const; + QString buildSqlQueryToFetch(const QString &sTable = QString()) const; + QString buildSqlQueryToUpdate() const; + QString buildSqlQueryToCreateTable() const; + }; + +} // namespace qx + +#endif // _QX_SOFT_DELETE_H_ diff --git a/include/QxDao/QxSqlDatabase.h b/include/QxDao/QxSqlDatabase.h new file mode 100644 index 0000000..cc153d8 --- /dev/null +++ b/include/QxDao/QxSqlDatabase.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** 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_SQL_DATABASE_H_ +#define _QX_SQL_DATABASE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlDatabase.h + * \author XDL Team + * \ingroup QxDao + * \brief Define all parameters to connect to database and retrieve a valid connection by thread + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + class IxDao_Helper; + + } // namespace detail + } // namespace dao +} // namespace qx + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlDatabase : define all parameters to connect to database and retrieve a valid connection by thread (this class is a singleton and is thread-safe) + */ + class QX_DLL_EXPORT QxSqlDatabase : public QxSingleton + { + + friend class QxSingleton; + friend class qx::dao::detail::IxDao_Helper; + + public: + enum ph_style + { + ph_style_question_mark, + ph_style_2_point_name, + ph_style_at_name + }; + + typedef std::function type_fct_db_open; + + private: + struct QxSqlDatabaseImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + QxSqlDatabase(); + virtual ~QxSqlDatabase(); + + public: + QString getDriverName() const; + QString getConnectOptions() const; + QString getDatabaseName() const; + QString getUserName() const; + QString getPassword() const; + QString getHostName() const; + int getPort() const; + bool getTraceSqlQuery() const; + bool getTraceSqlRecord() const; + bool getTraceSqlBoundValues() const; + bool getTraceSqlBoundValuesOnError() const; + ph_style getSqlPlaceHolderStyle() const; + bool getSessionThrowable() const; + bool getSessionAutoTransaction() const; + bool getValidatorThrowable() const; + bool getAutoReplaceSqlAliasIntoQuery() const; + bool getVerifyOffsetRelation() const; + bool getAddAutoIncrementIdToUpdateQuery() const; + bool getForceParentIdToAllChildren() const; + type_fct_db_open getFctDatabaseOpen() const; + bool getAddSqlSquareBracketsForTableName() const; + bool getAddSqlSquareBracketsForColumnName() const; + bool getFormatSqlQueryBeforeLogging() const; + QStringList getSqlDelimiterForTableName() const; + QStringList getSqlDelimiterForColumnName() const; + QStringList getSqlDelimiterForTableNameAlias() const; + QStringList getSqlDelimiterForColumnNameAlias() const; + int getTraceSqlOnlySlowQueriesDatabase() const; + int getTraceSqlOnlySlowQueriesTotal() const; + bool getDisplayTimerDetails() const; + + void setDriverName(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setConnectOptions(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setDatabaseName(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setUserName(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setPassword(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setHostName(const QString &s, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setPort(int i, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlQuery(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlRecord(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlBoundValues(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlBoundValuesOnError(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlPlaceHolderStyle(ph_style e, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSessionThrowable(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSessionAutoTransaction(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setValidatorThrowable(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlGenerator(qx::dao::detail::IxSqlGenerator_ptr p, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setAutoReplaceSqlAliasIntoQuery(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setVerifyOffsetRelation(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setAddAutoIncrementIdToUpdateQuery(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setForceParentIdToAllChildren(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setFctDatabaseOpen(type_fct_db_open fct, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setAddSqlSquareBracketsForTableName(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setAddSqlSquareBracketsForColumnName(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setFormatSqlQueryBeforeLogging(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlDelimiterForTableName(const QStringList &lst, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlDelimiterForColumnName(const QStringList &lst, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlDelimiterForTableNameAlias(const QStringList &lst, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setSqlDelimiterForColumnNameAlias(const QStringList &lst, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlOnlySlowQueriesDatabase(int i, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setTraceSqlOnlySlowQueriesTotal(int i, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + void setDisplayTimerDetails(bool b, bool bJustForCurrentThread = false, QSqlDatabase *pJustForThisDatabase = NULL); + + static QSqlDatabase getDatabase(); + static QSqlDatabase getDatabase(QSqlError &dbError); + static QSqlDatabase getDatabaseCloned(); + static QSqlDatabase checkDatabaseByThread(); + static void removeDatabaseByThread(); + static void closeAllDatabases(); + static void clearAllDatabases(); + static bool isEmpty(); + + qx::dao::detail::IxSqlGenerator *getSqlGenerator(); + + void clearAllSettingsForCurrentThread(); + void clearAllSettingsForDatabase(QSqlDatabase *p); + + protected: + bool setCurrentDatabaseByThread(QSqlDatabase *p); + void clearCurrentDatabaseByThread(); + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxSqlDatabase) + +#endif // _QX_SQL_DATABASE_H_ diff --git a/include/QxDao/QxSqlElement/IxSqlElement.h b/include/QxDao/QxSqlElement/IxSqlElement.h new file mode 100644 index 0000000..b3d9914 --- /dev/null +++ b/include/QxDao/QxSqlElement/IxSqlElement.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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 _IX_SQL_ELEMENT_H_ +#define _IX_SQL_ELEMENT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxSqlElement.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface for all SQL elements to build SQL query + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +#include + +#include + +#include +#include +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + class IxSqlElement; + } // namespace detail + } // namespace dao +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::dao::detail::IxSqlElement &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::dao::detail::IxSqlElement &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::dao::detail::IxSqlElement &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::dao::detail::IxSqlElement &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::IxSqlElement : common interface for all SQL elements to build SQL query + */ + class QX_DLL_EXPORT IxSqlElement + { + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::dao::detail::IxSqlElement &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::dao::detail::IxSqlElement &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::dao::detail::IxSqlElement &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::dao::detail::IxSqlElement &t, const QString &format); +#endif // _QX_NO_JSON + + public: + enum type_class + { + _no_type, + _sql_compare, + _sql_element_temp, + _sql_expression, + _sql_free_text, + _sql_in, + _sql_is_between, + _sql_is_null, + _sql_limit, + _sql_sort, + _sql_embed_query + }; + + protected: + int m_iIndex; //!< Index of SQL element to build unique string + QStringList m_lstColumns; //!< List of columns associated to SQL element + QStringList m_lstKeys; //!< List of keys associated to SQL element + QList m_lstValues; //!< List of values associated to SQL element + IxSqlGenerator *m_pSqlGenerator; //!< SQL generator to build SQL query specific for each database + + public: + IxSqlElement(int index); + virtual ~IxSqlElement(); + + void setColumn(const QString &column); + void setColumns(const QStringList &columns); + void setValue(const QVariant &val); + void setValues(const QVariantList &values); + + virtual IxSqlElement::type_class getTypeClass() const = 0; + + virtual QString toString() const = 0; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const = 0; + virtual void postProcess(QString &sql) const = 0; + + virtual void clone(IxSqlElement *other); + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void qxSave(Archive &ar) const + { + QString sExtraSettings = getExtraSettings(); + ar << boost::serialization::make_nvp("index", m_iIndex); + ar << boost::serialization::make_nvp("list_columns", m_lstColumns); + ar << boost::serialization::make_nvp("list_keys", m_lstKeys); + ar << boost::serialization::make_nvp("list_values", m_lstValues); + ar << boost::serialization::make_nvp("extra_settings", sExtraSettings); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void qxLoad(Archive &ar) + { + QString sExtraSettings; + ar >> boost::serialization::make_nvp("index", m_iIndex); + ar >> boost::serialization::make_nvp("list_columns", m_lstColumns); + ar >> boost::serialization::make_nvp("list_keys", m_lstKeys); + ar >> boost::serialization::make_nvp("list_values", m_lstValues); + ar >> boost::serialization::make_nvp("extra_settings", sExtraSettings); + setExtraSettings(sExtraSettings); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + protected: + void updateKeys(); + + virtual QString getExtraSettings() const = 0; + virtual void setExtraSettings(const QString &s) = 0; + }; + + typedef std::shared_ptr IxSqlElement_ptr; + + QX_DLL_EXPORT IxSqlElement_ptr create_sql_element(IxSqlElement::type_class e) QX_USED; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _IX_SQL_ELEMENT_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlCompare.h b/include/QxDao/QxSqlElement/QxSqlCompare.h new file mode 100644 index 0000000..a1cb900 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlCompare.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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_SQL_COMPARE_H_ +#define _QX_SQL_COMPARE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlCompare.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to compare value (==, <, >, <=, >=, LIKE, NOT LIKE, etc.) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlCompare : SQL element to compare value (==, <, >, <=, >=, LIKE, NOT LIKE, etc.) + */ + class QX_DLL_EXPORT QxSqlCompare : public IxSqlElement + { + + public: + enum type + { + _is_equal_to, + _is_not_equal_to, + _is_greater_than, + _is_greater_than_or_equal_to, + _is_less_than, + _is_less_than_or_equal_to, + _like, + _not_like, + _starts_with, + _ends_with, + _contains_string, + _custom_operator, + _is_equal_to_select, + _is_not_equal_to_select + }; + + protected: + QxSqlCompare::type m_type; //!< Compare type + QString m_sCustomOperator; //!< Possibility to define a custom operator with enum _custom_operator (for example <@ for PostgreSQL ltree type) + + public: + QxSqlCompare(); + QxSqlCompare(int index, QxSqlCompare::type t, const QString &sCustomOperator = QString()); + virtual ~QxSqlCompare(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlCompare_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_COMPARE_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlElement.h b/include/QxDao/QxSqlElement/QxSqlElement.h new file mode 100644 index 0000000..8bf8bb7 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlElement.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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_SQL_ELEMENT_H_ +#define _QX_SQL_ELEMENT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _QX_SQL_ELEMENT_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlElementTemp.h b/include/QxDao/QxSqlElement/QxSqlElementTemp.h new file mode 100644 index 0000000..5ce498c --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlElementTemp.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_SQL_ELEMENT_TEMP_H_ +#define _QX_SQL_ELEMENT_TEMP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlElementTemp.h + * \author XDL Team + * \ingroup QxDao + * \brief Temporary SQL element (need to be cloned to be used) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlElementTemp : temporary SQL element (need to be cloned to be used) + */ + class QX_DLL_EXPORT QxSqlElementTemp : public IxSqlElement + { + + public: + QxSqlElementTemp(); + virtual ~QxSqlElementTemp(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlElementTemp_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_ELEMENT_TEMP_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlEmbedQuery.h b/include/QxDao/QxSqlElement/QxSqlEmbedQuery.h new file mode 100644 index 0000000..36b7672 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlEmbedQuery.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_SQL_EMBED_QUERY_H_ +#define _QX_SQL_EMBED_QUERY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlEmbedQuery.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to embed a SQL sub-query inside a parent SQL query + */ + +#include + +namespace qx +{ + class QxSqlQuery; +} // namespace qx + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlEmbedQuery : SQL element to embed a SQL sub-query inside a parent SQL query + */ + class QX_DLL_EXPORT QxSqlEmbedQuery : public IxSqlElement + { + + public: + enum type + { + _none, + _in, + _not_in, + _is_equal_to, + _is_not_equal_to + }; + + private: + struct QxSqlEmbedQueryImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxSqlEmbedQuery(QxSqlEmbedQuery::type type = QxSqlEmbedQuery::_none); + QxSqlEmbedQuery(int index, QxSqlEmbedQuery::type type = QxSqlEmbedQuery::_none); + virtual ~QxSqlEmbedQuery(); + + void setQuery(const qx::QxSqlQuery &query); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlEmbedQuery_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_EMBED_QUERY_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlExpression.h b/include/QxDao/QxSqlElement/QxSqlExpression.h new file mode 100644 index 0000000..b36c710 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlExpression.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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_SQL_EXPRESSION_H_ +#define _QX_SQL_EXPRESSION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlExpression.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to build a SQL expression (WHERE, AND, OR, etc.) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlExpression : SQL element to build a SQL expression (WHERE, AND, OR, etc.) + */ + class QX_DLL_EXPORT QxSqlExpression : public IxSqlElement + { + + public: + enum type + { + _where, + _and, + _or, + _open_parenthesis, + _close_parenthesis + }; + + protected: + QxSqlExpression::type m_type; + + public: + QxSqlExpression(); + QxSqlExpression(int index, QxSqlExpression::type t); + virtual ~QxSqlExpression(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlExpression_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_EXPRESSION_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlFreeText.h b/include/QxDao/QxSqlElement/QxSqlFreeText.h new file mode 100644 index 0000000..51bb811 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlFreeText.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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_SQL_FREE_TEXT_H_ +#define _QX_SQL_FREE_TEXT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlFreeText.h + * \author XDL Team + * \ingroup QxDao + * \brief Possibility to add free text to SQL query + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlFreeText : possibility to add free text to SQL query + */ + class QX_DLL_EXPORT QxSqlFreeText : public IxSqlElement + { + + protected: + QString m_sText; //!< Custom SQL text to insert to SQL query + + public: + QxSqlFreeText(); + QxSqlFreeText(int index); + virtual ~QxSqlFreeText(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + void setText(const QString &txt); + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlFreeText_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_FREE_TEXT_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlIn.h b/include/QxDao/QxSqlElement/QxSqlIn.h new file mode 100644 index 0000000..a50637f --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlIn.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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_SQL_IN_H_ +#define _QX_SQL_IN_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlIn.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to verify a list of values (IN, NOT IN, etc.) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlIn : SQL element to verify a list of values (IN, NOT IN, etc.) + */ + class QX_DLL_EXPORT QxSqlIn : public IxSqlElement + { + + public: + enum type + { + _in, + _not_in, + _in_select, + _not_in_select + }; + + protected: + QxSqlIn::type m_type; + + public: + QxSqlIn(); + QxSqlIn(int index, QxSqlIn::type t); + virtual ~QxSqlIn(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlIn_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_IN_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlIsBetween.h b/include/QxDao/QxSqlElement/QxSqlIsBetween.h new file mode 100644 index 0000000..c0a9ed2 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlIsBetween.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_SQL_IS_BETWEEN_H_ +#define _QX_SQL_IS_BETWEEN_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlIsBetween.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to verify if a value is included into 2 other values + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlIsBetween : SQL element to verify if a value is included into 2 other values + */ + class QX_DLL_EXPORT QxSqlIsBetween : public IxSqlElement + { + + public: + enum type + { + _is_between, + _is_not_between + }; + + protected: + QxSqlIsBetween::type m_type; + + public: + QxSqlIsBetween(); + QxSqlIsBetween(int index, QxSqlIsBetween::type t); + virtual ~QxSqlIsBetween(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlIsBetween_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_IS_BETWEEN_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlIsNull.h b/include/QxDao/QxSqlElement/QxSqlIsNull.h new file mode 100644 index 0000000..bc5bf3b --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlIsNull.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_SQL_IS_NULL_H_ +#define _QX_SQL_IS_NULL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlIsNull.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to verify if a value is null or not null (IS NULL, IS NOT NULL) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlIsNull : SQL element to verify if a value is null or not null (IS NULL, IS NOT NULL) + */ + class QX_DLL_EXPORT QxSqlIsNull : public IxSqlElement + { + + public: + enum type + { + _is_null, + _is_not_null + }; + + protected: + QxSqlIsNull::type m_type; + + public: + QxSqlIsNull(); + QxSqlIsNull(int index, QxSqlIsNull::type t); + virtual ~QxSqlIsNull(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlIsNull_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_IS_NULL_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlLimit.h b/include/QxDao/QxSqlElement/QxSqlLimit.h new file mode 100644 index 0000000..e8ebe77 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlLimit.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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_SQL_LIMIT_H_ +#define _QX_SQL_LIMIT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlLimit.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to limit rows count fetched from database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlLimit : SQL element to limit rows count fetched from database + */ + class QX_DLL_EXPORT QxSqlLimit : public IxSqlElement + { + + public: + QxSqlLimit(); + QxSqlLimit(int index); + virtual ~QxSqlLimit(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + int getStartRow() const; + int getRowsCount() const; + int getMaxRow() const; + bool getWithTies() const; + + QString getStartRow_ParamKey() const; + QString getRowsCount_ParamKey() const; + QString getMaxRow_ParamKey() const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlLimit_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_LIMIT_H_ diff --git a/include/QxDao/QxSqlElement/QxSqlSort.h b/include/QxDao/QxSqlElement/QxSqlSort.h new file mode 100644 index 0000000..a657eb3 --- /dev/null +++ b/include/QxDao/QxSqlElement/QxSqlSort.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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_SQL_SORT_H_ +#define _QX_SQL_SORT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlSort.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL element to sort or to group list of elements fetched from database (ORDER BY, GROUP BY) + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlSort : SQL element to sort or to group list of elements fetched from database (ORDER BY, GROUP BY) + */ + class QX_DLL_EXPORT QxSqlSort : public IxSqlElement + { + + public: + enum type + { + _order_asc, + _order_desc, + _group_by + }; + + protected: + QxSqlSort::type m_type; + + public: + QxSqlSort(); + QxSqlSort(int index, QxSqlSort::type t); + virtual ~QxSqlSort(); + + virtual QString toString() const; + virtual void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql) const; + + virtual IxSqlElement::type_class getTypeClass() const; + + protected: + virtual QString getExtraSettings() const; + virtual void setExtraSettings(const QString &s); + }; + + typedef std::shared_ptr QxSqlSort_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_SORT_H_ diff --git a/include/QxDao/QxSqlError.h b/include/QxDao/QxSqlError.h new file mode 100644 index 0000000..f1ecda3 --- /dev/null +++ b/include/QxDao/QxSqlError.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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_SQL_ERROR_H_ +#define _QX_SQL_ERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlError.h + * \author XDL Team + * \ingroup QxDao + * \brief Define a SQL error exception and retrieve QSqlError type of Qt library + */ + +#include +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief qx::dao::sql_error : define a SQL error exception and retrieve QSqlError type of Qt library + */ + class sql_error : public std::exception + { + + private: + QSqlError m_error; + QByteArray m_errorMessage; + + public: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + sql_error(const QSqlError &err) : std::exception(), m_error(err) + { + if (!m_error.text().isEmpty() && (m_error.type() == QSqlError::NoError)) + { + m_error = QSqlError(m_error.driverText(), m_error.databaseText(), QSqlError::UnknownError, m_error.nativeErrorCode()); + }; + m_errorMessage = m_error.text().toLocal8Bit(); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + sql_error(const QSqlError &err) : std::exception(), m_error(err) + { + if (!m_error.text().isEmpty() && (m_error.type() == QSqlError::NoError)) + { + m_error.setType(QSqlError::UnknownError); + }; + m_errorMessage = m_error.text().toLocal8Bit(); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + virtual ~sql_error() throw() { ; } + + virtual const char *what() const throw() + { + if (m_error.isValid()) + { + return m_errorMessage.constData(); + } + else + { + return ""; + } + } + QSqlError get() const { return m_error; } + }; + + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_ERROR_H_ diff --git a/include/QxDao/QxSqlGenerator/IxSqlGenerator.h b/include/QxDao/QxSqlGenerator/IxSqlGenerator.h new file mode 100644 index 0000000..42372fe --- /dev/null +++ b/include/QxDao/QxSqlGenerator/IxSqlGenerator.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 _IX_SQL_GENERATOR_H_ +#define _IX_SQL_GENERATOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxSqlGenerator.h + * \author XDL Team + * \ingroup QxDao + * \brief Common interface for all SQL generators to build SQL query specific for each database + */ + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + class IxDao_Helper; + class IxSqlElement; + class QxSqlCompare; + class QxSqlElementTemp; + class QxSqlEmbedQuery; + class QxSqlExpression; + class QxSqlFreeText; + class QxSqlIn; + class QxSqlIsBetween; + class QxSqlIsNull; + class QxSqlLimit; + class QxSqlSort; + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::IxSqlGenerator : common interface for all SQL generators to build SQL query specific for each database + */ + class QX_DLL_EXPORT IxSqlGenerator + { + + public: + IxSqlGenerator(); + virtual ~IxSqlGenerator(); + + virtual void init() = 0; + virtual QString getAutoIncrement() const = 0; + virtual QString getWildCard() const = 0; + virtual QString getTableAliasSep() const = 0; + virtual QString getLimit(const QxSqlLimit *pLimit) const = 0; + virtual void resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch = NULL) const = 0; + virtual void postProcess(QString &sql, const QxSqlLimit *pLimit) const = 0; + virtual void onBeforeInsert(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void onBeforeUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void onAfterUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void onBeforeDelete(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void onAfterDelete(IxDao_Helper *pDaoHelper, void *pOwner) const = 0; + virtual void checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const = 0; + virtual void onBeforeSqlPrepare(IxDao_Helper *pDaoHelper, QString &sql) const = 0; + virtual void formatSqlQuery(IxDao_Helper *pDaoHelper, QString &sql) const = 0; + }; + + typedef std::shared_ptr IxSqlGenerator_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _IX_SQL_GENERATOR_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator.h new file mode 100644 index 0000000..09b2722 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_H_ +#define _QX_SQL_GENERATOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include +#include +#include +#include +#include +#include + +#endif // _QX_SQL_GENERATOR_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.h new file mode 100644 index 0000000..168a607 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_MSSQLSERVER_H_ +#define _QX_SQL_GENERATOR_MSSQLSERVER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_MSSQLServer.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator for Microsoft SQL Server database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_MSSQLServer : SQL generator for Microsoft SQL Server database + */ + class QX_DLL_EXPORT QxSqlGenerator_MSSQLServer : public QxSqlGenerator_Standard + { + + public: + QxSqlGenerator_MSSQLServer(); + virtual ~QxSqlGenerator_MSSQLServer(); + + virtual void init(); + virtual QString getLimit(const QxSqlLimit *pLimit) const; + virtual void resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql, const QxSqlLimit *pLimit) const; + + private: + void initSqlTypeByClassName() const; + }; + + typedef std::shared_ptr QxSqlGenerator_MSSQLServer_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_MSSQLSERVER_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.h new file mode 100644 index 0000000..3e65c59 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_MYSQL_H_ +#define _QX_SQL_GENERATOR_MYSQL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_MySQL.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator for MySQL database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_MySQL : SQL generator for MySQL database + */ + class QX_DLL_EXPORT QxSqlGenerator_MySQL : public QxSqlGenerator_Standard + { + + public: + QxSqlGenerator_MySQL(); + virtual ~QxSqlGenerator_MySQL(); + + virtual QString getAutoIncrement() const; + + private: + void initSqlTypeByClassName() const; + }; + + typedef std::shared_ptr QxSqlGenerator_MySQL_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_MYSQL_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.h new file mode 100644 index 0000000..e5e3dcd --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_ORACLE_H_ +#define _QX_SQL_GENERATOR_ORACLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_Oracle.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator for Oracle database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_Oracle : SQL generator for Oracle database + */ + class QX_DLL_EXPORT QxSqlGenerator_Oracle : public QxSqlGenerator_Standard + { + + protected: + bool m_bOldLimitSyntax; //!< Use old limit syntax (for Oracle version < 12.1), more details here : https://stackoverflow.com/questions/470542/how-do-i-limit-the-number-of-rows-returned-by-an-oracle-query-after-ordering + bool m_bManageLastInsertId; //!< Manage last insert id using RETURNING INTO syntax (thx to Romain Macureau and Abdennour Boutrig) + + public: + QxSqlGenerator_Oracle(); + QxSqlGenerator_Oracle(bool bManageLastInsertId); + virtual ~QxSqlGenerator_Oracle(); + + virtual QString getTableAliasSep() const; + virtual QString getLimit(const QxSqlLimit *pLimit) const; + virtual void resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql, const QxSqlLimit *pLimit) const; + virtual void checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const; + virtual void onBeforeInsert(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const; + + bool getOldLimitSyntax() const; + void setOldLimitSyntax(bool b); + + bool getManageLastInsertId() const; + void setManageLastInsertId(bool b); + + private: + void initSqlTypeByClassName() const; + }; + + typedef std::shared_ptr QxSqlGenerator_Oracle_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_ORACLE_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.h new file mode 100644 index 0000000..ed92331 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_POSTGRESQL_H_ +#define _QX_SQL_GENERATOR_POSTGRESQL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_PostgreSQL.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator for PostgreSQL database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_PostgreSQL : SQL generator for PostgreSQL database + */ + class QX_DLL_EXPORT QxSqlGenerator_PostgreSQL : public QxSqlGenerator_Standard + { + + public: + QxSqlGenerator_PostgreSQL(); + virtual ~QxSqlGenerator_PostgreSQL(); + + virtual void checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const; + virtual void onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const; + + private: + void initSqlTypeByClassName() const; + }; + + typedef std::shared_ptr QxSqlGenerator_PostgreSQL_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_POSTGRESQL_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.h new file mode 100644 index 0000000..54e7474 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_SQLITE_H_ +#define _QX_SQL_GENERATOR_SQLITE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_SQLite.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator for SQLite database + */ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_SQLite : SQL generator for SQLite database + */ + class QX_DLL_EXPORT QxSqlGenerator_SQLite : public QxSqlGenerator_Standard + { + + public: + QxSqlGenerator_SQLite(); + virtual ~QxSqlGenerator_SQLite(); + + private: + void initSqlTypeByClassName() const; + }; + + typedef std::shared_ptr QxSqlGenerator_SQLite_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_SQLITE_H_ diff --git a/include/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.h b/include/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.h new file mode 100644 index 0000000..83d7530 --- /dev/null +++ b/include/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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_SQL_GENERATOR_STANDARD_H_ +#define _QX_SQL_GENERATOR_STANDARD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlGenerator_Standard.h + * \author XDL Team + * \ingroup QxDao + * \brief SQL generator to build standard SQL query + */ + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + /*! + * \ingroup QxDao + * \brief qx::dao::detail::QxSqlGenerator_Standard : SQL generator to build standard SQL query + */ + class QX_DLL_EXPORT QxSqlGenerator_Standard : public IxSqlGenerator + { + + public: + QxSqlGenerator_Standard(); + virtual ~QxSqlGenerator_Standard(); + + virtual void init(); + virtual QString getAutoIncrement() const; + virtual QString getWildCard() const; + virtual QString getTableAliasSep() const; + virtual QString getLimit(const QxSqlLimit *pLimit) const; + virtual void resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch = NULL) const; + virtual void postProcess(QString &sql, const QxSqlLimit *pLimit) const; + virtual void onBeforeInsert(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onBeforeUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onAfterUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onBeforeDelete(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void onAfterDelete(IxDao_Helper *pDaoHelper, void *pOwner) const; + virtual void checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const; + virtual void onBeforeSqlPrepare(IxDao_Helper *pDaoHelper, QString &sql) const; + virtual void formatSqlQuery(IxDao_Helper *pDaoHelper, QString &sql) const; + }; + + typedef std::shared_ptr QxSqlGenerator_Standard_ptr; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_GENERATOR_STANDARD_H_ diff --git a/include/QxDao/QxSqlJoin.h b/include/QxDao/QxSqlJoin.h new file mode 100644 index 0000000..7301c72 --- /dev/null +++ b/include/QxDao/QxSqlJoin.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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_SQL_JOIN_H_ +#define _QX_SQL_JOIN_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlJoin.h + * \author XDL Team + * \ingroup QxDao + * \brief Define how to join 2 tables into SQL query (LEFT OUTER JOIN, INNER JOIN, etc...) + */ + +#define QX_LEFT_OUTER_JOIN QString("->") +#define QX_INNER_JOIN QString(">>") + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief qx::dao::sql_join : define how to join 2 tables into SQL query (LEFT OUTER JOIN, INNER JOIN, etc...) + */ + struct sql_join + { + + enum join_type + { + no_join, + left_outer_join, + inner_join + }; + }; + + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_JOIN_H_ diff --git a/include/QxDao/QxSqlQuery.h b/include/QxDao/QxSqlQuery.h new file mode 100644 index 0000000..9e87efe --- /dev/null +++ b/include/QxDao/QxSqlQuery.h @@ -0,0 +1,729 @@ +/**************************************************************************** +** +** 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_SQL_QUERY_H_ +#define _QX_SQL_QUERY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlQuery.h + * \author XDL Team + * \ingroup QxDao + * \brief Define a user SQL query added to default SQL query builded by QxOrm library, and used by qx::dao::xxx functions to filter elements fetched from database + */ + +#ifdef Q_COMPILER_INITIALIZER_LISTS +#include +#endif // Q_COMPILER_INITIALIZER_LISTS + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifndef _QX_NO_JSON +#include +#include +#include +#include +#endif // _QX_NO_JSON + +#include + +#include + +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + class QxSqlQuery; +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const qx::QxSqlQuery &t, const unsigned int file_version); + template + inline void qx_load(Archive &ar, qx::QxSqlQuery &t, const unsigned int file_version); + + } // namespace serialization +} // namespace boost +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxSqlQuery &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxSqlQuery &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::QxSqlQuery &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxSqlQuery &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQuery : define a user SQL query added to default SQL query builded by QxOrm library, and used by qx::dao::xxx functions to filter elements fetched from database + * + * The class qx::QxSqlQuery (or its typedef qx_query) is used to communicate with database (to filter, to sort, etc.) in two different ways : + * - writing manually SQL query ; + * - using C++ methods with a syntax similar to SQL (same concept than the great library SubSonic for .Net). + * + * With the first method (writing manually SQL query), you can use some optimizations specific for each database. + * The second method (using C++ code to build SQL query) binds automatically SQL parameters without using qx::QxSqlQuery::bind() function. + * + * Here is an example with qx::QxSqlQuery class writing manually a SQL query : + * \code + // Build a SQL query to fetch only 'author' of type 'female' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + QList list_of_female; + QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female); + + // Here we can work with the collection provided by database + for (long l = 0; l < list_of_female.count(); l++) { ; } + * \endcode + * + * QxOrm library provides 3 styles to write SQL parameters. + * This style can be modified for a project using the following method qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle() : + * - ph_style_2_point_name : "WHERE author.sex = :sex" (default style) ; + * - ph_style_at_name : "WHERE author.sex = @sex" ; + * - ph_style_question_mark : "WHERE author.sex = ?". + * + * Here is the same example using C++ code of the class qx::QxSqlQuery (or its typedef qx_query) to build query automatically : + * \code + // Build a SQL query to fetch only 'author' of type 'female' + qx_query query; + query.where("author.sex").isEqualTo(author::female); + + QList list_of_female; + QSqlError daoError = qx::dao::fetch_by_query(query, list_of_female); + + // Here we can work with the collection provided by database + for (long l = 0; l < list_of_female.count(); l++) { ; } + * \endcode + * + * With C++ methods of qx::QxSqlQuery class, you don't have to bind any SQL parameter, and the syntax is similar to real SQL. + * All SQL parameters will be provided to database automatically with the following style : qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle(). + * + * Here is an example with many methods of qx::QxSqlQuery class (or its typedef qx_query) : + * \code + qx_query query; + query.where("sex").isEqualTo(author::female) + .and_("age").isGreaterThan(38) + .or_("last_name").isNotEqualTo("Dupont") + .or_("first_name").like("Alfred") + .and_OpenParenthesis("id").isLessThanOrEqualTo(999) + .and_("birth_date").isBetween(date1, date2) + .closeParenthesis() + .or_("id").in(50, 999, 11, 23, 78945) + .and_("is_deleted").isNotNull() + .orderAsc("last_name", "first_name", "sex") + .limit(50, 150); + * \endcode + * + * This code will produce following SQL for MySQL, PostgreSQL and SQLite databases (for Oracle and SQLServer, there is a specific process for limit() method) : + * \code + WHERE sex = :sex_1_0 + AND age > :age_3_0 + OR last_name <> :last_name_5_0 + OR first_name LIKE :first_name_7_0 + AND ( id <= :id_10_0 AND birth_date BETWEEN :birth_date_12_0_1 AND :birth_date_12_0_2 ) + OR id IN (:id_15_0_0, :id_15_0_1, :id_15_0_2, :id_15_0_3, :id_15_0_4) + AND is_deleted IS NOT NULL + ORDER BY last_name ASC, first_name ASC, sex ASC + LIMIT :limit_rows_count_19_0 OFFSET :offset_start_row_19_0 + * \endcode + * + * Here is the list of all functions available to use qx::QxSqlQuery class (or its typedef qx_query) : + * \code + // with functions into namespace qx::dao + qx::dao::count() + qx::dao::fetch_by_query() + qx::dao::update_by_query() + qx::dao::delete_by_query() + qx::dao::destroy_by_query() + qx::dao::fetch_by_query_with_relation() + qx::dao::fetch_by_query_with_all_relation() + qx::dao::update_by_query_with_relation() + qx::dao::update_by_query_with_all_relation() + qx::dao::update_optimized_by_query() + + // with qx::QxSession class + qx::QxSession::count() + qx::QxSession::fetchByQuery() + qx::QxSession::update() + qx::QxSession::deleteByQuery() + qx::QxSession::destroyByQuery() + + // with qx::QxRepository class + qx::QxRepository::count() + qx::QxRepository::fetchByQuery() + qx::QxRepository::update() + qx::QxRepository::deleteByQuery() + qx::QxRepository::destroyByQuery() + * \endcode + * + * Note : those functions have 2 other optionals parameters : + * - const QStringList & columns : to indicate columns to fetch (by default, all columns are fetched) ; + * - const QStringList & relation : to indicate relations to fetch (one-to-one, one-to-many, many-to-one and many-to-many defined into void qx::register_class() mapping function by class), by default there is no relation fetched. + * + * Other note : it's possible to call a stored procedure using qx::QxSqlQuery class, for example : + * \code + qx_query query("CALL MyStoredProc(:param1, :param2)"); + query.bind(":param1", "myValue1"); + query.bind(":param2", 5024, QSql::InOut); + QSqlError daoError = qx::dao::call_query(query); + QVariant vNewValue = query.boundValue(":param2"); + query.dumpSqlResult(); + * \endcode + * + * If the stored procedure returns a resultset, you can iterate over each rows and fields using the following methods (after calling qx::dao::call_query() function) : + * - long qx::QxSqlQuery::getSqlResultRowCount() const; + * - long qx::QxSqlQuery::getSqlResultColumnCount() const; + * - QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const; + * - QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) const; + * - QVector qx::QxSqlQuery::getSqlResultAllColumns() const; + * - void qx::QxSqlQuery::dumpSqlResult(); + * + * Other note : to add your own SQL query methods (for example, some databases provide non-standard specifics SQL functions) : + * - create a derived class based on qx::QxSqlQuery class ; + * - if your C++ compiler supports covariant return type, add the macro QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_HPP(myClass) in the definition of your class (myClass.h) ; + * - if your C++ compiler supports covariant return type, add the macro QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_CPP(myClass) in the implementation of your class (myClass.cpp) ; + * - add all SQL specifics functions in your derived class. + */ + class QX_DLL_EXPORT QxSqlQuery + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + friend inline void boost::serialization::qx_save(Archive &ar, const qx::QxSqlQuery &t, const unsigned int file_version); + template + friend inline void boost::serialization::qx_load(Archive &ar, qx::QxSqlQuery &t, const unsigned int file_version); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxSqlQuery &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxSqlQuery &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::QxSqlQuery &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxSqlQuery &t, const QString &format); +#endif // _QX_NO_JSON + + public: + typedef std::function type_fct_on_before_sql_prepare; + + protected: + struct QxSqlResult + { + QHash positionByKey; + QHash positionByKeyUpper; + QVector> values; + }; + + typedef std::tuple type_bind_value; + + QStringList m_sQuery; //!< Query SQL with place-holder + QxCollection m_lstValue; //!< Bind value in this array + qx::dao::detail::IxSqlElement_ptr m_pSqlElementTemp; //!< Temporary SQL element + QList m_lstSqlElement; //!< List of all SQL elements to build SQL query + int m_iSqlElementIndex; //!< Current index of SQL element + int m_iParenthesisCount; //!< Current parenthesis count + bool m_bDistinct; //!< Replace SELECT by SELECT DISTINCT in SQL query + std::shared_ptr m_pSqlResult; //!< All results returning by SQL query or stored procedure (after calling qx::dao::call_query function) + QVariant m_vResponse; //!< Can be used to store some responses (from MongoDB database for example in JSON format) + QString m_sType; //!< Query type (for example : 'aggregate' or 'cursor' for MongoDB database) + QHash> m_lstJoinQueryUser; //!< List of SQL queries defined by user to add inside relationships joins (LEFT OUTER JOIN, INNER JOIN), for example : INNER JOIN my_table2 m2 ON (m1.id = m2.parent_id AND (XXX)) + QList> m_lstJoinQueryToResolve; //!< List of SQL queries to resolve (in the right order) to add inside relationships joins (LEFT OUTER JOIN, INNER JOIN), for example : INNER JOIN my_table2 m2 ON (m1.id = m2.parent_id AND (XXX)) + type_fct_on_before_sql_prepare m_fctOnBeforeSqlPrepare; //!< Custom callback function to modify SQL query before preparing in database + + public: + QxSqlQuery(); + QxSqlQuery(const char *query, const QVariantList &values = QVariantList()); + QxSqlQuery(const QString &query, const QVariantList &values = QVariantList()); + QxSqlQuery(const QStringList &query); + QxSqlQuery(const QString &type, const QString &query); + QxSqlQuery(const QString &type, const QStringList &query); + virtual ~QxSqlQuery(); + +#ifndef _QX_NO_JSON +#ifdef Q_COMPILER_INITIALIZER_LISTS + QxSqlQuery(std::initializer_list> json); + QxSqlQuery(std::initializer_list> json, std::initializer_list> opts); + QxSqlQuery(const QString &type, std::initializer_list> json); + QxSqlQuery(const QString &type, std::initializer_list> json, std::initializer_list> opts); +#endif // Q_COMPILER_INITIALIZER_LISTS +#endif // _QX_NO_JSON + + QString query(); + QString queryAt(int idx) const; + void queryAt(int idx, const QString &query); + QVariant response() const; + QString type() const; + bool isEmpty() const; + bool isDistinct() const; + void clear(); + void resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch = NULL) const; + void resolveOutput(QSqlQuery &query, bool bFetchSqlResult); + void postProcess(QString &sql) const; + void setResponse(const QVariant &v); + void setType(const QString &s); + QString getJoinQuery(const QString &relationKey, const QString &relationAlias); + QString getJoinQueryHash(); + + QxSqlQuery &query(const QString &sQuery); + QxSqlQuery &bind(const QVariant &vValue, QSql::ParamType paramType = QSql::In); + QxSqlQuery &bind(const QString &sKey, const QVariant &vValue, QSql::ParamType paramType = QSql::In); + + QVariant boundValue(const QString &sKey) const; + QVariant boundValue(int iPosition) const; + + long getSqlResultRowCount() const; + long getSqlResultColumnCount() const; + QVariant getSqlResultAt(long row, long column) const; + QVariant getSqlResultAt(long row, const QString &column, bool caseSensitive = false) const; + QVector getSqlResultAt(long row) const; + QVector getSqlResultAllColumns() const; + void dumpSqlResult(); + + static void dumpBoundValues(const QSqlQuery &query); + + QxSqlQuery &setFctOnBeforeSqlPrepare(type_fct_on_before_sql_prepare fct); + void onBeforeSqlPrepare(QString &sql); + + private: + void verifyQuery() const QX_USED; + void fetchSqlResult(QSqlQuery &query); + + public: + /* -- All methods to build SQL query using C++ syntax -- */ + + virtual QxSqlQuery &distinct(); + + virtual QxSqlQuery &where(const QString &column); + virtual QxSqlQuery &where_OpenParenthesis(const QString &column); + virtual QxSqlQuery &and_(const QString &column); + virtual QxSqlQuery &and_OpenParenthesis(const QString &column); + virtual QxSqlQuery &or_(const QString &column); + virtual QxSqlQuery &or_OpenParenthesis(const QString &column); + + virtual QxSqlQuery &openParenthesis(); + virtual QxSqlQuery &closeParenthesis(); + + virtual QxSqlQuery &orderAsc(const QStringList &columns); + virtual QxSqlQuery &orderAsc(const QString &col1); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); + virtual QxSqlQuery &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); + + virtual QxSqlQuery &orderDesc(const QStringList &columns); + virtual QxSqlQuery &orderDesc(const QString &col1); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); + virtual QxSqlQuery &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); + + virtual QxSqlQuery &groupBy(const QStringList &columns); + virtual QxSqlQuery &groupBy(const QString &col1); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); + virtual QxSqlQuery &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); + + virtual QxSqlQuery &limit(int rowsCount, int startRow = 0, bool withTies = false); + + virtual QxSqlQuery &like(const QString &val); + virtual QxSqlQuery ¬Like(const QString &val); + virtual QxSqlQuery &startsWith(const QString &val); + virtual QxSqlQuery &endsWith(const QString &val); + virtual QxSqlQuery &containsString(const QString &val); + + virtual QxSqlQuery &isEqualTo(const QVariant &val); + virtual QxSqlQuery &isNotEqualTo(const QVariant &val); + virtual QxSqlQuery &isGreaterThan(const QVariant &val); + virtual QxSqlQuery &isGreaterThanOrEqualTo(const QVariant &val); + virtual QxSqlQuery &isLessThan(const QVariant &val); + virtual QxSqlQuery &isLessThanOrEqualTo(const QVariant &val); + virtual QxSqlQuery &customOperator(const QString &sCustomOperator, const QVariant &val); + + virtual QxSqlQuery &in(const QVariantList &values); + virtual QxSqlQuery &in(const QVariant &val1); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8); + virtual QxSqlQuery &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9); + + virtual QxSqlQuery ¬In(const QVariantList &values); + virtual QxSqlQuery ¬In(const QVariant &val1); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8); + virtual QxSqlQuery ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9); + + virtual QxSqlQuery &in_Select(const QxSqlQuery &query); + virtual QxSqlQuery ¬In_Select(const QxSqlQuery &query); + virtual QxSqlQuery &isEqualTo_Select(const QxSqlQuery &query); + virtual QxSqlQuery &isNotEqualTo_Select(const QxSqlQuery &query); + + virtual QxSqlQuery &isNull(); + virtual QxSqlQuery &isNotNull(); + + virtual QxSqlQuery &isBetween(const QVariant &val1, const QVariant &val2); + virtual QxSqlQuery &isNotBetween(const QVariant &val1, const QVariant &val2); + + virtual QxSqlQuery &freeText(const QString &text, const QVariantList &values = QVariantList()); + + virtual QxSqlQuery &addJoinQuery(const QString &relationKeyOrAlias, const QxSqlQuery &joinQuery); + + private: + QxSqlQuery &addSqlExpression(const QString &column, qx::dao::detail::QxSqlExpression::type type); + QxSqlQuery &addSqlCompare(const QVariant &val, qx::dao::detail::QxSqlCompare::type type, const QString &sCustomOperator = QString()); + QxSqlQuery &addSqlSort(const QStringList &columns, qx::dao::detail::QxSqlSort::type type); + QxSqlQuery &addSqlIn(const QVariantList &values, qx::dao::detail::QxSqlIn::type type); + QxSqlQuery &addSqlIsNull(qx::dao::detail::QxSqlIsNull::type type); + QxSqlQuery &addSqlIsBetween(const QVariant &val1, const QVariant &val2, qx::dao::detail::QxSqlIsBetween::type type); + QxSqlQuery &addFreeText(const QString &text, const QVariantList &values); + QxSqlQuery &addEmbedQuery(const QxSqlQuery &query, qx::dao::detail::QxSqlEmbedQuery::type type, bool requirePreviousElement); + }; + +} // namespace qx + +typedef qx::QxSqlQuery qx_query; + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief qx::dao::call_query function can be used to call a custom SQL query or a stored procedure + * + * To get an output value parameter (must be pass as QSql::Out or QSql::InOut) returned by a stored procedure, just call the following method : QVariant qx::QxSqlQuery::boundValue(const QString & sKey) const;.
+ * To iterate over all resultset, just use the following methods : + * - long qx::QxSqlQuery::getSqlResultRowCount() const; + * - long qx::QxSqlQuery::getSqlResultColumnCount() const; + * - QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const; + * - QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) const; + * - QVector qx::QxSqlQuery::getSqlResultAllColumns() const; + * - void qx::QxSqlQuery::dumpSqlResult(); + * + * Here is an example of code using qx::dao::call_query function : + * \code + qx_query query("CALL MyStoredProc(:param1, :param2)"); + query.bind(":param1", "myValue1"); + query.bind(":param2", 5024, QSql::InOut); + QSqlError daoError = qx::dao::call_query(query); + QVariant vNewValue = query.boundValue(":param2"); + query.dumpSqlResult(); + * \endcode + */ + QX_DLL_EXPORT QSqlError call_query(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + + /*! + * \ingroup QxDao + * \brief qx::dao::call_query_without_prepare function can be used to call a custom SQL query or a stored procedure : same as qx::dao::call_query() function without calling prepare() QSqlQuery class method (can be useful to execute some specific SQL queries) + */ + QX_DLL_EXPORT QSqlError call_query_without_prepare(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL); + + namespace helper + { + + QX_DLL_EXPORT QSqlError call_query_helper(qx::QxSqlQuery &query, QSqlDatabase *pDatabase, bool bPrepare); + + } // namespace helper + } // namespace dao +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx_query) + +QX_CLASS_VERSION(qx::QxSqlQuery, 0) + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, qx::QxSqlQuery) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_HPP(className) \ +public: \ + virtual className &distinct(); \ + \ + virtual className &where(const QString &column); \ + virtual className &where_OpenParenthesis(const QString &column); \ + virtual className &and_(const QString &column); \ + virtual className &and_OpenParenthesis(const QString &column); \ + virtual className &or_(const QString &column); \ + virtual className &or_OpenParenthesis(const QString &column); \ + \ + virtual className &openParenthesis(); \ + virtual className &closeParenthesis(); \ + \ + virtual className &orderAsc(const QStringList &columns); \ + virtual className &orderAsc(const QString &col1); \ + virtual className &orderAsc(const QString &col1, const QString &col2); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); \ + virtual className &orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); \ + \ + virtual className &orderDesc(const QStringList &columns); \ + virtual className &orderDesc(const QString &col1); \ + virtual className &orderDesc(const QString &col1, const QString &col2); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); \ + virtual className &orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); \ + \ + virtual className &groupBy(const QStringList &columns); \ + virtual className &groupBy(const QString &col1); \ + virtual className &groupBy(const QString &col1, const QString &col2); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8); \ + virtual className &groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9); \ + \ + virtual className &limit(int rowsCount, int startRow = 0, bool withTies = false); \ + \ + virtual className &like(const QString &val); \ + virtual className ¬Like(const QString &val); \ + virtual className &startsWith(const QString &val); \ + virtual className &endsWith(const QString &val); \ + virtual className &containsString(const QString &val); \ + \ + virtual className &isEqualTo(const QVariant &val); \ + virtual className &isNotEqualTo(const QVariant &val); \ + virtual className &isGreaterThan(const QVariant &val); \ + virtual className &isGreaterThanOrEqualTo(const QVariant &val); \ + virtual className &isLessThan(const QVariant &val); \ + virtual className &isLessThanOrEqualTo(const QVariant &val); \ + virtual className &customOperator(const QString &sCustomOperator, const QVariant &val); \ + \ + virtual className &in(const QVariantList &values); \ + virtual className &in(const QVariant &val1); \ + virtual className &in(const QVariant &val1, const QVariant &val2); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8); \ + virtual className &in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9); \ + \ + virtual className ¬In(const QVariantList &values); \ + virtual className ¬In(const QVariant &val1); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8); \ + virtual className ¬In(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9); \ + \ + virtual className &in_Select(const QxSqlQuery &query); \ + virtual className ¬In_Select(const QxSqlQuery &query); \ + virtual className &isEqualTo_Select(const QxSqlQuery &query); \ + virtual className &isNotEqualTo_Select(const QxSqlQuery &query); \ + \ + virtual className &isNull(); \ + virtual className &isNotNull(); \ + \ + virtual className &isBetween(const QVariant &val1, const QVariant &val2); \ + virtual className &isNotBetween(const QVariant &val1, const QVariant &val2); \ + \ + virtual className &freeText(const QString &text, const QVariantList &values = QVariantList()); \ + \ + virtual className &addJoinQuery(const QString &relationKeyOrAlias, const QxSqlQuery &joinQuery); + +#define QX_SQL_QUERY_DERIVED_IMPL_COVARIANT_RETURN_TYPE_CPP(className) \ + \ + className &className::distinct() { return static_cast(qx::QxSqlQuery::distinct()); } \ + \ + className &className::where(const QString &column) { return static_cast(qx::QxSqlQuery::where(column)); } \ + className &className::where_OpenParenthesis(const QString &column) { return static_cast(qx::QxSqlQuery::where_OpenParenthesis(column)); } \ + className &className::and_(const QString &column) { return static_cast(qx::QxSqlQuery::and_(column)); } \ + className &className::and_OpenParenthesis(const QString &column) { return static_cast(qx::QxSqlQuery::and_OpenParenthesis(column)); } \ + className &className::or_(const QString &column) { return static_cast(qx::QxSqlQuery::or_(column)); } \ + className &className::or_OpenParenthesis(const QString &column) { return static_cast(qx::QxSqlQuery::or_OpenParenthesis(column)); } \ + \ + className &className::openParenthesis() { return static_cast(qx::QxSqlQuery::openParenthesis()); } \ + className &className::closeParenthesis() { return static_cast(qx::QxSqlQuery::closeParenthesis()); } \ + \ + className &className::orderAsc(const QStringList &columns) { return static_cast(qx::QxSqlQuery::orderAsc(columns)); } \ + className &className::orderAsc(const QString &col1) { return static_cast(qx::QxSqlQuery::orderAsc(col1)); } \ + className &className::orderAsc(const QString &col1, const QString &col2) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4, col5)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4, col5, col6)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4, col5, col6, col7)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4, col5, col6, col7, col8)); } \ + className &className::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) { return static_cast(qx::QxSqlQuery::orderAsc(col1, col2, col3, col4, col5, col6, col7, col8, col9)); } \ + \ + className &className::orderDesc(const QStringList &columns) { return static_cast(qx::QxSqlQuery::orderDesc(columns)); } \ + className &className::orderDesc(const QString &col1) { return static_cast(qx::QxSqlQuery::orderDesc(col1)); } \ + className &className::orderDesc(const QString &col1, const QString &col2) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4, col5)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4, col5, col6)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4, col5, col6, col7)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4, col5, col6, col7, col8)); } \ + className &className::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) { return static_cast(qx::QxSqlQuery::orderDesc(col1, col2, col3, col4, col5, col6, col7, col8, col9)); } \ + \ + className &className::groupBy(const QStringList &columns) { return static_cast(qx::QxSqlQuery::groupBy(columns)); } \ + className &className::groupBy(const QString &col1) { return static_cast(qx::QxSqlQuery::groupBy(col1)); } \ + className &className::groupBy(const QString &col1, const QString &col2) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4, col5)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4, col5, col6)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4, col5, col6, col7)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4, col5, col6, col7, col8)); } \ + className &className::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) { return static_cast(qx::QxSqlQuery::groupBy(col1, col2, col3, col4, col5, col6, col7, col8, col9)); } \ + \ + className &className::limit(int rowsCount, int startRow, bool withTies) { return static_cast(qx::QxSqlQuery::limit(rowsCount, startRow, withTies)); } \ + \ + className &className::like(const QString &val) { return static_cast(qx::QxSqlQuery::like(val)); } \ + className &className::notLike(const QString &val) { return static_cast(qx::QxSqlQuery::notLike(val)); } \ + className &className::startsWith(const QString &val) { return static_cast(qx::QxSqlQuery::startsWith(val)); } \ + className &className::endsWith(const QString &val) { return static_cast(qx::QxSqlQuery::endsWith(val)); } \ + className &className::containsString(const QString &val) { return static_cast(qx::QxSqlQuery::containsString(val)); } \ + \ + className &className::isEqualTo(const QVariant &val) { return static_cast(qx::QxSqlQuery::isEqualTo(val)); } \ + className &className::isNotEqualTo(const QVariant &val) { return static_cast(qx::QxSqlQuery::isNotEqualTo(val)); } \ + className &className::isGreaterThan(const QVariant &val) { return static_cast(qx::QxSqlQuery::isGreaterThan(val)); } \ + className &className::isGreaterThanOrEqualTo(const QVariant &val) { return static_cast(qx::QxSqlQuery::isGreaterThanOrEqualTo(val)); } \ + className &className::isLessThan(const QVariant &val) { return static_cast(qx::QxSqlQuery::isLessThan(val)); } \ + className &className::isLessThanOrEqualTo(const QVariant &val) { return static_cast(qx::QxSqlQuery::isLessThanOrEqualTo(val)); } \ + className &className::customOperator(const QString &sCustomOperator, const QVariant &val) { return static_cast(qx::QxSqlQuery::customOperator(sCustomOperator, val)); } \ + \ + className &className::in(const QVariantList &values) { return static_cast(qx::QxSqlQuery::in(values)); } \ + className &className::in(const QVariant &val1) { return static_cast(qx::QxSqlQuery::in(val1)); } \ + className &className::in(const QVariant &val1, const QVariant &val2) { return static_cast(qx::QxSqlQuery::in(val1, val2)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4, val5)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4, val5, val6)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4, val5, val6, val7)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4, val5, val6, val7, val8)); } \ + className &className::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9) { return static_cast(qx::QxSqlQuery::in(val1, val2, val3, val4, val5, val6, val7, val8, val9)); } \ + \ + className &className::notIn(const QVariantList &values) { return static_cast(qx::QxSqlQuery::notIn(values)); } \ + className &className::notIn(const QVariant &val1) { return static_cast(qx::QxSqlQuery::notIn(val1)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2) { return static_cast(qx::QxSqlQuery::notIn(val1, val2)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4, val5)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4, val5, val6)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4, val5, val6, val7)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4, val5, val6, val7, val8)); } \ + className &className::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9) { return static_cast(qx::QxSqlQuery::notIn(val1, val2, val3, val4, val5, val6, val7, val8, val9)); } \ + \ + className &className::in_Select(const QxSqlQuery &query) { return static_cast(qx::QxSqlQuery::in_Select(query)); } \ + className &className::notIn_Select(const QxSqlQuery &query) { return static_cast(qx::QxSqlQuery::notIn_Select(query)); } \ + className &className::isEqualTo_Select(const QxSqlQuery &query) { return static_cast(qx::QxSqlQuery::isEqualTo_Select(query)); } \ + className &className::isNotEqualTo_Select(const QxSqlQuery &query) { return static_cast(qx::QxSqlQuery::isNotEqualTo_Select(query)); } \ + \ + className &className::isNull() { return static_cast(qx::QxSqlQuery::isNull()); } \ + className &className::isNotNull() { return static_cast(qx::QxSqlQuery::isNotNull()); } \ + \ + className &className::isBetween(const QVariant &val1, const QVariant &val2) { return static_cast(qx::QxSqlQuery::isBetween(val1, val2)); } \ + className &className::isNotBetween(const QVariant &val1, const QVariant &val2) { return static_cast(qx::QxSqlQuery::isNotBetween(val1, val2)); } \ + \ + className &className::freeText(const QString &text, const QVariantList &values) { return static_cast(qx::QxSqlQuery::freeText(text, values)); } \ + \ + className &className::addJoinQuery(const QString &relationKeyOrAlias, const QxSqlQuery &joinQuery) { return static_cast(qx::QxSqlQuery::addJoinQuery(relationKeyOrAlias, joinQuery)); } + +#endif // _QX_SQL_QUERY_H_ diff --git a/include/QxDao/QxSqlQueryBuilder.h b/include/QxDao/QxSqlQueryBuilder.h new file mode 100644 index 0000000..0ee4e92 --- /dev/null +++ b/include/QxDao/QxSqlQueryBuilder.h @@ -0,0 +1,567 @@ +/**************************************************************************** +** +** 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_SQL_QUERY_BUILDER_H_ +#define _QX_SQL_QUERY_BUILDER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlQueryBuilder.h + * \author XDL Team + * \ingroup QxDao + * \brief Concrete SQL query builder by class with a cache mechanism to backup and restore queries already built by the program + */ + +#include +#include + +#include + +#include +#include +#include + +#define QX_SQL_ERR_NO_DATA_MEMBER_REGISTERED "'QxSqlQueryBuilder' error : 'qx::register_class()' not called or no data member registered" +#define QX_SQL_ERR_NO_ID_REGISTERED "'QxSqlQueryBuilder' error : no id registered" + +#define QX_SQL_BUILDER_INIT_FCT(oper) \ + qx::dao::detail::IxDao_Timer timer(this->getDaoHelper(), qx::dao::detail::IxDao_Helper::timer_build_sql); \ + QString joinQueryHash = (this->getDaoHelper() ? this->getDaoHelper()->qxQuery().getJoinQueryHash() : QString()); \ + QString ignoreSoftDeleteHash = (this->getDaoHelper() ? this->getDaoHelper()->getIgnoreSoftDeleteHash() : QString()); \ + QString key = QxClass::getSingleton()->getKey() + joinQueryHash + ignoreSoftDeleteHash + oper; \ + if ((joinQueryHash.isEmpty()) && (this->findSqlQuery(key))) \ + { \ + return (*this); \ + } \ + QString &sql = this->getCurrentBuildingSql(); \ + sql = ""; + +#define QX_SQL_BUILDER_INIT_FCT_WITH_RELATION(oper) \ + qx::dao::detail::IxDao_Timer timer(this->getDaoHelper(), qx::dao::detail::IxDao_Helper::timer_build_sql); \ + QString joinQueryHash = (this->getDaoHelper() ? this->getDaoHelper()->qxQuery().getJoinQueryHash() : QString()); \ + QString ignoreSoftDeleteHash = (this->getDaoHelper() ? this->getDaoHelper()->getIgnoreSoftDeleteHash() : QString()); \ + QString key = QxClass::getSingleton()->getKey() + joinQueryHash + this->getHashRelation() + ignoreSoftDeleteHash + oper; \ + if ((joinQueryHash.isEmpty()) && (this->findSqlQuery(key))) \ + { \ + this->findSqlAlias(key); \ + return (*this); \ + } \ + QString &sql = this->getCurrentBuildingSql(); \ + sql = ""; + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder : concrete SQL query builder for class T with a cache mechanism to backup and restore queries already built by the program + */ + template + class QxSqlQueryBuilder : public IxSqlQueryBuilder + { + + private: + typedef typename qx::trait::remove_attr::type type_sql_tmp_1; + typedef typename qx::trait::remove_smart_ptr::type type_sql_tmp_2; + + public: + typedef typename qx::QxSqlQueryBuilder::type_sql_tmp_2 type_sql; + + public: + QxSqlQueryBuilder() : IxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder() { static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); } + + virtual void init() + { + if (isInitDone()) + { + return; + } + setDataMemberX(QxClass::getSingleton()->dataMemberX()); + setSoftDelete(QxClass::getSingleton()->getSoftDelete()); + IxSqlQueryBuilder::init(); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_Count : concrete SQL query builder for class T to build a COUNT SQL query + */ + template + class QxSqlQueryBuilder_Count : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_Count() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_Count() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("Count") + sql = "SELECT COUNT(*) FROM " + qx::IxDataMember::getSqlFromTable(this->table()); + if (!this->softDelete().isEmpty()) + { + sql += " WHERE " + this->softDelete().buildSqlQueryToFetch(); + } + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_Exist : concrete SQL query builder for class T to build an EXIST SQL query + */ + template + class QxSqlQueryBuilder_Exist : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_Exist() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_Exist() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("Exist") + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_Exist::sql(sql, (*this)); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_FetchAll : concrete SQL query builder for class T to build a FETCH ALL SQL query + */ + template + class QxSqlQueryBuilder_FetchAll : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_FetchAll() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_FetchAll() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(pRelationX); + + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QX_SQL_BUILDER_INIT_FCT("FetchAll") + qx::dao::detail::QxSqlQueryHelper_FetchAll::sql(sql, (*this)); + this->setSqlQuery(sql, key); + } + else + { + QString sql; + if (!this->verifyColumns(columns)) + { + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_FetchAll::sql(sql, (*this), columns); + this->setSqlQuery(sql); + } + + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_FetchById : concrete SQL query builder for class T to build a FETCH BY ID SQL query + */ + template + class QxSqlQueryBuilder_FetchById : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_FetchById() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_FetchById() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(pRelationX); + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + QxSqlQueryBuilder_FetchAll builder; + builder.clone(*this); + + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QX_SQL_BUILDER_INIT_FCT("FetchById") + qx::dao::detail::QxSqlQueryHelper_FetchById::sql(sql, builder); + this->setSqlQuery(sql, key); + } + else + { + QString sql; + if (!this->verifyColumns(columns)) + { + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_FetchById::sql(sql, builder, columns); + this->setSqlQuery(sql); + } + + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_Insert : concrete SQL query builder for class T to build an INSERT SQL query + */ + template + class QxSqlQueryBuilder_Insert : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_Insert() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_Insert() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("Insert") + qx::dao::detail::QxSqlQueryHelper_Insert::sql(sql, (*this)); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_Update : concrete SQL query builder for class T to build an UPDATE SQL query + */ + template + class QxSqlQueryBuilder_Update : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_Update() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_Update() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(pRelationX); + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QX_SQL_BUILDER_INIT_FCT("Update") + qx::dao::detail::QxSqlQueryHelper_Update::sql(sql, (*this)); + this->setSqlQuery(sql, key); + } + else + { + QString sql; + if (!this->verifyColumns(columns)) + { + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_Update::sql(sql, (*this), columns); + this->setSqlQuery(sql); + } + + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_DeleteAll : concrete SQL query builder for class T to build a DELETE ALL SQL query + */ + template + class QxSqlQueryBuilder_DeleteAll : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_DeleteAll() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_DeleteAll() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("DeleteAll") + sql = "DELETE FROM " + this->table(); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_SoftDeleteAll : concrete SQL query builder for class T to build a SOFT DELETE ALL SQL query + */ + template + class QxSqlQueryBuilder_SoftDeleteAll : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_SoftDeleteAll() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_SoftDeleteAll() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("SoftDeleteAll") + if (!this->softDelete().isEmpty()) + { + sql = "UPDATE " + this->table() + " SET " + this->softDelete().buildSqlQueryToUpdate(); + } + else + { + qAssert(false); + } + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_DeleteById : concrete SQL query builder for class T to build a DELETE BY ID SQL query + */ + template + class QxSqlQueryBuilder_DeleteById : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_DeleteById() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_DeleteById() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("DeleteById") + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_DeleteById::sql(sql, (*this), false); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_SoftDeleteById : concrete SQL query builder for class T to build a SOFT DELETE BY ID SQL query + */ + template + class QxSqlQueryBuilder_SoftDeleteById : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_SoftDeleteById() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_SoftDeleteById() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("SoftDeleteById") + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + if (this->softDelete().isEmpty()) + { + qAssert(false); + return (*this); + } + qx::dao::detail::QxSqlQueryHelper_DeleteById::sql(sql, (*this), true); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_CreateTable : concrete SQL query builder for class T to build a CREATE TABLE SQL query + */ + template + class QxSqlQueryBuilder_CreateTable : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_CreateTable() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_CreateTable() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + Q_UNUSED(pRelationX); + QX_SQL_BUILDER_INIT_FCT("CreateTable") + qx::dao::detail::QxSqlQueryHelper_CreateTable::sql(sql, (*this)); + this->setSqlQuery(sql, key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_Count_WithRelation : concrete SQL query builder for class T to build a COUNT WITH RELATION SQL query + */ + template + class QxSqlQueryBuilder_Count_WithRelation : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_Count_WithRelation() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_Count_WithRelation() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + QX_SQL_BUILDER_INIT_FCT_WITH_RELATION("Count_WithRelation") + IxSqlQueryBuilder::sql_Count_WithRelation(pRelationX, sql, (*this)); + this->setSqlQuery(sql, key); + this->insertSqlAlias(key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_FetchAll_WithRelation : concrete SQL query builder for class T to build a FETCH ALL WITH RELATION SQL query + */ + template + class QxSqlQueryBuilder_FetchAll_WithRelation : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_FetchAll_WithRelation() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_FetchAll_WithRelation() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + QX_SQL_BUILDER_INIT_FCT_WITH_RELATION("FetchAll_WithRelation") + qx::dao::detail::QxSqlQueryHelper_FetchAll_WithRelation::sql(pRelationX, sql, (*this)); + this->setSqlQuery(sql, key); + this->insertSqlAlias(key); + return (*this); + } + }; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlQueryBuilder_FetchById_WithRelation : concrete SQL query builder for class T to build a FETCH BY ID WITH RELATION SQL query + */ + template + class QxSqlQueryBuilder_FetchById_WithRelation : public QxSqlQueryBuilder + { + + public: + typedef typename QxSqlQueryBuilder::type_sql type_sql; + + QxSqlQueryBuilder_FetchById_WithRelation() : QxSqlQueryBuilder() { ; } + virtual ~QxSqlQueryBuilder_FetchById_WithRelation() { ; } + + virtual IxSqlQueryBuilder &buildSql(const QStringList &columns = QStringList(), QxSqlRelationLinked *pRelationX = NULL) + { + Q_UNUSED(columns); + QX_SQL_BUILDER_INIT_FCT_WITH_RELATION("FetchById_WithRelation") + if (!this->getDataId()) + { + qDebug("[QxOrm] %s", QX_SQL_ERR_NO_ID_REGISTERED); + qAssert(false); + return (*this); + } + QxSqlQueryBuilder_FetchAll_WithRelation builder; + builder.clone(*this); + qx::dao::detail::QxSqlQueryHelper_FetchById_WithRelation::sql(pRelationX, sql, builder); + this->setSqlQuery(sql, key); + this->insertSqlAlias(key); + return (*this); + } + }; + +} // namespace qx + +#endif // _QX_SQL_QUERY_BUILDER_H_ diff --git a/include/QxDao/QxSqlQueryHelper.h b/include/QxDao/QxSqlQueryHelper.h new file mode 100644 index 0000000..ea219df --- /dev/null +++ b/include/QxDao/QxSqlQueryHelper.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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_SQL_QUERY_HELPER_H_ +#define _QX_SQL_QUERY_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_CreateTable; + template + struct QxSqlQueryHelper_DeleteById; + template + struct QxSqlQueryHelper_Exist; + template + struct QxSqlQueryHelper_FetchAll; + template + struct QxSqlQueryHelper_FetchAll_WithRelation; + template + struct QxSqlQueryHelper_FetchById; + template + struct QxSqlQueryHelper_FetchById_WithRelation; + template + struct QxSqlQueryHelper_Insert; + template + struct QxSqlQueryHelper_Update; + + } // namespace detail + } // namespace dao +} // namespace qx + +#include "../../inl/QxDao/QxSqlQueryHelper_CreateTable.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_DeleteById.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_Exist.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_FetchAll.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_FetchAll_WithRelation.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_FetchById.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_FetchById_WithRelation.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_Insert.inl" +#include "../../inl/QxDao/QxSqlQueryHelper_Update.inl" + +#endif // _QX_SQL_QUERY_HELPER_H_ diff --git a/include/QxDao/QxSqlRelation.h b/include/QxDao/QxSqlRelation.h new file mode 100644 index 0000000..e1b68fc --- /dev/null +++ b/include/QxDao/QxSqlRelation.h @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_H_ +#define _QX_SQL_RELATION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelation.h + * \author XDL Team + * \ingroup QxDao + * \brief Base class for all relationships defined between 2 classes (or between 2 tables in database) + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace qx +{ + + template + class QxClass; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelation : base class for all relationships defined between 2 classes (or between 2 tables in database) + */ + template + class QxSqlRelation : public IxSqlRelation + { + + protected: + typedef typename qx::trait::remove_attr::type type_tmp_1; + typedef typename qx::trait::remove_smart_ptr::type type_tmp_2; + typedef type_tmp_2 type_container; + typedef qx::trait::generic_container type_generic_container; + typedef typename type_generic_container::type_item type_item; + typedef typename std::conditional::value, typename type_generic_container::type_value_qx, type_container>::type type_tmp_3; + typedef typename QxSqlRelation::type_tmp_3 type_data; + typedef Owner type_owner; + + enum + { + is_valid = (qx::trait::is_qx_registered::value && qx::trait::is_qx_registered::value) + }; + enum + { + is_data_pointer = (std::is_pointer::value || qx::trait::is_smart_ptr::value) + }; + enum + { + is_data_container = qx::trait::is_container::value + }; + enum + { + is_same_data_owner = std::is_same::value + }; + + public: + QxSqlRelation(IxDataMember *p) : IxSqlRelation(p) { this->setIsSameDataOwner(static_cast(is_same_data_owner)); } + virtual ~QxSqlRelation() { static_assert(is_valid, "is_valid"); } + + virtual void init() + { + if (!this->canInit()) + { + return; + } + this->setClass(QxClass::getSingleton(), QxClass::getSingleton()); + IxSqlRelation::init(); + } + + protected: + DataType *getDataTypePtr(QxSqlRelationParams ¶ms) const + { + qAssert(params.owner() && this->getDataMember()); + return static_cast(this->getDataMember()->getValueVoidPtr(params.owner())); + } + + type_owner &getOwner(QxSqlRelationParams ¶ms) const + { + qAssert(params.owner()); + return (*static_cast(params.owner())); + } + + type_data &getData(QxSqlRelationParams ¶ms) const + { + return getData_Helper::get(getDataTypePtr(params)); + } + + type_container &getContainer(QxSqlRelationParams ¶ms) const + { + return getContainer_Helper::get(getDataTypePtr(params)); + } + + type_item createItem() const + { + return createItem_Helper::get(); + } + + bool isNullData(QxSqlRelationParams ¶ms) const + { + return isNullData_Helper::get(getDataTypePtr(params)); + } + + bool callTriggerBeforeFetch(type_data &t, QxSqlRelationParams ¶ms) const + { + if (!params.builder().getDaoHelper()) + { + return true; + } + qx::dao::on_before_fetch((&t), params.builder().getDaoHelper()); + return params.builder().getDaoHelper()->isValid(); + } + + bool callTriggerAfterFetch(type_data &t, QxSqlRelationParams ¶ms) const + { + if (!params.builder().getDaoHelper()) + { + return true; + } + qx::dao::on_after_fetch((&t), params.builder().getDaoHelper()); + return params.builder().getDaoHelper()->isValid(); + } + + private: + template + struct getData_Helper + { + static type_data &get(DataType *t) { return (*t); } + }; + + template + struct getData_Helper + { + static type_data &get(DataType *t) + { + if (!(*t)) + { + qx::trait::construct_ptr::get(*t); + }; + return (**t); + } + }; + + template + struct getData_Helper + { + static type_data &get(DataType *t) + { + qAssert(false); + Q_UNUSED(t); + type_data *pDummy(NULL); + return (*pDummy); + } + }; + + template + struct getData_Helper + { + static type_data &get(DataType *t) + { + qAssert(false); + Q_UNUSED(t); + type_data *pDummy(NULL); + return (*pDummy); + } + }; + + template + struct getContainer_Helper + { + static type_container &get(DataType *t) + { + qAssert(false); + Q_UNUSED(t); + type_container *pDummy(NULL); + return (*pDummy); + } + }; + + template + struct getContainer_Helper + { + static type_container &get(DataType *t) + { + qAssert(false); + Q_UNUSED(t); + type_container *pDummy(NULL); + return (*pDummy); + } + }; + + template + struct getContainer_Helper + { + static type_container &get(DataType *t) { return (*t); } + }; + + template + struct getContainer_Helper + { + static type_container &get(DataType *t) + { + if (!(*t)) + { + qx::trait::construct_ptr::get(*t); + }; + return (**t); + } + }; + + template + struct createItem_Helper + { + static type_item get() + { + qAssert(false); + type_item *pDummy(NULL); + return (*pDummy); + } + }; + + template + struct createItem_Helper + { + static type_item get() { return type_generic_container::createItem(); } + }; + + template + struct isNullData_Helper + { + static bool get(DataType *t) + { + Q_UNUSED(t); + return false; + } + }; + + template + struct isNullData_Helper + { + static bool get(DataType *t) { return ((!(*t)) ? true : false); } + }; + }; + +} // namespace qx + +#include +#include +#include +#include +#include + +#endif // _QX_SQL_RELATION_H_ diff --git a/include/QxDao/QxSqlRelationLinked.h b/include/QxDao/QxSqlRelationLinked.h new file mode 100644 index 0000000..8a65a6c --- /dev/null +++ b/include/QxDao/QxSqlRelationLinked.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_LINKED_H_ +#define _QX_SQL_RELATION_LINKED_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelationLinked.h + * \author XDL Team + * \ingroup QxDao + * \brief Hierarchy of relationships to build SQL query + */ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + class IxDao_Helper; + + } // namespace detail + } // namespace dao +} // namespace qx + +namespace qx +{ + + class IxClass; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelationLinked : hierarchy of relationships to build SQL query + * + * Here is the structure, each real relation has a relation linked associated to build the hierarchy, like this : + * \code + (, ) + ("blog", blog_relation) + ("blog", ) + ("author", author_relation) + ("author", ) + ("list_blog", list_blog_relation) + ("list_blog", ) + (etc...) + ("comment", comment_relation) + ("comment", ) + ("blog_id", blog_id_relation) + ("blog_id", ) + (etc...) + ("category", category_relation) + ("category", ) + ("list_blog", list_blog_relation) + ("list_blog", ) + (etc...) + * \endcode + */ + class QX_DLL_EXPORT QxSqlRelationLinked + { + + public: + typedef std::shared_ptr type_ptr; + typedef std::tuple, long>, QString, bool> type_relation; + typedef qx::QxCollection type_lst_relation; + typedef QHash type_lst_relation_linked; + + private: + struct QxSqlRelationLinkedImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxSqlRelationLinked(); + QxSqlRelationLinked(bool bRoot); + virtual ~QxSqlRelationLinked(); + + static type_ptr getHierarchy(IxClass *pClass, const QStringList &sRelationX, qx_bool &bOk, qx::dao::detail::IxDao_Helper *pDaoHelper = NULL); + + void hierarchySelect(QxSqlRelationParams ¶ms); + void hierarchyFrom(QxSqlRelationParams ¶ms); + void hierarchyJoin(QxSqlRelationParams ¶ms); + void hierarchyWhereSoftDelete(QxSqlRelationParams ¶ms); + void hierarchyResolveOutput(QxSqlRelationParams ¶ms); + QSqlError hierarchyOnBeforeSave(QxSqlRelationParams ¶ms); + QSqlError hierarchyOnAfterSave(QxSqlRelationParams ¶ms); + void updateOffset(QxSqlRelationParams ¶ms); + + bool getCartesianProduct() const; + long getAllRelationCount() const; + long getRelationCount() const; + bool existRelation(const QString &sKey) const; + type_lst_relation_linked getRelationLinkedX() const; + type_lst_relation getRelationX() const; + + bool isRoot() const; + bool checkRootColumns(const QString &s) const; + long getRootColumnsCount() const; + long getRootColumnsOffset() const; + void setRootColumnsOffset(long l); + QString getRootCustomAlias() const; + + protected: + bool isValidDaoHelper(QxSqlRelationParams ¶ms) const; + }; + + typedef std::shared_ptr QxSqlRelationLinked_ptr; + +} // namespace qx + +#endif // _QX_SQL_RELATION_LINKED_H_ diff --git a/include/QxDao/QxSqlRelationParams.h b/include/QxDao/QxSqlRelationParams.h new file mode 100644 index 0000000..9964a38 --- /dev/null +++ b/include/QxDao/QxSqlRelationParams.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_PARAMS_H_ +#define _QX_SQL_RELATION_PARAMS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelationParams.h + * \author XDL Team + * \ingroup QxDao + * \brief Define list of parameters to transfer to relationships to manage SQL queries builded by QxOrm library + */ + +#include +#include + +#include +#include + +#include + +namespace qx +{ + + class QxSqlRelationLinked; + class IxSqlQueryBuilder; + class IxSqlRelation; + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelationParams : define list of parameters to transfer to relationships to manage SQL queries builded by QxOrm library + */ + class QX_DLL_EXPORT QxSqlRelationParams + { + + public: + typedef std::shared_ptr type_relation_linked_ptr; + typedef QHash type_lst_relation_linked; + + protected: + QVariant m_vId; //!< Current id + long m_lIndex; //!< Current SQL relation index + long m_lIndexOwner; //!< Current SQL relation owner index + long m_lOffset; //!< Current SQL query offset + QString *m_sql; //!< Current SQL query + IxSqlQueryBuilder *m_builder; //!< Current SQL query builder + QSqlQuery *m_query; //!< Current SQL query connected to database + QSqlDatabase *m_database; //!< Current SQL database connexion + void *m_pOwner; //!< Owner to current object to resolve input/output + qx::dao::sql_join::join_type m_eJoinType; //!< Current join type to build SQL query : LEFT OUTER JOIN, INNER JOIN, etc... + type_lst_relation_linked *m_pRelationX; //!< Current list of relations used by qx::QxSqlRelationLinked class + QString m_sTableAlias; //!< Current SQL table alias : useful for relationships defined in base class + qx::dao::save_mode::e_save_mode m_eSaveMode; //!< Used to improve performance, if you know that you are just inserting or updating items in database + bool m_bRecursiveMode; //!< Recursive mode to iterate over each level of relationship + QSet m_lstRecursiveItems; //!< Used by recursive process to avoid infinite loop + QPair, long> *m_pColumns; //!< List of relation columns to fetch (syntax : my_relation { column_1, column_2, etc... }), if empty then fetch all columns + QString m_sCustomAlias; //!< Custom SQL table alias instead of generating a new one automatically + QString m_sCustomAliasOwner; //!< Custom SQL table alias owner instead of generating a new one automatically + qx::QxCollection *m_pLstExecBatch; //!< List of data to send to database when QSqlQuery::execBatch() method is used + bool m_bIsDistinct; //!< SQL query of type SELECT DISTINCT + + public: + QxSqlRelationParams(); + QxSqlRelationParams(long lIndex, long lOffset, QString *sql, IxSqlQueryBuilder *builder, QSqlQuery *query, void *pOwner, const QVariant &vId = QVariant(), qx::QxCollection *pLstExecBatch = NULL); + virtual ~QxSqlRelationParams(); + + inline QVariant id() const { return m_vId; } + inline long index() const { return m_lIndex; } + inline long indexOwner() const { return m_lIndexOwner; } + inline long offset() const { return m_lOffset; } + inline QString &sql() + { + qAssert(m_sql); + return (*m_sql); + } + inline const QString &sql() const + { + qAssert(m_sql); + return (*m_sql); + } + inline QSqlQuery &query() + { + qAssert(m_query); + return (*m_query); + } + inline const QSqlQuery &query() const + { + qAssert(m_query); + return (*m_query); + } + inline QSqlDatabase &database() + { + qAssert(m_database); + return (*m_database); + } + inline const QSqlDatabase &database() const + { + qAssert(m_database); + return (*m_database); + } + inline IxSqlQueryBuilder &builder() + { + qAssert(m_builder); + return (*m_builder); + } + inline const IxSqlQueryBuilder &builder() const + { + qAssert(m_builder); + return (*m_builder); + } + inline void *owner() const { return m_pOwner; } + inline qx::dao::sql_join::join_type joinType() const { return m_eJoinType; } + inline type_lst_relation_linked *relationX() const { return m_pRelationX; } + inline QString getTableAlias() const { return m_sTableAlias; } + inline qx::dao::save_mode::e_save_mode saveMode() const { return m_eSaveMode; } + inline bool recursiveMode() const { return m_bRecursiveMode; } + inline bool existRecursiveItem(void *p) const { return m_lstRecursiveItems.contains(p); } + inline QSet getColumns() const { return (m_pColumns ? m_pColumns->first : QSet()); } + inline bool checkColumns(const QString &s) const { return (!m_pColumns || m_pColumns->first.isEmpty() || m_pColumns->first.contains(s)); } + inline long getColumnsCount() const { return (m_pColumns ? m_pColumns->first.count() : 0); } + inline long getColumnsOffset() const { return (m_pColumns ? m_pColumns->second : 0); } + inline QString getCustomAlias() const { return m_sCustomAlias; } + inline QString getCustomAliasOwner() const { return m_sCustomAliasOwner; } + inline qx::QxCollection *getLstExecBatch() const { return m_pLstExecBatch; } + inline bool isDistinct() const { return m_bIsDistinct; } + + inline void setId(const QVariant &vId) { m_vId = vId; } + inline void setIndex(long lIndex) { m_lIndex = lIndex; } + inline void setIndexOwner(long lIndex) { m_lIndexOwner = lIndex; } + inline void setOffset(long lOffset) { m_lOffset = lOffset; } + inline void setSql(QString *sql) { m_sql = sql; } + inline void setQuery(QSqlQuery *query) { m_query = query; } + inline void setDatabase(QSqlDatabase *database) { m_database = database; } + inline void setOwner(void *pOwner) { m_pOwner = pOwner; } + inline void setJoinType(qx::dao::sql_join::join_type e) { m_eJoinType = e; } + inline void setRelationX(type_lst_relation_linked *p) { m_pRelationX = p; } + inline void setTableAlias(const QString &s) { m_sTableAlias = s; } + inline void setSaveMode(qx::dao::save_mode::e_save_mode e) { m_eSaveMode = e; } + inline void setRecursiveMode(bool b) { m_bRecursiveMode = b; } + inline void insertRecursiveItem(void *p) + { + if (p) + { + m_lstRecursiveItems.insert(p); + } + } + inline void setColumns(QPair, long> *p) { m_pColumns = p; } + inline void setColumnsOffset(long l) + { + if (m_pColumns) + { + m_pColumns->second = l; + } + } + inline void setCustomAlias(const QString &s) { m_sCustomAlias = s; } + inline void setCustomAliasOwner(const QString &s) { m_sCustomAliasOwner = s; } + inline void setLstExecBatch(qx::QxCollection *p) { m_pLstExecBatch = p; } + void setBuilder(IxSqlQueryBuilder *builder); + }; + +} // namespace qx + +#endif // _QX_SQL_RELATION_PARAMS_H_ diff --git a/include/QxDao/QxSqlRelation_ManyToMany.h b/include/QxDao/QxSqlRelation_ManyToMany.h new file mode 100644 index 0000000..36aaaee --- /dev/null +++ b/include/QxDao/QxSqlRelation_ManyToMany.h @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_MANY_TO_MANY_H_ +#define _QX_SQL_RELATION_MANY_TO_MANY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelation_ManyToMany.h + * \author XDL Team + * \ingroup QxDao + * \brief Manage a relationship many-to-many defined between 2 classes (or between 2 tables in database) + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelation_ManyToMany : manage a relationship many-to-many defined between 2 classes (or between 2 tables in database) + */ + template + class QxSqlRelation_ManyToMany : public QxSqlRelation + { + + private: + typedef typename QxSqlRelation::type_owner type_owner; + typedef typename QxSqlRelation::type_data type_data; + typedef typename QxSqlRelation::type_container type_container; + typedef typename QxSqlRelation::type_generic_container type_generic_container; + typedef typename QxSqlRelation::type_item type_item; + typedef typename type_generic_container::type_iterator type_iterator; + typedef typename type_item::type_value type_value; + + enum + { + is_data_container = QxSqlRelation::is_data_container + }; + + public: + QxSqlRelation_ManyToMany(IxDataMember *p, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType) : QxSqlRelation(p) + { + this->setRelationType(qx::IxSqlRelation::many_to_many); + this->setExtraTable(sExtraTable); + this->setForeignKeyOwner(sForeignKeyOwner); + this->setForeignKeyDataType(sForeignKeyDataType); + this->verifyParameters(); + } + virtual ~QxSqlRelation_ManyToMany() { static_assert(is_data_container, "is_data_container"); } + + virtual QString getDescription() const { return "relation many-to-many"; } + virtual bool getCartesianProduct() const { return true; } + virtual void createTable(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazySelect(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyJoin(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhereSoftDelete(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveOutput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_Values(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual QSqlError onBeforeSave(QxSqlRelationParams ¶ms) const + { + Q_UNUSED(params); + return QSqlError(); + } + + virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + return this->getIdFromQuery_ManyToMany(bEager, params, iOffset, iNameIndex); + } + + virtual void updateOffset(bool bEager, QxSqlRelationParams ¶ms) const + { + this->updateOffset_ManyToMany(bEager, params); + } + + virtual void eagerSelect(QxSqlRelationParams ¶ms) const + { + this->eagerSelect_ManyToMany(params); + } + + virtual void eagerJoin(QxSqlRelationParams ¶ms) const + { + this->eagerJoin_ManyToMany(params); + } + + virtual void eagerWhereSoftDelete(QxSqlRelationParams ¶ms) const + { + this->eagerWhereSoftDelete_ManyToMany(params); + } + + virtual void *eagerFetch_ResolveOutput(QxSqlRelationParams ¶ms) const + { + if (!this->verifyOffset(params, true)) + { + return NULL; + } + QSqlQuery &query = params.query(); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + long lIndex = 0; + long lOffsetId = ((pId && (!params.isDistinct())) ? pId->getNameCount() : 0); + bool bValidId(false); + long lOffsetOld = params.offset(); + this->updateOffset(true, params); + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + bValidId = (bValidId || qx::trait::is_valid_primary_key(v)); + } + if (!bValidId) + { + return NULL; + } + } + + type_item item = this->createItem(); + type_data &item_val = item.value_qx(); + if (!this->callTriggerBeforeFetch(item_val, params)) + { + return NULL; + } + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + pId->fromVariant((&item_val), v, "", i, qx::cvt::context::e_database); + } + } + else + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = this->getIdFromQuery(true, params, (lOffsetOld + i), i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + } + + long lOffsetRelation = (lOffsetOld + lOffsetId); + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + p->fromVariant((&item_val), query.value(lCurrIndex + lOffsetRelation), -1, qx::cvt::context::e_database); + lCurrIndex++; + } + } + + if (params.relationX()) + { + long lOffsetCurrent = (lCurrIndex + lOffsetRelation); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + void *pOwnerOld = params.owner(); + params.setOwner(&item_val); + lOffsetOld = params.offset(); + params.setOffset(lOffsetCurrent); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazyFetch_ResolveOutput(params); + } + } + params.setOwner(pOwnerOld); + params.setOffset(lOffsetOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + params.setIndexOwner(lIndexOwnerOld); + } + + if (!this->callTriggerAfterFetch(item_val, params)) + { + return NULL; + } + type_value *pValue = type_generic_container::insertItem(this->getContainer(params), item); + if (!type_item::is_value_pointer && pValue) + { + return pValue; + } + return (&item_val); + } + + virtual QSqlError onAfterSave(QxSqlRelationParams ¶ms) const + { + QSqlError daoError; + if (this->isNullData(params)) + { + return this->deleteFromExtraTable(params); + } + if (!params.recursiveMode()) + { + daoError = qx::dao::save(this->getContainer(params), (¶ms.database())); + } + else + { + daoError = qx::dao::save_with_relation_recursive(this->getContainer(params), params.saveMode(), (¶ms.database()), (¶ms)); + } + if (daoError.isValid()) + { + return daoError; + } + daoError = this->deleteFromExtraTable(params); + if (daoError.isValid()) + { + return daoError; + } + daoError = this->insertIntoExtraTable(params); + if (daoError.isValid()) + { + return daoError; + } + return QSqlError(); + } + + virtual QString createExtraTable() const + { + return this->createExtraTable_ManyToMany(); + } + + private: + void verifyParameters() + { + qAssert(!this->getExtraTable().isEmpty() && !this->getForeignKeyOwner().isEmpty() && !this->getForeignKeyDataType().isEmpty() && (this->getForeignKeyOwner() != this->getForeignKeyDataType())); + } + + QSqlError deleteFromExtraTable(QxSqlRelationParams ¶ms) const + { + return this->deleteFromExtraTable_ManyToMany(params); + } + + QSqlError insertIntoExtraTable(QxSqlRelationParams ¶ms) const + { + IxDataMember *pIdOwner = this->getDataIdOwner(); + qAssert(pIdOwner); + IxDataMember *pIdData = this->getDataId(); + qAssert(pIdData); + if (!pIdOwner || !pIdData) + { + return QSqlError(); + } + QStringList lstForeignKeyOwner = this->getForeignKeyOwner().split("|"); + QStringList lstForeignKeyDataType = this->getForeignKeyDataType().split("|"); + qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count()); + qAssert(pIdData->getNameCount() == lstForeignKeyDataType.count()); + + QString sql = "INSERT INTO " + this->getExtraTable() + " ("; + sql += pIdOwner->getSqlName(", ", this->getForeignKeyOwner(), false, (¶ms.builder())); + sql += ", "; + sql += pIdData->getSqlName(", ", this->getForeignKeyDataType(), false, (¶ms.builder())); + sql += ") VALUES ("; + sql += pIdOwner->getSqlPlaceHolder("", -1, ", ", this->getForeignKeyOwner()) + ", " + pIdData->getSqlPlaceHolder("", -1, ", ", this->getForeignKeyDataType()) + ")"; + if (this->traceSqlQuery()) + { + qDebug("[QxOrm] sql query (extra-table) : %s", qPrintable(sql)); + } + + type_item item; + type_container &container = this->getContainer(params); + type_iterator itr = type_generic_container::begin(container, item); + type_iterator itr_end = type_generic_container::end(container); + QSqlQuery queryInsert(params.database()); + if (!queryInsert.prepare(sql)) + { + return queryInsert.lastError(); + } + + while (itr != itr_end) + { + pIdOwner->setSqlPlaceHolder(queryInsert, params.owner(), "", this->getForeignKeyOwner()); + pIdData->setSqlPlaceHolder(queryInsert, (&item.value_qx()), "", this->getForeignKeyDataType()); + if (!queryInsert.exec()) + { + return queryInsert.lastError(); + } + itr = type_generic_container::next(container, itr, item); + } + + return QSqlError(); + } + }; + +} // namespace qx + +#endif // _QX_SQL_RELATION_MANY_TO_MANY_H_ diff --git a/include/QxDao/QxSqlRelation_ManyToOne.h b/include/QxDao/QxSqlRelation_ManyToOne.h new file mode 100644 index 0000000..7c49292 --- /dev/null +++ b/include/QxDao/QxSqlRelation_ManyToOne.h @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_MANY_TO_ONE_H_ +#define _QX_SQL_RELATION_MANY_TO_ONE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelation_ManyToOne.h + * \author XDL Team + * \ingroup QxDao + * \brief Manage a relationship many-to-one defined between 2 classes (or between 2 tables in database) + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelation_ManyToOne : manage a relationship many-to-one defined between 2 classes (or between 2 tables in database) + */ + template + class QxSqlRelation_ManyToOne : public QxSqlRelation + { + + private: + typedef typename QxSqlRelation::type_owner type_owner; + typedef typename QxSqlRelation::type_data type_data; + + public: + QxSqlRelation_ManyToOne(IxDataMember *p) : QxSqlRelation(p) { this->setRelationType(qx::IxSqlRelation::many_to_one); } + virtual ~QxSqlRelation_ManyToOne() { ; } + + virtual QString getDescription() const { return "relation many-to-one"; } + virtual QString createExtraTable() const { return ""; } + virtual bool getCartesianProduct() const { return false; } + virtual void lazyFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyJoin(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhereSoftDelete(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual QSqlError onAfterSave(QxSqlRelationParams ¶ms) const + { + Q_UNUSED(params); + return QSqlError(); + } + + virtual QSqlError onBeforeSave(QxSqlRelationParams ¶ms) const + { + if (this->isNullData(params) || params.recursiveMode()) + { + return QSqlError(); + } + return qx::dao::save(this->getData(params), (¶ms.database())); + } + + virtual void lazyUpdate_ResolveInput(QxSqlRelationParams ¶ms) const + { + this->lazyInsert_ResolveInput(params); + } + + virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + return this->getIdFromQuery_ManyToOne(bEager, params, iOffset, iNameIndex); + } + + virtual void updateOffset(bool bEager, QxSqlRelationParams ¶ms) const + { + this->updateOffset_ManyToOne(bEager, params); + } + + virtual void createTable(QxSqlRelationParams ¶ms) const + { + this->createTable_ManyToOne(params); + } + + virtual void lazySelect(QxSqlRelationParams ¶ms) const + { + this->lazySelect_ManyToOne(params); + } + + virtual void eagerSelect(QxSqlRelationParams ¶ms) const + { + this->eagerSelect_ManyToOne(params); + } + + virtual void eagerJoin(QxSqlRelationParams ¶ms) const + { + this->eagerJoin_ManyToOne(params); + } + + virtual void eagerWhereSoftDelete(QxSqlRelationParams ¶ms) const + { + this->eagerWhereSoftDelete_ManyToOne(params); + } + + virtual void lazyFetch_ResolveOutput(QxSqlRelationParams ¶ms) const + { + if (!this->verifyOffset(params, false)) + { + return; + } + QSqlQuery &query = params.query(); + typename QxSqlRelation::type_owner &currOwner = this->getOwner(params); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (!pData) + { + return; + } + bool bValidId(false); + for (int i = 0; i < pData->getNameCount(); i++) + { + QVariant vId = query.value(params.offset() + i); + bValidId = (bValidId || qx::trait::is_valid_primary_key(vId)); + } + if (pData && bValidId) + { + for (int i = 0; i < pData->getNameCount(); i++) + { + pData->fromVariant((&currOwner), query.value(params.offset() + i), i, qx::cvt::context::e_database); + } + } + this->updateOffset(false, params); + } + + virtual void *eagerFetch_ResolveOutput(QxSqlRelationParams ¶ms) const + { + if (!this->verifyOffset(params, false)) + { + return NULL; + } + QSqlQuery &query = params.query(); + typename QxSqlRelation::type_owner &currOwner = this->getOwner(params); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (!pData) + { + return NULL; + } + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + if (!pId) + { + return NULL; + } + long lIndex = 0; + long lOffsetId = ((pId && (!params.isDistinct())) ? pId->getNameCount() : 0); + long lOffsetData = ((pData && (!params.isDistinct())) ? pData->getNameCount() : 0); + long lOffsetOld = params.offset(); + this->updateOffset(true, params); + long lOffsetRelation = (lOffsetOld + lOffsetId + lOffsetData); + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + bool bValidId(false), bValidIdBis(false); + + if (!params.isDistinct()) + { + for (int i = 0; i < pData->getNameCount(); i++) + { + QVariant vId = query.value(lOffsetOld + i); + bValidId = (bValidId || qx::trait::is_valid_primary_key(vId)); + } + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant vIdBis = query.value(lOffsetOld + lOffsetData + i); + bValidIdBis = (bValidIdBis || qx::trait::is_valid_primary_key(vIdBis)); + } + if (pData && bValidId) + { + for (int i = 0; i < pData->getNameCount(); i++) + { + pData->fromVariant((&currOwner), query.value(lOffsetOld + i), i, qx::cvt::context::e_database); + } + } + if (!bValidIdBis) + { + return NULL; + } + } + + type_data &currData = this->getData(params); + if (!this->callTriggerBeforeFetch(currData, params)) + { + return NULL; + } + + if (pId && (!params.isDistinct())) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + pId->fromVariant((&currData), query.value(lOffsetOld + lOffsetData + i), i, qx::cvt::context::e_database); + } + } + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + p->fromVariant((&currData), query.value(lOffsetRelation++), -1, qx::cvt::context::e_database); + } + } + + if (params.relationX()) + { + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + void *pOwnerOld = params.owner(); + params.setOwner(&currData); + lOffsetOld = params.offset(); + params.setOffset(lOffsetRelation++); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazyFetch_ResolveOutput(params); + } + } + params.setOwner(pOwnerOld); + params.setOffset(lOffsetOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + params.setIndexOwner(lIndexOwnerOld); + } + + if (!this->callTriggerAfterFetch(currData, params)) + { + return NULL; + } + return (&currData); + } + + virtual void lazyInsert(QxSqlRelationParams ¶ms) const + { + this->lazyInsert_ManyToOne(params); + } + + virtual void lazyInsert_Values(QxSqlRelationParams ¶ms) const + { + this->lazyInsert_Values_ManyToOne(params); + } + + virtual void lazyUpdate(QxSqlRelationParams ¶ms) const + { + this->lazyUpdate_ManyToOne(params); + } + + virtual void lazyInsert_ResolveInput(QxSqlRelationParams ¶ms) const + { + QSqlQuery &query = params.query(); + typename QxSqlRelation::type_owner &currOwner = this->getOwner(params); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (pData) + { + pData->setSqlPlaceHolder(query, (&currOwner), "", "", false, params.getLstExecBatch()); + } + } + }; + +} // namespace qx + +#endif // _QX_SQL_RELATION_MANY_TO_ONE_H_ diff --git a/include/QxDao/QxSqlRelation_OneToMany.h b/include/QxDao/QxSqlRelation_OneToMany.h new file mode 100644 index 0000000..dfb131d --- /dev/null +++ b/include/QxDao/QxSqlRelation_OneToMany.h @@ -0,0 +1,322 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_ONE_TO_MANY_H_ +#define _QX_SQL_RELATION_ONE_TO_MANY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelation_OneToMany.h + * \author XDL Team + * \ingroup QxDao + * \brief Manage a relationship one-to-many defined between 2 classes (or between 2 tables in database) + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelation_OneToMany : manage a relationship one-to-many defined between 2 classes (or between 2 tables in database) + */ + template + class QxSqlRelation_OneToMany : public QxSqlRelation + { + + private: + typedef typename QxSqlRelation::type_owner type_owner; + typedef typename QxSqlRelation::type_data type_data; + typedef typename QxSqlRelation::type_container type_container; + typedef typename QxSqlRelation::type_generic_container type_generic_container; + typedef typename QxSqlRelation::type_item type_item; + typedef typename type_generic_container::type_iterator type_iterator; + typedef typename type_item::type_value type_value; + + enum + { + is_data_container = QxSqlRelation::is_data_container + }; + + public: + QxSqlRelation_OneToMany(IxDataMember *p, const QString &sForeignKey) : QxSqlRelation(p) + { + this->setRelationType(qx::IxSqlRelation::one_to_many); + this->setForeignKey(sForeignKey); + qAssert(!this->getForeignKey().isEmpty()); + } + virtual ~QxSqlRelation_OneToMany() { static_assert(is_data_container, "is_data_container"); } + + virtual QString getDescription() const { return "relation one-to-many"; } + virtual QString createExtraTable() const { return ""; } + virtual bool getCartesianProduct() const { return true; } + virtual void createTable(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazySelect(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyJoin(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhereSoftDelete(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveOutput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_Values(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual QSqlError onBeforeSave(QxSqlRelationParams ¶ms) const + { + Q_UNUSED(params); + return QSqlError(); + } + + virtual QSqlError onAfterSave(QxSqlRelationParams ¶ms) const + { + if (this->isNullData(params)) + { + return QSqlError(); + } + this->forceParentIdToAllChildren(params); + if (!params.recursiveMode()) + { + return qx::dao::save(this->getContainer(params), (¶ms.database())); + } + else + { + return qx::dao::save_with_relation_recursive(this->getContainer(params), params.saveMode(), (¶ms.database()), (¶ms)); + } + } + + virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + return this->getIdFromQuery_OneToMany(bEager, params, iOffset, iNameIndex); + } + + virtual void updateOffset(bool bEager, QxSqlRelationParams ¶ms) const + { + this->updateOffset_OneToMany(bEager, params); + } + + virtual void eagerSelect(QxSqlRelationParams ¶ms) const + { + this->eagerSelect_OneToMany(params); + } + + virtual void eagerJoin(QxSqlRelationParams ¶ms) const + { + this->eagerJoin_OneToMany(params); + } + + virtual void eagerWhereSoftDelete(QxSqlRelationParams ¶ms) const + { + this->eagerWhereSoftDelete_OneToMany(params); + } + + virtual void *eagerFetch_ResolveOutput(QxSqlRelationParams ¶ms) const + { + if (!this->verifyOffset(params, true)) + { + return NULL; + } + QSqlQuery &query = params.query(); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + if (!pId) + { + return NULL; + } + IxDataMember *pForeign = this->getDataByKey(this->getForeignKey()); + qAssert(pForeign); + if (!pForeign) + { + return NULL; + } + long lIndex = 0; + long lOffsetId = ((pId && (!params.isDistinct())) ? pId->getNameCount() : 0); + long lOffsetForeign = ((pForeign && (!params.isDistinct())) ? pForeign->getNameCount() : 0); + long lOffsetOld = params.offset(); + this->updateOffset(true, params); + long lOffsetRelation = (lOffsetOld + lOffsetId + lOffsetForeign); + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + bool bValidId(false), bValidForeign(false); + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant vId = query.value(lOffsetOld + i); + bValidId = (bValidId || qx::trait::is_valid_primary_key(vId)); + } + for (int i = 0; i < pForeign->getNameCount(); i++) + { + QVariant vForeign = query.value(lOffsetOld + lOffsetId + i); + bValidForeign = (bValidForeign || qx::trait::is_valid_primary_key(vForeign)); + } + if (!bValidId || !bValidForeign) + { + return NULL; + } + } + + type_item item = this->createItem(); + type_data &item_val = item.value_qx(); + if (!this->callTriggerBeforeFetch(item_val, params)) + { + return NULL; + } + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + pId->fromVariant((&item_val), v, "", i, qx::cvt::context::e_database); + } + for (int i = 0; i < pForeign->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + lOffsetId + i); + pForeign->fromVariant((&item_val), v, "", i, qx::cvt::context::e_database); + } + } + else + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = this->getIdFromQuery(true, params, (lOffsetOld + i), i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + } + + while ((p = this->nextData(lIndex))) + { + if ((p != pForeign) && (params.checkColumns(p->getKey()))) + { + p->fromVariant((&item_val), query.value(lOffsetRelation++), -1, qx::cvt::context::e_database); + } + } + + if (params.relationX()) + { + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + void *pOwnerOld = params.owner(); + params.setOwner(&item_val); + lOffsetOld = params.offset(); + params.setOffset(lOffsetRelation++); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazyFetch_ResolveOutput(params); + } + } + params.setOwner(pOwnerOld); + params.setOffset(lOffsetOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + params.setIndexOwner(lIndexOwnerOld); + } + + if (!this->callTriggerAfterFetch(item_val, params)) + { + return NULL; + } + type_value *pValue = type_generic_container::insertItem(this->getContainer(params), item); + if (!type_item::is_value_pointer && pValue) + { + return pValue; + } + return (&item_val); + } + + private: + void forceParentIdToAllChildren(QxSqlRelationParams ¶ms) const + { + bool bForce = qx::QxSqlDatabase::getSingleton()->getForceParentIdToAllChildren(); + if (!bForce || !params.owner()) + { + return; + } + IxDataMember *pIdOwner = this->getDataIdOwner(); + if (!pIdOwner) + { + return; + } + IxDataMember *pForeign = this->getDataByKey(this->getForeignKey()); + if (!pForeign) + { + return; + } + if (pIdOwner->getNameCount() != pForeign->getNameCount()) + { + return; + } + + QList vIdOwner; + for (int i = 0; i < pIdOwner->getNameCount(); i++) + { + vIdOwner.append(pIdOwner->toVariant(params.owner(), i, qx::cvt::context::e_database)); + } + + type_item item; + type_container &container = this->getContainer(params); + type_iterator itr = type_generic_container::begin(container, item); + type_iterator itr_end = type_generic_container::end(container); + + while (itr != itr_end) + { + type_data &item_val = item.value_qx(); + for (int i = 0; i < vIdOwner.count(); i++) + { + pForeign->fromVariant((&item_val), vIdOwner.at(i), "", i, qx::cvt::context::e_database); + } + itr = type_generic_container::next(container, itr, item); + } + } + }; + +} // namespace qx + +#endif // _QX_SQL_RELATION_ONE_TO_MANY_H_ diff --git a/include/QxDao/QxSqlRelation_OneToOne.h b/include/QxDao/QxSqlRelation_OneToOne.h new file mode 100644 index 0000000..831f2ae --- /dev/null +++ b/include/QxDao/QxSqlRelation_OneToOne.h @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** 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_SQL_RELATION_ONE_TO_ONE_H_ +#define _QX_SQL_RELATION_ONE_TO_ONE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlRelation_OneToOne.h + * \author XDL Team + * \ingroup QxDao + * \brief Manage a relationship one-to-one defined between 2 classes (or between 2 tables in database) + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxSqlRelation_OneToOne : manage a relationship one-to-one defined between 2 classes (or between 2 tables in database) + */ + template + class QxSqlRelation_OneToOne : public QxSqlRelation + { + + private: + typedef typename QxSqlRelation::type_owner type_owner; + typedef typename QxSqlRelation::type_data type_data; + + public: + QxSqlRelation_OneToOne(IxDataMember *p) : QxSqlRelation(p) { this->setRelationType(qx::IxSqlRelation::one_to_one); } + virtual ~QxSqlRelation_OneToOne() { ; } + + virtual QString getDescription() const { return "relation one-to-one"; } + virtual QString createExtraTable() const { return ""; } + virtual bool getCartesianProduct() const { return false; } + virtual void createTable(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazySelect(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFrom(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyJoin(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerWhere(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyWhereSoftDelete(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void eagerFetch_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyFetch_ResolveOutput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_Values(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyInsert_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual void lazyUpdate_ResolveInput(QxSqlRelationParams ¶ms) const { Q_UNUSED(params); } + virtual QSqlError onBeforeSave(QxSqlRelationParams ¶ms) const + { + Q_UNUSED(params); + return QSqlError(); + } + + virtual QSqlError onAfterSave(QxSqlRelationParams ¶ms) const + { + if (this->isNullData(params)) + { + return QSqlError(); + } + if (!params.recursiveMode()) + { + return qx::dao::save(this->getData(params), (¶ms.database())); + } + else + { + return qx::dao::save_with_relation_recursive(this->getData(params), params.saveMode(), (¶ms.database()), (¶ms)); + } + } + + virtual QVariant getIdFromQuery(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + return this->getIdFromQuery_OneToOne(bEager, params, iOffset, iNameIndex); + } + + virtual void updateOffset(bool bEager, QxSqlRelationParams ¶ms) const + { + this->updateOffset_OneToOne(bEager, params); + } + + virtual void eagerSelect(QxSqlRelationParams ¶ms) const + { + this->eagerSelect_OneToOne(params); + } + + virtual void eagerJoin(QxSqlRelationParams ¶ms) const + { + this->eagerJoin_OneToOne(params); + } + + virtual void eagerWhereSoftDelete(QxSqlRelationParams ¶ms) const + { + this->eagerWhereSoftDelete_OneToOne(params); + } + + virtual void *eagerFetch_ResolveOutput(QxSqlRelationParams ¶ms) const + { + if (!this->verifyOffset(params, true)) + { + return NULL; + } + QSqlQuery &query = params.query(); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + if (!pId) + { + return NULL; + } + long lIndex = 0; + long lOffsetId = ((pId && (!params.isDistinct())) ? pId->getNameCount() : 0); + bool bValidId(false); + long lOffsetOld = params.offset(); + this->updateOffset(true, params); + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + bValidId = (bValidId || qx::trait::is_valid_primary_key(v)); + } + if (!bValidId) + { + return NULL; + } + } + + type_data &currData = this->getData(params); + if (!this->callTriggerBeforeFetch(currData, params)) + { + return NULL; + } + + if (!params.isDistinct()) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = query.value(lOffsetOld + i); + pId->fromVariant((&currData), v, i, qx::cvt::context::e_database); + } + } + + long lOffsetRelation = (lOffsetOld + lOffsetId); + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + p->fromVariant((&currData), query.value(lCurrIndex + lOffsetRelation), -1, qx::cvt::context::e_database); + lCurrIndex++; + } + } + + if (params.relationX()) + { + long lOffsetCurrent = (lCurrIndex + lOffsetRelation); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + void *pOwnerOld = params.owner(); + params.setOwner(&currData); + lOffsetOld = params.offset(); + params.setOffset(lOffsetCurrent); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazyFetch_ResolveOutput(params); + } + } + params.setOwner(pOwnerOld); + params.setOffset(lOffsetOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + params.setIndexOwner(lIndexOwnerOld); + } + + if (!this->callTriggerAfterFetch(currData, params)) + { + return NULL; + } + return (&currData); + } + }; + +} // namespace qx + +#endif // _QX_SQL_RELATION_ONE_TO_ONE_H_ diff --git a/include/QxDao/QxSqlRelation_RawData.h b/include/QxDao/QxSqlRelation_RawData.h new file mode 100644 index 0000000..d5df3c0 --- /dev/null +++ b/include/QxDao/QxSqlRelation_RawData.h @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ diff --git a/include/QxDao/QxSqlSaveMode.h b/include/QxDao/QxSqlSaveMode.h new file mode 100644 index 0000000..d2c2748 --- /dev/null +++ b/include/QxDao/QxSqlSaveMode.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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_SQL_SAVE_MODE_H_ +#define _QX_SQL_SAVE_MODE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSqlSaveMode.h + * \author XDL Team + * \ingroup QxDao + * \brief To improve performance, if you know that you are just inserting or updating items in database + */ + +namespace qx +{ + namespace dao + { + + /*! + * \ingroup QxDao + * \brief qx::dao::save_mode : to improve performance, if you know that you are just inserting or updating items in database + */ + struct save_mode + { + + enum e_save_mode + { + e_none, + e_check_insert_or_update, + e_insert_only, + e_update_only + }; + }; + + } // namespace dao +} // namespace qx + +#endif // _QX_SQL_SAVE_MODE_H_ diff --git a/include/QxDao/QxTimeNeutral.h b/include/QxDao/QxTimeNeutral.h new file mode 100644 index 0000000..f44c53e --- /dev/null +++ b/include/QxDao/QxTimeNeutral.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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_TIME_NEUTRAL_H_ +#define _QX_TIME_NEUTRAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxTimeNeutral.h + * \author XDL Team + * \ingroup QxDao + * \brief Helper class to store a time value into database under neutral format (HHMMSS) => cross database compatibility + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include + +#include + +#include + +namespace qx +{ + class QxTimeNeutral; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxTimeNeutral &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxTimeNeutral &t) QX_USED; + +namespace qx +{ + + /*! + * \ingroup QxDao + * \brief qx::QxTimeNeutral : helper class to store a time value into database under neutral format (HHMMSS) => cross database compatibility + */ + class QxTimeNeutral + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxTimeNeutral &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxTimeNeutral &t); + + private: + QTime m_time; //!< Data value under QTime format from Qt library + QString m_neutral; //!< Data value under neutral format 'hhmmss' + + public: + QxTimeNeutral() { ; } + explicit QxTimeNeutral(const QTime &time) : m_time(time) { update(); } + explicit QxTimeNeutral(const QString &neutral) : m_neutral(neutral) { update(); } + virtual ~QxTimeNeutral() { ; } + + inline QTime toTime() const { return m_time; } + inline QString toNeutral() const { return m_neutral; } + inline bool isValid() const { return m_time.isValid(); } + + inline void setTime(const QTime &time) + { + m_neutral = ""; + m_time = time; + update(); + } + inline void setNeutral(const QString &neutral) + { + m_time = QTime(); + m_neutral = neutral; + update(); + } + + static QxTimeNeutral fromTime(const QTime &time) { return QxTimeNeutral(time); } + static QxTimeNeutral fromNeutral(const QString &neutral) { return QxTimeNeutral(neutral); } + + private: + static inline const char *format() { return "hhmmss"; } + + void update() + { + if (m_neutral.isEmpty() && !m_time.isValid()) + { + return; + } + else if (m_time.isValid()) + { + m_neutral = m_time.toString(format()); + } + else + { + qAssert(m_neutral.size() == QString(format()).size()); + m_time = QTime::fromString(m_neutral, format()); + qAssert(m_time.isValid()); + } + } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("time_neutral", m_neutral); + if (Archive::is_loading::value) + { + m_time = QTime(); + update(); + } + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::QxTimeNeutral) + +#endif // _QX_TIME_NEUTRAL_H_ diff --git a/include/QxDaoRepository.h b/include/QxDaoRepository.h new file mode 100644 index 0000000..9a3f628 --- /dev/null +++ b/include/QxDaoRepository.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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_REPOSITORY_H_ +#define _QX_DAO_REPOSITORY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDaoRepository.h + * \author XDL Team + * \ingroup QxDao + * \brief Include all headers required to use repository pattern + */ + +#include + +#include +#include +#include + +#endif // _QX_DAO_REPOSITORY_H_ diff --git a/include/QxDataMember/IxDataMember.h b/include/QxDataMember/IxDataMember.h new file mode 100644 index 0000000..66a9ccb --- /dev/null +++ b/include/QxDataMember/IxDataMember.h @@ -0,0 +1,430 @@ +/**************************************************************************** +** +** 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 _IX_DATA_MEMBER_H_ +#define _IX_DATA_MEMBER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxDataMember.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Common interface for all class properties registered into QxOrm context + */ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#endif // _MSC_VER + +#include +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include +#include +#include + +#include + +#include + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#define QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(ArchiveInput, ArchiveOutput) \ + virtual void toArchive(const void *pOwner, ArchiveOutput &ar) const = 0; \ + virtual void fromArchive(void *pOwner, ArchiveInput &ar) = 0; + +namespace qx +{ + + class IxDataMemberX; + class IxSqlRelation; + class IxSqlQueryBuilder; + struct IxDataMemberSqlCallbackParams; + + namespace dao + { + namespace detail + { + + class IxDao_Helper; + + } // namespace detail + } // namespace dao + + /*! + * \ingroup QxDataMember + * \brief qx::IxDataMember : common interface for all class properties registered into QxOrm context + */ + class QX_DLL_EXPORT IxDataMember : public qx::QxPropertyBag + { + + template + friend class QxDataMember; + + public: + typedef std::function type_fct_sql_callback; + + private: + struct IxDataMemberImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + static QMutex m_mutex; //!< Mutex => qx::IxDataMember is thread-safe + + public: + IxDataMember(const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl); + virtual ~IxDataMember() = 0; + + QString getKey() const; + QString getName() const; + int getNameCount() const; + QString getNameParent() const; + const char *getNamePtr() const; + QString getDescription() const; + QString getFormat() const; + long getVersion() const; + bool getSerialize() const; + bool getDao() const; + QVariant getDefaultValue() const; + QVariant getMinValue() const; + QVariant getMaxValue() const; + int getPrecision() const; + int getMinLength() const; + int getMaxLength() const; + bool getRequired() const; + bool getReadOnly() const; + bool getAutoIncrement() const; + bool getNotNull() const; + bool getIsPrimaryKey() const; + bool getIsIndex() const; + bool getIsUnique() const; + IxDataMemberX *getParent() const; + IxSqlRelation *getSqlRelation() const; + bool hasSqlRelation() const; + bool getAccessDataPointer() const; + virtual QString getType() const; + QString getTypeParent() const; + IxDataMember *getPImpl() const; + + void setName(const QString &s); + void setNameParent(const QString &s); + void setDescription(const QString &s); + void setFormat(const QString &s); + void setSqlType(const QString &s); + void setSqlAlias(const QString &s); + void setVersion(long l); + void setSerialize(bool b); + void setDao(bool b); + void setDefaultValue(const QVariant &v); + void setPrecision(int i); + void setRequired(bool b); + void setReadOnly(bool b); + void setAutoIncrement(bool b); + void setIsPrimaryKey(bool b); + void setIsIndex(bool b); + void setIsUnique(bool b); + void setParent(IxDataMemberX *p); + void setSqlRelation(IxSqlRelation *p); + void setAccessDataPointer(bool b); + + void setMinValue(long lMinValue, const QString &sMessage = QString()); + void setMinValue(double dMinValue, const QString &sMessage = QString()); + void setMaxValue(long lMaxValue, const QString &sMessage = QString()); + void setMaxValue(double dMaxValue, const QString &sMessage = QString()); + void setMinLength(int iMinLength, const QString &sMessage = QString()); + void setMaxLength(int iMaxLength, const QString &sMessage = QString()); + void setNotNull(bool bNotNull, const QString &sMessage = QString()); + + bool isThereRelationPartOfPrimaryKey(int iIndexNamePK, IxSqlRelation *&pRelation, int &iIndexNameFK) const; + bool isPartOfPrimaryKey(int iIndexNameFK, IxDataMember *&pPrimaryKey, int &iIndexNamePK) const; + void setRelationPartOfPrimaryKey(int iIndexNamePK, IxSqlRelation *pRelation, int iIndexNameFK); + void setPartOfPrimaryKey(int iIndexNameFK, IxDataMember *pPrimaryKey, int iIndexNamePK); + + QString getName(int iIndex, const QString &sOtherName = QString()) const; + QString getSqlAlias(const QString &sTable = QString(), bool bClauseWhere = false, int iIndexName = 0, qx::IxSqlQueryBuilder *pSqlQueryBuilder = NULL) const; + QString getSqlType(int iIndexName = -1) const; + QString getSqlTypeAndParams(int iIndexName = -1) const; + QString getSqlPlaceHolder(const QString &sAppend = QString(), int iIndexName = 0, const QString &sSep = QString(", "), const QString &sOtherName = QString(), bool bCheckFKPartOfPK = false) const; + void setSqlPlaceHolder(QSqlQuery &query, void *pOwner, const QString &sAppend = QString(), const QString &sOtherName = QString(), bool bCheckFKPartOfPK = false, qx::QxCollection *pLstExecBatch = NULL) const; + QString getSqlAliasEqualToPlaceHolder(const QString &sTable = QString(), bool bClauseWhere = false, const QString &sAppend = QString(), const QString &sSep = QString(" AND "), bool bCheckFKPartOfPK = false, qx::IxSqlQueryBuilder *pSqlQueryBuilder = NULL) const; + QString getSqlNameEqualToPlaceHolder(const QString &sAppend = QString(), const QString &sSep = QString(" AND "), bool bCheckFKPartOfPK = false, qx::IxSqlQueryBuilder *pSqlQueryBuilder = NULL) const; + QString getSqlTablePointNameAsAlias(const QString &sTable, const QString &sSep = QString(", "), const QString &sSuffixAlias = QString(), bool bCheckFKPartOfPK = false, const QString &sCustomAlias = QString(), qx::IxSqlQueryBuilder *pSqlQueryBuilder = NULL) const; + QString getSqlName(const QString &sSep = QString(", "), const QString &sOtherName = QString(), bool bCheckFKPartOfPK = false, qx::IxSqlQueryBuilder *pSqlQueryBuilder = NULL) const; + QString getSqlNameAndTypeAndParams(const QString &sSep = QString(", "), const QString &sOtherName = QString(), bool bCheckFKPartOfPK = false) const; + + void customGetSqlName(type_fct_sql_callback fct); + void customGetSqlTablePointNameAsAlias(type_fct_sql_callback fct); + void customGetSqlNameEqualToPlaceHolder(type_fct_sql_callback fct); + void customGetSqlAliasEqualToPlaceHolder(type_fct_sql_callback fct); + void customGetSqlAlias(type_fct_sql_callback fct); + + static QString getSqlFromTable(const QString &sTable, const QString &sCustomAlias = QString()); + static QString getSqlTableName(const QString &sTable); + static QString getSqlColumnName(const QString &sColumn); + static QString getSqlTableNameAlias(const QString &sTable); + static QString getSqlColumnNameAlias(const QString &sColumn); + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const = 0; + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const = 0; + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) = 0; + + QVariant toVariant(const void *pOwner, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const; + qx_bool fromVariant(void *pOwner, const QVariant &v, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context); + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const = 0; + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) = 0; + + QJsonValue toJson(const void *pOwner) const; + qx_bool fromJson(void *pOwner, const QJsonValue &j); +#endif // _QX_NO_JSON + + protected: + virtual qx::any getDataPtr(const void *pOwner) const = 0; + virtual qx::any getDataPtr(void *pOwner) = 0; + virtual void *getDataVoidPtr(const void *pOwner) const = 0; + virtual void *getDataVoidPtr(void *pOwner) = 0; + + public: + qx::any getValueAnyPtr(const void *pOwner) const { return this->getDataPtr(pOwner); } + qx::any getValueAnyPtr(void *pOwner) { return this->getDataPtr(pOwner); } + void *getValueVoidPtr(const void *pOwner) const { return this->getDataVoidPtr(pOwner); } + void *getValueVoidPtr(void *pOwner) { return this->getDataVoidPtr(pOwner); } + + template + T *getValuePtr(void *pOwner, bool *bOk = NULL) + { + if (bOk) + { + (*bOk) = false; + } + if (!getAccessDataPointer()) + { + qDebug("[QxOrm] qx::IxDataMember::getValuePtr() : '%s'", "cannot access data-member pointer"); + return NULL; + } + qx::any a = this->getDataPtr(pOwner); + try + { + T *t = qx::any_cast(a); + if (bOk) + { + (*bOk) = (t != NULL); + }; + return t; + } + catch (const qx::bad_any_cast &err) + { + Q_UNUSED(err); + qDebug("[QxOrm] qx::IxDataMember::getValuePtr() : '%s'", "bad any cast exception"); + return NULL; + } + catch (...) + { + qDebug("[QxOrm] qx::IxDataMember::getValuePtr() : '%s'", "unknown cast exception"); + return NULL; + } + } + + template + T getValue(void *pOwner, bool *bOk = NULL) + { + if (!getAccessDataPointer()) + { + return qxCannotAccessDataPointer::getValue(this, pOwner, bOk); + } + T *t = this->getValuePtr(pOwner, bOk); + return (t ? (*t) : T()); + } + + template + bool setValue(void *pOwner, const T &val) + { + if (!getAccessDataPointer()) + { + return qxCannotAccessDataPointer::setValue(this, pOwner, val); + } + T *t = this->getValuePtr(pOwner); + if (t) + { + (*t) = val; + } + return (t != NULL); + } + + private: + template + struct qxCannotAccessDataPointer + { + static T getValue(IxDataMember *pData, void *pOwner, bool *bOk) + { + Q_UNUSED(pData); + Q_UNUSED(pOwner); + qDebug("[QxOrm] qx::IxDataMember::qxCannotAccessDataPointer::getValue() : '%s'", "type T not supported"); + if (bOk) + { + (*bOk) = false; + }; + return T(); + } + static bool setValue(IxDataMember *pData, void *pOwner, const T &val) + { + Q_UNUSED(pData); + Q_UNUSED(pOwner); + Q_UNUSED(val); + qDebug("[QxOrm] qx::IxDataMember::qxCannotAccessDataPointer::setValue() : '%s'", "type T not supported"); + return false; + } + }; + + template + struct qxCannotAccessDataPointer + { + static QVariant getValue(IxDataMember *pData, void *pOwner, bool *bOk) + { + if (bOk) + { + (*bOk) = (pData != NULL); + }; + return (pData ? pData->toVariant(pOwner, "") : QVariant()); + } + static bool setValue(IxDataMember *pData, void *pOwner, const QVariant &val) + { + return (pData ? pData->fromVariant(pOwner, val, "").getValue() : false); + } + }; + + template + struct qxCannotAccessDataPointer + { + static QString getValue(IxDataMember *pData, void *pOwner, bool *bOk) + { + if (bOk) + { + (*bOk) = (pData != NULL); + }; + return (pData ? pData->toVariant(pOwner, "").toString() : QString()); + } + static bool setValue(IxDataMember *pData, void *pOwner, const QString &val) + { + QVariant tmp(val); + return (pData ? pData->fromVariant(pOwner, tmp, "").getValue() : false); + } + }; + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_IX_DATA_MEMBER_PURE_VIRTUAL_ARCHIVE(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + private: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int version); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + + typedef std::shared_ptr IxDataMember_ptr; + + /*! + * \ingroup QxDataMember + * \brief qx::IxDataMemberSqlCallbackParams : list of parameters used by custom callback functions to override SQL queries generated by QxOrm library + */ + struct IxDataMemberSqlCallbackParams + { + + const IxDataMember *pDataMember; //!< The data member instance which calls custom callback function + QString &sSQL; //!< Default value is the SQL generated by QxOrm library for this data member, can be changed by the custom callback function + QString sTable; //!< SQL table name (not always provided) + QString sSep; //!< SQL separator (not always provided) + QString sCustomAlias; //!< SQL custom alias (not always provided) + QString sSuffixAlias; //!< SQL suffix alias (not always provided) + QString sAppend; //!< String to append to SQL query (not always provided) + QString sOtherName; //!< SQL other name for this data member (not always provided) + bool bClauseWhere; //!< Define if we are building SQL in the clause WHERE or not (not always provided) + bool bCheckFKPartOfPK; //!< Check if foreign key is part of primary key (not always provided) + int iIndexName; //!< Index name for composite primary key (not always provided) + qx::dao::detail::IxDao_Helper *pDaoHelper; //!< DAO helper instance + qx::IxSqlQueryBuilder *pSqlQueryBuilder; //!< SQL query builder instance + + IxDataMemberSqlCallbackParams(const IxDataMember *p, QString &sql); + ~IxDataMemberSqlCallbackParams(); + }; + +} // namespace qx + +QX_DLL_EXPORT_INLINE_FCT bool operator<(const qx::IxDataMember &i1, const qx::IxDataMember &i2); +QX_DLL_EXPORT_INLINE_FCT bool operator>(const qx::IxDataMember &i1, const qx::IxDataMember &i2); + +#endif // _IX_DATA_MEMBER_H_ diff --git a/include/QxDataMember/IxDataMemberX.h b/include/QxDataMember/IxDataMemberX.h new file mode 100644 index 0000000..de548fd --- /dev/null +++ b/include/QxDataMember/IxDataMemberX.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 _IX_DATA_MEMBER_X_H_ +#define _IX_DATA_MEMBER_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxDataMemberX.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Common interface for a list of IxDataMember class properties registered into QxOrm context (for example, list of data member of a class) + */ + +#include + +#include + +#include + +namespace qx +{ + + class IxClass; + + /*! + * \ingroup QxDataMember + * \brief qx::IxDataMemberX : common interface for a list of IxDataMember class properties registered into QxOrm context (for example, list of data member of a class) + */ + class QX_DLL_EXPORT IxDataMemberX + { + + private: + struct IxDataMemberXImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + protected: + IxDataMemberX(); + virtual ~IxDataMemberX(); + + public: + IxClass *getClass() const; + void setClass(IxClass *p); + + QString getName() const; + const char *getNamePtr() const; + QString getDescription() const; + long getVersion() const; + qx::dao::strategy::inheritance getDaoStrategy() const; + + long count() const; + long size() const; + bool exist(const QString &sKey) const; + IxDataMember *get(long l) const; + IxDataMember *get(const QString &s) const; + IxDataMember *getId() const; + + virtual long count_WithDaoStrategy() const = 0; + virtual bool exist_WithDaoStrategy(const QString &sKey) const = 0; + virtual IxDataMember *get_WithDaoStrategy(long lIndex) const = 0; + virtual IxDataMember *get_WithDaoStrategy(const QString &sKey) const = 0; + virtual IxDataMember *getId_WithDaoStrategy() const = 0; + + protected: + void setId(IxDataMember *p); + QxCollection &getListDataMemberRef(); + const QxCollection &getListDataMemberRef() const; + QxCollection &getListPImplRef(); + const QxCollection &getListPImplRef() const; + }; + + typedef std::shared_ptr IxDataMemberX_ptr; + +} // namespace qx + +#endif // _IX_DATA_MEMBER_X_H_ diff --git a/include/QxDataMember/QxDataMember.h b/include/QxDataMember/QxDataMember.h new file mode 100644 index 0000000..636a24b --- /dev/null +++ b/include/QxDataMember/QxDataMember.h @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** 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_DATA_MEMBER_H_ +#define _QX_DATA_MEMBER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDataMember.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Concrete class property registered into QxOrm context + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include +#include + +#define QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(ArchiveInput, ArchiveOutput) \ + virtual void toArchive(const void *pOwner, ArchiveOutput &ar) const { QxDataMember::toArchive(ar, getNamePtr(), getData(pOwner)); } \ + virtual void fromArchive(void *pOwner, ArchiveInput &ar) { QxDataMember::fromArchive(ar, getNamePtr(), getData(pOwner)); } + +namespace qx +{ + + /*! + * \ingroup QxDataMember + * \brief qx::QxDataMember : concrete property of type DataType registered into QxOrm context for the class Owner + */ + template + class QxDataMember : public IxDataMember + { + + protected: + typedef DataType Owner::*type_data_member_ptr; + + type_data_member_ptr m_pData; //!< Data member under format "& Owner::DataMember" + IxDataMember *m_pImpl_; //!< If not NULL then this data member is owned by a private implementation idiom instance + + public: + QxDataMember(type_data_member_ptr pData, const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl = NULL) : IxDataMember(sKey, lVersion, bSerialize, bDao, pImpl), m_pData(pData), m_pImpl_(pImpl) { this->setAccessDataPointer(true); } + virtual ~QxDataMember() { ; } + + inline DataType *getData(void *pOwner) const + { + void *pOwner_ = (m_pImpl_ ? m_pImpl_->getDataVoidPtr(pOwner) : pOwner); + return (pOwner_ ? (&((static_cast(pOwner_))->*m_pData)) : NULL); + } + inline const DataType *getData(const void *pOwner) const + { + const void *pOwner_ = (m_pImpl_ ? m_pImpl_->getDataVoidPtr(pOwner) : pOwner); + return (pOwner_ ? (&((static_cast(pOwner_))->*m_pData)) : NULL); + } + + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const { return qx::cvt::to_variant((*getData(pOwner)), sFormat, iIndexName, ctx); } + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) { return qx::cvt::from_variant(v, (*getData(pOwner)), sFormat, iIndexName, ctx); } + virtual QString getType() const + { + QMutexLocker locker(&IxDataMember::m_mutex); + return QString(qx::trait::get_class_name::get()); + } + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const { return qx::cvt::to_json((*getData(pOwner)), sFormat); } + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) { return qx::cvt::from_json(j, (*getData(pOwner)), sFormat); } +#endif // _QX_NO_JSON + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const + { + if ((pOwner1 == NULL) || (pOwner2 == NULL)) + { + return false; + } + if (pOwner1 == pOwner2) + { + return true; + } + return qxCompareDataMember::value, 0>::isEqual((*this), pOwner1, pOwner2); + } + + protected: + virtual qx::any getDataPtr(const void *pOwner) const { return qx::any(getData(pOwner)); } + virtual qx::any getDataPtr(void *pOwner) { return qx::any(getData(pOwner)); } + virtual void *getDataVoidPtr(const void *pOwner) const { return static_cast(const_cast(getData(pOwner))); } + virtual void *getDataVoidPtr(void *pOwner) { return static_cast(getData(pOwner)); } + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_DATA_MEMBER_IMPL_VIRTUAL_ARCHIVE(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + private: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + + template + static inline void toArchive(Archive &ar, const char *sName, const DataType *pData) + { + ar << boost::serialization::make_nvp(sName, (*pData)); + } + + template + static inline void fromArchive(Archive &ar, const char *sName, DataType *pData) + { + ar >> boost::serialization::make_nvp(sName, (*pData)); + } + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + private: + template + struct qxCompareDataMember + { + static inline bool isEqual(const QxDataMember &dataMember, const void *pOwner1, const void *pOwner2) + { + return (dataMember.toVariant(pOwner1, "") == dataMember.toVariant(pOwner2, "")); + } + }; + + template + struct qxCompareDataMember + { + static inline bool isEqual(const QxDataMember &dataMember, const void *pOwner1, const void *pOwner2) + { + return ((*dataMember.getData(pOwner1)) == (*dataMember.getData(pOwner2))); + } + }; + }; + +} // namespace qx + +#include "../../inl/QxDataMember/QxDataMember.inl" + +#endif // _QX_DATA_MEMBER_H_ diff --git a/include/QxDataMember/QxDataMemberX.h b/include/QxDataMember/QxDataMemberX.h new file mode 100644 index 0000000..6774ccf --- /dev/null +++ b/include/QxDataMember/QxDataMemberX.h @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** 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_DATA_MEMBER_X_H_ +#define _QX_DATA_MEMBER_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDataMemberX.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Concrete list of class properties registered into QxOrm context + */ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxDataMember + * \brief qx::QxDataMemberX : concrete list of properties registered into QxOrm context for the class T + */ + template + class QxDataMemberX : public IxDataMemberX, public QxSingleton> + { + + friend class QxSingleton>; + + public: + typedef typename qx::trait::get_primary_key::type type_primary_key; + typedef typename qx::trait::get_base_class::type type_base_class; + + protected: + QxDataMemberX() : IxDataMemberX(), QxSingleton>(QString("qx::QxDataMemberX_") + qx::trait::get_class_name::get_xml_tag()) { ; } + virtual ~QxDataMemberX() { ; } + + public: + virtual long count_WithDaoStrategy() const { return count_WithDaoStrategy_Helper(); } + virtual bool exist_WithDaoStrategy(const QString &sKey) const { return exist_WithDaoStrategy_Helper(sKey); } + virtual IxDataMember *get_WithDaoStrategy(long lIndex) const { return get_WithDaoStrategy_Helper(lIndex); } + virtual IxDataMember *get_WithDaoStrategy(const QString &sKey) const { return get_WithDaoStrategy_Helper(sKey); } + virtual IxDataMember *getId_WithDaoStrategy() const { return getId_WithDaoStrategy_Helper(); } + + IxDataMember *id(type_primary_key T::*pDataMemberId, const QString &sKey, long lVersion = 0); + IxDataMember *id(const QString &sKey, long lVersion); + IxDataMember *add(const QString &sKey, long lVersion); + + template + IxDataMember *add(V U::*pData, const QString &sKey, long lVersion = 0, bool bSerialize = true, bool bDao = true); + template + IxSqlRelation *relationOneToOne(V U::*pData, const QString &sKey, long lVersion = 0); + template + IxSqlRelation *relationManyToOne(V U::*pData, const QString &sKey, long lVersion = 0); + template + IxSqlRelation *relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion = 0); + template + IxSqlRelation *relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion = 0); + + template + IxDataMember *pimpl(V U::*pData, const QString &sKey); + template + IxDataMember *id(type_primary_key U::*pDataMemberId, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxDataMember *add(V U::*pData, const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl); + template + IxSqlRelation *relationOneToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationManyToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion, IxDataMember *pImpl); + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + inline void toArchive(const T *pOwner, Archive &ar, const unsigned int file_version) const; + template + inline void fromArchive(T *pOwner, Archive &ar, const unsigned int file_version); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + private: + IxDataMember *initId(IxDataMember *pId, long lVersion); + IxDataMember *initData(IxDataMember *pData, long lVersion); + IxDataMember *initPImpl(IxDataMember *pImpl); + + inline IxDataMemberX *getBaseClass_Helper() const { return QxDataMemberX::getSingleton(); } + + long count_WithDaoStrategy_Helper() const + { + if (getDaoStrategy() == qx::dao::strategy::single_table_inheritance) + { + return ((getBaseClass_Helper()->getDaoStrategy() != getDaoStrategy()) ? count() : getBaseClass_Helper()->count_WithDaoStrategy()); + } + else if (getDaoStrategy() == qx::dao::strategy::class_table_inheritance) + { + return (count() + ((!getId() && getId_WithDaoStrategy()) ? 1 : 0)); + } + else if (getDaoStrategy() == qx::dao::strategy::concrete_table_inheritance) + { + return (count() + getBaseClass_Helper()->count_WithDaoStrategy()); + } + qAssert(false); + return 0; + } + + bool exist_WithDaoStrategy_Helper(const QString &sKey) const + { + if (getDaoStrategy() == qx::dao::strategy::single_table_inheritance) + { + return ((getBaseClass_Helper()->getDaoStrategy() != getDaoStrategy()) ? exist(sKey) : getBaseClass_Helper()->exist_WithDaoStrategy(sKey)); + } + else if (getDaoStrategy() == qx::dao::strategy::class_table_inheritance) + { + return (exist(sKey) || (getId_WithDaoStrategy() ? (getId_WithDaoStrategy()->getKey() == sKey) : false)); + } + else if (getDaoStrategy() == qx::dao::strategy::concrete_table_inheritance) + { + return (exist(sKey) || getBaseClass_Helper()->exist_WithDaoStrategy(sKey)); + } + qAssert(false); + return false; + } + + IxDataMember *get_WithDaoStrategy_Helper(long lIndex) const + { + if (getDaoStrategy() == qx::dao::strategy::single_table_inheritance) + { + return ((getBaseClass_Helper()->getDaoStrategy() != getDaoStrategy()) ? get(lIndex) : getBaseClass_Helper()->get_WithDaoStrategy(lIndex)); + } + else if (getDaoStrategy() == qx::dao::strategy::class_table_inheritance) + { + return ((!getId() && (lIndex == count())) ? getId_WithDaoStrategy() : get(lIndex)); + } + else if (getDaoStrategy() == qx::dao::strategy::concrete_table_inheritance) + { + return (((lIndex >= 0) && (lIndex < count())) ? get(lIndex) : getBaseClass_Helper()->get_WithDaoStrategy(lIndex - count())); + } + qAssert(false); + return NULL; + } + + IxDataMember *get_WithDaoStrategy_Helper(const QString &sKey) const + { + if (getDaoStrategy() == qx::dao::strategy::single_table_inheritance) + { + return ((getBaseClass_Helper()->getDaoStrategy() != getDaoStrategy()) ? get(sKey) : getBaseClass_Helper()->get_WithDaoStrategy(sKey)); + } + else if (getDaoStrategy() == qx::dao::strategy::class_table_inheritance) + { + return ((getId_WithDaoStrategy() && (getId_WithDaoStrategy()->getKey() == sKey)) ? getId_WithDaoStrategy() : get(sKey)); + } + else if (getDaoStrategy() == qx::dao::strategy::concrete_table_inheritance) + { + return (exist(sKey) ? get(sKey) : getBaseClass_Helper()->get_WithDaoStrategy(sKey)); + } + qAssert(false); + return NULL; + } + + IxDataMember *getId_WithDaoStrategy_Helper() const + { + if (getDaoStrategy() == qx::dao::strategy::single_table_inheritance) + { + return ((getBaseClass_Helper()->getDaoStrategy() != getDaoStrategy()) ? getId() : getBaseClass_Helper()->getId_WithDaoStrategy()); + } + else if (getDaoStrategy() == qx::dao::strategy::class_table_inheritance) + { + return (getId() ? getId() : getBaseClass_Helper()->getId_WithDaoStrategy()); + } + else if (getDaoStrategy() == qx::dao::strategy::concrete_table_inheritance) + { + return (getId() ? getId() : getBaseClass_Helper()->getId_WithDaoStrategy()); + } + qAssert(false); + return NULL; + } + }; + +} // namespace qx + +#include "../../inl/QxDataMember/QxDataMemberX.inl" + +#endif // _QX_DATA_MEMBER_X_H_ diff --git a/include/QxDataMember/QxDataMember_PImpl.h b/include/QxDataMember/QxDataMember_PImpl.h new file mode 100644 index 0000000..15f0c90 --- /dev/null +++ b/include/QxDataMember/QxDataMember_PImpl.h @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** 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_DATA_MEMBER_PIMPL_H_ +#define _QX_DATA_MEMBER_PIMPL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDataMember_PImpl.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Concrete class property registered into QxOrm context (using private implementation idiom) + */ + +#include + +#define QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(ArchiveInput, ArchiveOutput) \ + virtual void toArchive(const void *pOwner, ArchiveOutput &ar) const Q_DECL_OVERRIDE \ + { \ + Q_UNUSED(pOwner); \ + Q_UNUSED(ar); \ + } \ + virtual void fromArchive(void *pOwner, ArchiveInput &ar) Q_DECL_OVERRIDE \ + { \ + Q_UNUSED(pOwner); \ + Q_UNUSED(ar); \ + } + +namespace qx +{ + + /*! + * \ingroup QxDataMember + * \brief qx::QxDataMember_PImpl : concrete property of type DataType registered into QxOrm context for the class Owner (using private implementation idiom) + */ + template + class QxDataMember_PImpl : public IxDataMember + { + + protected: + typedef DataType Owner::*type_data_member_ptr; + + type_data_member_ptr m_pData; //!< Data member under format "& Owner::DataMember" + + public: + QxDataMember_PImpl(type_data_member_ptr pData, const QString &sKey) : IxDataMember(sKey, 0, false, false, NULL), m_pData(pData) + { + static_assert(std::is_pointer::value, "std::is_pointer::value"); + this->setAccessDataPointer(true); + } + virtual ~QxDataMember_PImpl() { ; } + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner1); + Q_UNUSED(pOwner2); + return false; + } + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return QVariant(); + } + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(v); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return qx_bool(true); + } + virtual QString getType() const Q_DECL_OVERRIDE { return QString(); } + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + return QJsonValue(); + } + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(j); + Q_UNUSED(sFormat); + return qx_bool(true); + } +#endif // _QX_NO_JSON + + protected: + inline DataType *getData(void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + inline const DataType *getData(const void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + + virtual qx::any getDataPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? qx::any(*getData(pOwner)) : qx::any()); } + virtual qx::any getDataPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? qx::any(*getData(pOwner)) : qx::any()); } + virtual void *getDataVoidPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? static_cast(const_cast(*getData(pOwner))) : NULL); } + virtual void *getDataVoidPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? static_cast(*getData(pOwner)) : NULL); } + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + + template + class QxDataMember_PImpl, Owner> : public IxDataMember + { + + protected: + typedef std::unique_ptr Owner::*type_data_member_ptr; + + type_data_member_ptr m_pData; //!< Data member under format "& Owner::DataMember" + + public: + QxDataMember_PImpl(type_data_member_ptr pData, const QString &sKey) : IxDataMember(sKey, 0, false, false, NULL), m_pData(pData) { this->setAccessDataPointer(true); } + virtual ~QxDataMember_PImpl() { ; } + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner1); + Q_UNUSED(pOwner2); + return false; + } + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return QVariant(); + } + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(v); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return qx_bool(true); + } + virtual QString getType() const Q_DECL_OVERRIDE { return QString(); } + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + return QJsonValue(); + } + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(j); + Q_UNUSED(sFormat); + return qx_bool(true); + } +#endif // _QX_NO_JSON + + protected: + inline std::unique_ptr *getData(void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + inline const std::unique_ptr *getData(const void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + + virtual qx::any getDataPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? qx::any(getData(pOwner)->get()) : qx::any()); } + virtual qx::any getDataPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? qx::any(getData(pOwner)->get()) : qx::any()); } + virtual void *getDataVoidPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? static_cast(const_cast(getData(pOwner)->get())) : NULL); } + virtual void *getDataVoidPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? static_cast(getData(pOwner)->get()) : NULL); } + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + + template + class QxDataMember_PImpl, Owner> : public IxDataMember + { + + protected: + typedef std::shared_ptr Owner::*type_data_member_ptr; + + type_data_member_ptr m_pData; //!< Data member under format "& Owner::DataMember" + + public: + QxDataMember_PImpl(type_data_member_ptr pData, const QString &sKey) : IxDataMember(sKey, 0, false, false, NULL), m_pData(pData) { this->setAccessDataPointer(true); } + virtual ~QxDataMember_PImpl() { ; } + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner1); + Q_UNUSED(pOwner2); + return false; + } + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return QVariant(); + } + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(v); + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return qx_bool(true); + } + virtual QString getType() const Q_DECL_OVERRIDE { return QString(); } + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(sFormat); + return QJsonValue(); + } + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) Q_DECL_OVERRIDE + { + Q_UNUSED(pOwner); + Q_UNUSED(j); + Q_UNUSED(sFormat); + return qx_bool(true); + } +#endif // _QX_NO_JSON + + protected: + inline std::shared_ptr *getData(void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + inline const std::shared_ptr *getData(const void *pOwner) const { return (&((static_cast(pOwner))->*m_pData)); } + + virtual qx::any getDataPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? qx::any(getData(pOwner)->get()) : qx::any()); } + virtual qx::any getDataPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? qx::any(getData(pOwner)->get()) : qx::any()); } + virtual void *getDataVoidPtr(const void *pOwner) const Q_DECL_FINAL { return (pOwner ? static_cast(const_cast(getData(pOwner)->get())) : NULL); } + virtual void *getDataVoidPtr(void *pOwner) Q_DECL_FINAL { return (pOwner ? static_cast(getData(pOwner)->get()) : NULL); } + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_DATA_MEMBER_PIMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +#endif // _QX_DATA_MEMBER_PIMPL_H_ diff --git a/include/QxDataMember/QxDataMember_QObject.h b/include/QxDataMember/QxDataMember_QObject.h new file mode 100644 index 0000000..e6137e1 --- /dev/null +++ b/include/QxDataMember/QxDataMember_QObject.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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_DATA_MEMBER_QOBJECT_H_ +#define _QX_DATA_MEMBER_QOBJECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDataMember_QObject.h + * \author XDL Team + * \ingroup QxDataMember + * \brief Connect Qt introspection engine (based on QObject class, with QMetaObject type) to QxOrm library introspection engine + */ + +#include +#include + +#include + +#include +#include + +#define QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(ArchiveInput, ArchiveOutput) \ + virtual void toArchive(const void *pOwner, ArchiveOutput &ar) const; \ + virtual void fromArchive(void *pOwner, ArchiveInput &ar); + +namespace qx +{ + + /*! + * \ingroup QxDataMember + * \brief qx::QxDataMember_QObject : connect Qt introspection engine (based on QObject class, with QMetaObject type) to QxOrm library introspection engine + */ + class QX_DLL_EXPORT QxDataMember_QObject : public IxDataMember + { + + protected: + const QMetaObject *m_metaObject; //!< Meta-object from introspection engine of Qt library (& MyQObject::staticMetaObject) + QMetaProperty m_metaProperty; //!< Meta-property from introspection engine of Qt library + + public: + QxDataMember_QObject(const QMetaObject *pMetaObject, const QString &sKey); + virtual ~QxDataMember_QObject() { ; } + + virtual bool isEqual(const void *pOwner1, const void *pOwner2) const; + virtual QVariant toVariant(const void *pOwner, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context) const; + virtual qx_bool fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName = -1, qx::cvt::context::ctx_type ctx = qx::cvt::context::e_no_context); + virtual QString getType() const; + +#ifndef _QX_NO_JSON + virtual QJsonValue toJson(const void *pOwner, const QString &sFormat) const; + virtual qx_bool fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat); +#endif // _QX_NO_JSON + + public: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + protected: + virtual qx::any getDataPtr(const void *pOwner) const; + virtual qx::any getDataPtr(void *pOwner); + virtual void *getDataVoidPtr(const void *pOwner) const; + virtual void *getDataVoidPtr(void *pOwner); + }; + +} // namespace qx + +#endif // _QX_DATA_MEMBER_QOBJECT_H_ diff --git a/include/QxExtras/QxBoostOptionalOnly.h b/include/QxExtras/QxBoostOptionalOnly.h new file mode 100644 index 0000000..b23f84b --- /dev/null +++ b/include/QxExtras/QxBoostOptionalOnly.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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_ENABLE_BOOST +#ifndef _QX_BOOST_OPTIONAL_ONLY_H_ +#define _QX_BOOST_OPTIONAL_ONLY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxBoostOptionalOnly.h + * \author XDL Team + * \ingroup QxExtras + * \brief Provides support for boost::optional to manage NULL values even if _QX_ENABLE_BOOST compilation option is not defined : so this header file enables just boost::optional feature and should be included just after header file (ideally in a precompiled header) + */ + +#include +#include + +#include + +#define _QX_ENABLE_BOOST +#include +#undef _QX_ENABLE_BOOST + +#include + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::optional) + +namespace qx +{ + namespace trait + { + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + } // namespace trait +} // namespace qx + +namespace qx +{ + namespace cvt + { + namespace detail + { + +#ifndef _QX_NO_JSON + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::optional &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + }; + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::optional &t, const QString &format) + { + if (j.isNull()) + { + t = boost::none; + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_json(j, (*t), format); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_string((*t), format, index, ctx); + }; + return QString(); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (!t) + { + t = T(); + }; + return qx::cvt::from_string(s, (*t), format, index, ctx); + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_variant((*t), format, index, ctx); + }; + return qx::trait::construct_null_qvariant::get(); + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (v.isNull()) + { + t = boost::none; + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_variant(v, (*t), format, index, ctx); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_BOOST_OPTIONAL_ONLY_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxExtras/QxStdOptional.h b/include/QxExtras/QxStdOptional.h new file mode 100644 index 0000000..a3a9a52 --- /dev/null +++ b/include/QxExtras/QxStdOptional.h @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** 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_STD_OPTIONAL_H_ +#define _QX_STD_OPTIONAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxStdOptional.h + * \author XDL Team + * \ingroup QxExtras + * \brief Support std::optional class (requires a C++17 compiler) to manage NULL database value, this header should be included just after header file (ideally in a precompiled header) + */ + +#include + +#include + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::optional &t) +{ + qint8 iHasData = (t ? 1 : 0); + stream << iHasData; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::optional &t) +{ + qint8 iHasData = 0; + stream >> iHasData; + if (iHasData) + { + t = T(); + stream >> (*t); + } + else + { + t = std::optional(); + } + return stream; +} + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::optional) + +namespace qx +{ + namespace trait + { + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + } // namespace trait +} // namespace qx + +namespace qx +{ + namespace cvt + { + namespace detail + { + +#ifndef _QX_NO_JSON + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::optional &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + }; + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::optional &t, const QString &format) + { + if (j.isNull()) + { + t = std::optional(); + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_json(j, (*t), format); + } + }; + +#endif // _QX_NO_JSON + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_string((*t), format, index, ctx); + }; + return QString(); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (!t) + { + t = T(); + }; + return qx::cvt::from_string(s, (*t), format, index, ctx); + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_variant((*t), format, index, ctx); + }; + return qx::trait::construct_null_qvariant::get(); + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (v.isNull()) + { + t = std::optional(); + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_variant(v, (*t), format, index, ctx); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_STD_OPTIONAL_H_ diff --git a/include/QxFactory/IxFactory.h b/include/QxFactory/IxFactory.h new file mode 100644 index 0000000..3cf7e49 --- /dev/null +++ b/include/QxFactory/IxFactory.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 _IX_FACTORY_H_ +#define _IX_FACTORY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxFactory.h + * \author XDL Team + * \ingroup QxFactory + * \brief Common interface for all classes that can be created dynamically using the class name + */ + +#ifndef _QX_NO_RTTI +#include +#endif // _QX_NO_RTTI + +#include + +namespace qx +{ + + /*! + * \ingroup QxFactory + * \brief qx::IxFactory : common interface for all classes that can be created dynamically using the class name + */ + class QX_DLL_EXPORT IxFactory + { + + protected: + QString m_sKeyFactory; //!< Factory key used by the collection QxFactoryX + + public: + IxFactory(const QString &sKey); + virtual ~IxFactory(); + + virtual qx::any createObject(bool bRawPointer = false) const = 0; + virtual void *createObjectNudePtr() const = 0; + +#ifndef _QX_NO_RTTI + virtual const std::type_info &typeInfo() const = 0; +#endif // _QX_NO_RTTI + + private: + IxFactory(const IxFactory &other) { Q_UNUSED(other); } + IxFactory &operator=(const IxFactory &other) + { + Q_UNUSED(other); + return (*this); + } + }; + +} // namespace qx + +#endif // _IX_FACTORY_H_ diff --git a/include/QxFactory/QxFactory.h b/include/QxFactory/QxFactory.h new file mode 100644 index 0000000..6da03b2 --- /dev/null +++ b/include/QxFactory/QxFactory.h @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** 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_FACTORY_H_ +#define _QX_FACTORY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFactory.h + * \author XDL Team + * \ingroup QxFactory + * \brief Concrete factory class to create object dynamically using the class name + */ + +#include + +#include + +#include +#include +#include + +#define QX_STR_CANNOT_INSTANTIATE_ABSTRACT_CLASS "[QxOrm] qx::QxFactory ---> cannot instantiate abstract class '%s'" + +#if _QX_AUTO_REGISTER_REPOSITORY +#define QX_AUTO_REGISTER_REPOSITORY(className, sKey) qx::register_repository(sKey); +#else // _QX_AUTO_REGISTER_REPOSITORY +#define QX_AUTO_REGISTER_REPOSITORY(className, sKey) /* Nothing */ +#endif // _QX_AUTO_REGISTER_REPOSITORY + +namespace qx +{ + + class IxPersistable; + template + class QxClass; + +#ifdef _QX_ENABLE_QT_NETWORK + namespace service + { + class IxService; + class IxParameter; + } // namespace service +#endif // _QX_ENABLE_QT_NETWORK + +#if _QX_AUTO_REGISTER_REPOSITORY + template + inline void register_repository(const QString &sKey); +#endif // _QX_AUTO_REGISTER_REPOSITORY + + /*! + * \ingroup QxFactory + * \brief qx::QxFactory : concrete factory class to create object of type T dynamically using the class name + */ + template + class QxFactory : public IxFactory + { + + public: + QxFactory(const QString &sKey) : IxFactory(sKey) { QX_AUTO_REGISTER_REPOSITORY(T, sKey); } + virtual ~QxFactory() { ; } + +#ifdef _QX_ENABLE_QT_NETWORK + virtual qx::any createObject(bool bRawPointer = false) const + { + QxClass::getSingleton(); + return qxCreateInstance::value, std::is_base_of::value, std::is_base_of::value, std::is_base_of::value, std::is_base_of::value, 0>::create(bRawPointer); + } + + virtual void *createObjectNudePtr() const + { + QxClass::getSingleton(); + return qxCreateInstance::value, std::is_base_of::value, std::is_base_of::value, std::is_base_of::value, std::is_base_of::value, 0>::createNudePtr(); + } +#else // _QX_ENABLE_QT_NETWORK + virtual qx::any createObject(bool bRawPointer = false) const + { + QxClass::getSingleton(); + return qxCreateInstance::value, std::is_base_of::value, false, false, std::is_base_of::value, 0>::create(bRawPointer); + } + + virtual void *createObjectNudePtr() const + { + QxClass::getSingleton(); + return qxCreateInstance::value, std::is_base_of::value, false, false, std::is_base_of::value, 0>::createNudePtr(); + } +#endif // _QX_ENABLE_QT_NETWORK + +#ifndef _QX_NO_RTTI + virtual const std::type_info &typeInfo() const + { + return typeid(T); + } +#endif // _QX_NO_RTTI + + private: + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + if (bRawPointer) + { + T *p = new T(); + return qx::any(p); + }; + std::shared_ptr ptr = std::make_shared(); + return qx::any(ptr); + } + static inline void *createNudePtr() { return static_cast(new T()); } + }; + + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + Q_UNUSED(bRawPointer); + qDebug(QX_STR_CANNOT_INSTANTIATE_ABSTRACT_CLASS, qx::trait::get_class_name::get()); + return qx::any(); + } + static inline void *createNudePtr() + { + qDebug(QX_STR_CANNOT_INSTANTIATE_ABSTRACT_CLASS, qx::trait::get_class_name::get()); + return NULL; + } + }; + + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + if (bRawPointer) + { + T *p = new T(); + return qx::any(p); + }; + std::shared_ptr ptr = std::make_shared(); + return qx::any(ptr); + } + static inline void *createNudePtr() { return static_cast(new T()); } + }; + +#ifdef _QX_ENABLE_QT_NETWORK + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + if (bRawPointer) + { + T *p = new T(); + return qx::any(p); + }; + std::shared_ptr ptr = std::make_shared(); + return qx::any(ptr); + } + static inline void *createNudePtr() { return static_cast(new T()); } + }; + + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + if (bRawPointer) + { + T *p = new T(); + return qx::any(p); + }; + std::shared_ptr ptr = std::make_shared(); + return qx::any(ptr); + } + static inline void *createNudePtr() { return static_cast(new T()); } + }; +#endif // _QX_ENABLE_QT_NETWORK + + template + struct qxCreateInstance + { + static inline qx::any create(bool bRawPointer) + { + if (bRawPointer) + { + T *p = new T(); + return qx::any(p); + }; + std::shared_ptr ptr = std::make_shared(); + return qx::any(ptr); + } + static inline void *createNudePtr() { return static_cast(new T()); } + }; + }; + +} // namespace qx + +#include "../../inl/QxFactory/QxFactory.inl" + +#endif // _QX_FACTORY_H_ diff --git a/include/QxFactory/QxFactoryX.h b/include/QxFactory/QxFactoryX.h new file mode 100644 index 0000000..9e2308d --- /dev/null +++ b/include/QxFactory/QxFactoryX.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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_FACTORY_X_H_ +#define _QX_FACTORY_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFactoryX.h + * \author XDL Team + * \ingroup QxFactory + * \brief List of all classes registered with QxOrm library factory pattern to create object instance dynamically using the class name + */ + +#include +#include + +#include + +#include + +namespace qx +{ + + inline qx::any create(const QString &sKey, bool bRawPointer = false); + template + inline T *create_nude_ptr(const QString &sKey); + inline void *create_void_ptr(const QString &sKey); + + class QxClassX; + + /*! + * \ingroup QxFactory + * \brief qx::QxFactoryX : list of all classes registered with QxOrm library factory pattern to create object instance dynamically using the class name + */ + class QX_DLL_EXPORT QxFactoryX : public QxSingleton + { + + friend class QxClassX; + friend class IxFactory; + friend class QxSingleton; + friend inline qx::any create(const QString &sKey, bool bRawPointer); + template + friend inline T *create_nude_ptr(const QString &sKey); + friend inline void *create_void_ptr(const QString &sKey); + + protected: + QHash m_mapFactoryX; //!< Collection of all 'IxFactory' pointer + QMutex m_oMutexFactoryX; //!< Mutex -> 'QxFactoryX' is thread-safe + + private: + QxFactoryX() : QxSingleton("qx::QxFactoryX") { ; } + virtual ~QxFactoryX() { ; } + + QHash *getAllFactory() { return (&m_mapFactoryX); } + + void registerFactory(const QString &sKey, IxFactory *pFactory); + void unregisterFactory(const QString &sKey); + + qx::any createObject(const QString &sKey, bool bRawPointer = false) const; + void *createObjectNudePtr(const QString &sKey) const; + +#ifndef _QX_NO_RTTI + const std::type_info &typeInfo(const QString &sKey) const; +#endif // _QX_NO_RTTI + + static inline qx::any createInstance(const QString &sKey, bool bRawPointer = false) { return QxFactoryX::getSingleton()->createObject(sKey, bRawPointer); } + static inline void *createInstanceNudePtr(const QString &sKey) { return QxFactoryX::getSingleton()->createObjectNudePtr(sKey); } + +#ifndef _QX_NO_RTTI + static inline const std::type_info &getTypeInfo(const QString &sKey) { return QxFactoryX::getSingleton()->typeInfo(sKey); } +#endif // _QX_NO_RTTI + }; + + /*! + * \ingroup QxFactory + * \brief Return a smart-pointer new instance of object (std::shared_ptr) associated by key sKey using qx::any type (for example : qx::create("drug") return a new instance of smart-pointer drug class into qx::any type) + */ + inline qx::any create(const QString &sKey, bool bRawPointer /* = false */) + { + return qx::QxFactoryX::createInstance(sKey, bRawPointer); + } + + /*! + * \ingroup QxFactory + * \brief Return a nude pointer (be careful with memory leak) of type T associated by key sKey, or return NULL if sKey is not registered into factory engine + */ + template + inline T *create_nude_ptr(const QString &sKey) +#ifdef _QX_NO_RTTI + { + return static_cast(qx::QxFactoryX::createInstanceNudePtr(sKey)); + } +#else // _QX_NO_RTTI + { + return dynamic_cast(static_cast(qx::QxFactoryX::createInstanceNudePtr(sKey))); + } +#endif // _QX_NO_RTTI + + /*! + * \ingroup QxFactory + * \brief Return a void * pointer (be careful with memory leak) associated by key sKey, or return NULL if sKey is not registered into factory engine + */ + inline void *create_void_ptr(const QString &sKey) + { + return qx::QxFactoryX::createInstanceNudePtr(sKey); + } + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxFactoryX) + +#endif // _QX_FACTORY_X_H_ diff --git a/include/QxFunction/IxFunction.h b/include/QxFunction/IxFunction.h new file mode 100644 index 0000000..ff5d75f --- /dev/null +++ b/include/QxFunction/IxFunction.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** 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 _IX_FUNCTION_H_ +#define _IX_FUNCTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxFunction.h + * \author XDL Team + * \ingroup QxFunction + * \brief Common interface for all functions registered into QxOrm context (used by introspection engine) + */ + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::IxFunction : common interface for all functions registered into QxOrm context (used by introspection engine) + */ + class IxFunction : public qx::QxPropertyBag + { + + protected: + QString m_sKey; //!< Function key + QString m_sSeparator; //!< Separator character(s) for 'QString' parameters type + QString m_sDescription; //!< Function description + + public: + typedef std::vector type_any_params; + + IxFunction() : qx::QxPropertyBag(), m_sSeparator("|") { ; } + virtual ~IxFunction() { ; } + + QString getKey() const { return m_sKey; } + QString getSeparator() const { return m_sSeparator; } + QString getDescription() const { return m_sDescription; } + + void setKey(const QString &s) { m_sKey = s; } + void setSeparator(const QString &s) { m_sSeparator = s; } + void setDescription(const QString &s) { m_sDescription = s; } + + virtual int getParamCount() const = 0; + + virtual qx_bool invoke(const QString ¶ms = QString(), qx::any *ret = NULL) const = 0; + virtual qx_bool invoke(const type_any_params ¶ms, qx::any *ret = NULL) const = 0; + virtual qx_bool invoke(void *pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) const = 0; + virtual qx_bool invoke(void *pOwner, const type_any_params ¶ms, qx::any *ret = NULL) const = 0; + + virtual qx_bool isValidFct() const = 0; + virtual qx_bool isValidParams(const QString ¶ms) const = 0; + virtual qx_bool isValidParams(const type_any_params ¶ms) const = 0; + + template + qx_bool isValidOwner(void *pOwner, T *dummy) const + { + Q_UNUSED(dummy); + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + if (!pOwner) + { + return qx_bool(false, 0, QX_FUNCTION_ERR_NULL_OWNER); + } +#ifndef _QX_NO_RTTI + if (!dynamic_cast(static_cast(pOwner))) + { + return qx_bool(false, 0, QX_FUNCTION_ERR_INVALID_OWNER); + } +#endif // _QX_NO_RTTI + return true; + } + + template + qx_bool isValid(const T ¶ms) const + { + qx_bool bValid = isValidFct(); + if (!bValid) + { + return bValid; + }; + bValid = isValidParams(params); + if (!bValid) + { + return bValid; + }; + return true; + } + + template + qx_bool isValid(void *pOwner, const T ¶ms, U *dummy) const + { + Q_UNUSED(dummy); + qx_bool bValid = isValidFct(); + if (!bValid) + { + return bValid; + }; + bValid = isValidParams(params); + if (!bValid) + { + return bValid; + }; + bValid = isValidOwner(pOwner, NULL); + if (!bValid) + { + return bValid; + }; + return true; + } + }; + + typedef std::shared_ptr IxFunction_ptr; + typedef QxCollection IxFunctionX; + typedef std::shared_ptr IxFunctionX_ptr; + +} // namespace qx + +#endif // _IX_FUNCTION_H_ diff --git a/include/QxFunction/QxFunctionError.h b/include/QxFunction/QxFunctionError.h new file mode 100644 index 0000000..65e3a0f --- /dev/null +++ b/include/QxFunction/QxFunctionError.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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_FUNCTION_ERROR_H_ +#define _QX_FUNCTION_ERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunctionError.h + * \author XDL Team + * \ingroup QxFunction + * \brief Define all messages when an error occured using QxFunction module of QxOrm library + */ + +#define QX_FUNCTION_ERR_NUMBER_PARAMS "Incorrect parameters count" +#define QX_FUNCTION_ERR_INVALID_PARAM "Invalid parameter at position 'XXX'" +#define QX_FUNCTION_ERR_INVALID_FCT "Invalid function" +#define QX_FUNCTION_ERR_EMPTY_FCT "Empty function" +#define QX_FUNCTION_ERR_INVALID_MEMBER_FCT "Invalid member function" +#define QX_FUNCTION_ERR_EMPTY_MEMBER_FCT "Empty member function" +#define QX_FUNCTION_ERR_INVALID_OWNER "Invalid owner" +#define QX_FUNCTION_ERR_NULL_OWNER "NULL owner" +#define QX_FUNCTION_ERR_INVALID_INVOKE_CALL "Invalid 'invoke()' call" +#define QX_FUNCTION_ERR_UNKNOWN_ERROR "Unknown error calling function" + +#endif // _QX_FUNCTION_ERROR_H_ diff --git a/include/QxFunction/QxFunctionInclude.h b/include/QxFunction/QxFunctionInclude.h new file mode 100644 index 0000000..d5cd7b0 --- /dev/null +++ b/include/QxFunction/QxFunctionInclude.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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_FUNCTION_INCLUDE_H_ +#define _QX_FUNCTION_INCLUDE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _QX_FUNCTION_INCLUDE_H_ diff --git a/include/QxFunction/QxFunctionMacro.h b/include/QxFunction/QxFunctionMacro.h new file mode 100644 index 0000000..016df03 --- /dev/null +++ b/include/QxFunction/QxFunctionMacro.h @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** 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_FUNCTION_MACRO_H_ +#define _QX_FUNCTION_MACRO_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#define QX_FUNCTION_CLASS_FCT(className) \ +public: \ + type_fct m_fct; \ + className(type_fct fct) : IxFunction(), m_fct(fct) { ; }; \ + virtual ~className() { ; }; \ + virtual qx_bool invoke(const QString ¶ms = QString(), qx::any *ret = NULL) const \ + { \ + return QxInvokerFct::value>::invoke(params, ret, this); \ + } \ + virtual qx_bool invoke(const type_any_params ¶ms, qx::any *ret = NULL) const \ + { \ + return QxInvokerFct::value>::invoke(params, ret, this); \ + } \ + virtual qx_bool invoke(void *pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) const \ + { \ + Q_UNUSED(pOwner); \ + Q_UNUSED(params); \ + Q_UNUSED(ret); \ + qAssert(false); \ + return qx_bool(false, 0, QX_FUNCTION_ERR_INVALID_INVOKE_CALL); \ + } \ + virtual qx_bool invoke(void *pOwner, const type_any_params ¶ms, qx::any *ret = NULL) const \ + { \ + Q_UNUSED(pOwner); \ + Q_UNUSED(params); \ + Q_UNUSED(ret); \ + qAssert(false); \ + return qx_bool(false, 0, QX_FUNCTION_ERR_INVALID_INVOKE_CALL); \ + } \ + virtual qx_bool isValidFct() const \ + { \ + return ((!m_fct) ? qx_bool(false, 0, QX_FUNCTION_ERR_EMPTY_FCT) : qx_bool(true)); \ + } + +#define QX_FUNCTION_CLASS_MEMBER_FCT(className) \ +public: \ + type_fct m_fct; \ + className(type_fct fct) : IxFunction(), m_fct(fct) { ; }; \ + virtual ~className() { ; }; \ + virtual qx_bool invoke(void *pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) const \ + { \ + return QxInvokerFct::value>::invoke(pOwner, params, ret, this); \ + } \ + virtual qx_bool invoke(void *pOwner, const type_any_params ¶ms, qx::any *ret = NULL) const \ + { \ + return QxInvokerFct::value>::invoke(pOwner, params, ret, this); \ + } \ + virtual qx_bool invoke(const QString ¶ms = QString(), qx::any *ret = NULL) const \ + { \ + Q_UNUSED(params); \ + Q_UNUSED(ret); \ + qAssert(false); \ + return qx_bool(false, 0, QX_FUNCTION_ERR_INVALID_INVOKE_CALL); \ + } \ + virtual qx_bool invoke(const type_any_params ¶ms, qx::any *ret = NULL) const \ + { \ + Q_UNUSED(params); \ + Q_UNUSED(ret); \ + qAssert(false); \ + return qx_bool(false, 0, QX_FUNCTION_ERR_INVALID_INVOKE_CALL); \ + } \ + virtual qx_bool isValidFct() const \ + { \ + return ((!m_fct) ? qx_bool(false, 0, QX_FUNCTION_ERR_EMPTY_MEMBER_FCT) : qx_bool(true)); \ + } + +#define QX_FUNCTION_CATCH_AND_RETURN_INVOKE() \ + catch (const std::exception &e) { bValid = qx_bool(false, 0, e.what()); } \ + catch (...) { bValid = qx_bool(false, 0, QX_FUNCTION_ERR_UNKNOWN_ERROR); } \ + if (!bValid) \ + { \ + QString sMsgDebug = bValid.getDesc(); \ + qDebug("[QxOrm] %s", qPrintable(sMsgDebug)); \ + qAssert(false); \ + } \ + return bValid; + +#define QX_FUNCTION_INVOKE_START_WITH_OWNER() \ + if (ret) \ + { \ + (*ret) = qx::any(); \ + } \ + qx_bool bValid = pThis->isValid(pOwner, params, NULL); \ + if (!bValid) \ + { \ + QString sMsgDebug = bValid.getDesc(); \ + qDebug("[QxOrm] %s", qPrintable(sMsgDebug)); \ + qAssert(false); \ + return bValid; \ + } + +#define QX_FUNCTION_INVOKE_START_WITHOUT_OWNER() \ + if (ret) \ + { \ + (*ret) = qx::any(); \ + } \ + qx_bool bValid = pThis->isValid(params); \ + if (!bValid) \ + { \ + QString sMsgDebug = bValid.getDesc(); \ + qDebug("[QxOrm] %s", qPrintable(sMsgDebug)); \ + qAssert(false); \ + return bValid; \ + } + +#define QX_FUNCTION_FETCH_PARAM(TYPE, VALUE, FCT) \ + typename std::remove_const::type VALUE; \ + { \ + qx_bool bTmp = qx::function::detail::FCT(params, VALUE, pThis); \ + if (!bTmp) \ + { \ + QString sMsgDebug = bTmp.getDesc(); \ + qDebug("[QxOrm] %s", qPrintable(sMsgDebug)); \ + qAssert(false); \ + return bTmp; \ + } \ + } + +#define QX_FUNCTION_GET_PARAM_TYPE_ANY(PARAMCOUNT) \ + Q_UNUSED(qx_fct); \ + if (params.size() < PARAMCOUNT) \ + { \ + return qx_bool(false, 0, QX_FUNCTION_ERR_NUMBER_PARAMS); \ + } \ + qx_bool bValid = true; \ + try \ + { \ + p = qx::any_cast

(params[PARAMCOUNT - 1]); \ + } \ + catch (...) \ + { \ + bValid = qx_bool(false, 0, QString(QX_FUNCTION_ERR_INVALID_PARAM).replace("XXX", QString::number(PARAMCOUNT))); \ + } \ + return bValid; + +#define QX_FUNCTION_GET_PARAM_TYPE_STRING(PARAMCOUNT) \ + if (!qx_fct) \ + { \ + return qx_bool(false, 0, QX_FUNCTION_ERR_UNKNOWN_ERROR); \ + } \ + QStringList lst = params.split(qx_fct->getSeparator()); \ + if (lst.size() < PARAMCOUNT) \ + { \ + return qx_bool(false, 0, QX_FUNCTION_ERR_NUMBER_PARAMS); \ + } \ + qx_bool bValid = true; \ + try \ + { \ + bValid = qx::cvt::from_string(lst.at(PARAMCOUNT - 1), p); \ + } \ + catch (...) \ + { \ + bValid = qx_bool(false, 0, QString(QX_FUNCTION_ERR_INVALID_PARAM).replace("XXX", QString::number(PARAMCOUNT))); \ + } \ + return bValid; + +#define QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(PARAMCOUNT) \ + if (!qx_fct) \ + { \ + return qx_bool(false, 0, QX_FUNCTION_ERR_UNKNOWN_ERROR); \ + } \ + QStringList lst = params.split(qx_fct->getSeparator()); \ + if (lst.size() < PARAMCOUNT) \ + { \ + return qx_bool(false, 0, QX_FUNCTION_ERR_NUMBER_PARAMS); \ + } \ + p = lst.at(PARAMCOUNT - 1); \ + return true; + +#endif // _QX_FUNCTION_MACRO_H_ diff --git a/include/QxFunction/QxFunction_0.h b/include/QxFunction/QxFunction_0.h new file mode 100644 index 0000000..5420c18 --- /dev/null +++ b/include/QxFunction/QxFunction_0.h @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** 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_FUNCTION_0_H_ +#define _QX_FUNCTION_0_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_0.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context without parameter + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_0 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and without parameter + */ + template + class QxFunction_0 : public IxFunction + { + + public: + typedef std::function type_fct; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_0); + + virtual int getParamCount() const { return 0; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_0 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + try + { + pThis->m_fct(static_cast(pOwner)); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_0 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner)); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_0 : public IxFunction + { + + public: + typedef std::function type_fct; + QX_FUNCTION_CLASS_FCT(QxFunction_0); + + virtual int getParamCount() const { return 0; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_0 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + try + { + pThis->m_fct(); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_0 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + try + { + R retTmp = pThis->m_fct(); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_0(const typename QxFunction_0::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_0(const typename QxFunction_0::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_0_H_ diff --git a/include/QxFunction/QxFunction_1.h b/include/QxFunction/QxFunction_1.h new file mode 100644 index 0000000..d048921 --- /dev/null +++ b/include/QxFunction/QxFunction_1.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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_FUNCTION_1_H_ +#define _QX_FUNCTION_1_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_1.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 1 parameter + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_1 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 1 parameter P1 + */ + template + class QxFunction_1 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_1); + + virtual int getParamCount() const { return 1; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_1 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + try + { + pThis->m_fct(static_cast(pOwner), p1); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_1 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_1 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + QX_FUNCTION_CLASS_FCT(QxFunction_1); + + virtual int getParamCount() const { return 1; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_1 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + try + { + pThis->m_fct(p1); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_1 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + try + { + R retTmp = pThis->m_fct(p1); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_1(const typename QxFunction_1::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_1(const typename QxFunction_1::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_1_H_ diff --git a/include/QxFunction/QxFunction_2.h b/include/QxFunction/QxFunction_2.h new file mode 100644 index 0000000..294e560 --- /dev/null +++ b/include/QxFunction/QxFunction_2.h @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** 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_FUNCTION_2_H_ +#define _QX_FUNCTION_2_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_2.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 2 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_2 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 2 parameters P1, P2 + */ + template + class QxFunction_2 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_2); + + virtual int getParamCount() const { return 2; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_2 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_2 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_2 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + QX_FUNCTION_CLASS_FCT(QxFunction_2); + + virtual int getParamCount() const { return 2; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_2 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + try + { + pThis->m_fct(p1, p2); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_2 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + try + { + R retTmp = pThis->m_fct(p1, p2); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_2(const typename QxFunction_2::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_2(const typename QxFunction_2::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_2_H_ diff --git a/include/QxFunction/QxFunction_3.h b/include/QxFunction/QxFunction_3.h new file mode 100644 index 0000000..354fa58 --- /dev/null +++ b/include/QxFunction/QxFunction_3.h @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** 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_FUNCTION_3_H_ +#define _QX_FUNCTION_3_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_3.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 3 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_3 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 3 parameters P1, P2, P3 + */ + template + class QxFunction_3 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_3); + + virtual int getParamCount() const { return 3; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_3 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_3 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_3 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + QX_FUNCTION_CLASS_FCT(QxFunction_3); + + virtual int getParamCount() const { return 3; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_3 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + try + { + pThis->m_fct(p1, p2, p3); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_3 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + try + { + R retTmp = pThis->m_fct(p1, p2, p3); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_3(const typename QxFunction_3::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_3(const typename QxFunction_3::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_3_H_ diff --git a/include/QxFunction/QxFunction_4.h b/include/QxFunction/QxFunction_4.h new file mode 100644 index 0000000..be4d0c1 --- /dev/null +++ b/include/QxFunction/QxFunction_4.h @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** 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_FUNCTION_4_H_ +#define _QX_FUNCTION_4_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_4.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 4 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_4 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 4 parameters P1, P2, P3, P4 + */ + template + class QxFunction_4 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_4); + + virtual int getParamCount() const { return 4; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_4 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_4 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_4 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + QX_FUNCTION_CLASS_FCT(QxFunction_4); + + virtual int getParamCount() const { return 4; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_4 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + try + { + pThis->m_fct(p1, p2, p3, p4); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_4 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_4(const typename QxFunction_4::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_4(const typename QxFunction_4::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_4_H_ diff --git a/include/QxFunction/QxFunction_5.h b/include/QxFunction/QxFunction_5.h new file mode 100644 index 0000000..59c5a55 --- /dev/null +++ b/include/QxFunction/QxFunction_5.h @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** 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_FUNCTION_5_H_ +#define _QX_FUNCTION_5_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_5.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 5 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_5 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 5 parameters P1, P2, P3, P4, P5 + */ + template + class QxFunction_5 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_5); + + virtual int getParamCount() const { return 5; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_5 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_5 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_5 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + QX_FUNCTION_CLASS_FCT(QxFunction_5); + + virtual int getParamCount() const { return 5; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_5 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + try + { + pThis->m_fct(p1, p2, p3, p4, p5); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_5 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4, p5); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_5(const typename QxFunction_5::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_5(const typename QxFunction_5::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_5_H_ diff --git a/include/QxFunction/QxFunction_6.h b/include/QxFunction/QxFunction_6.h new file mode 100644 index 0000000..d442edb --- /dev/null +++ b/include/QxFunction/QxFunction_6.h @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** 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_FUNCTION_6_H_ +#define _QX_FUNCTION_6_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_6.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 6 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_6 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 6 parameters P1, P2, P3, P4, P5, P6 + */ + template + class QxFunction_6 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_6); + + virtual int getParamCount() const { return 6; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_6 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_6 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_6 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + QX_FUNCTION_CLASS_FCT(QxFunction_6); + + virtual int getParamCount() const { return 6; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_6 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + try + { + pThis->m_fct(p1, p2, p3, p4, p5, p6); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_6 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4, p5, p6); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_6(const typename QxFunction_6::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_6(const typename QxFunction_6::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_6_H_ diff --git a/include/QxFunction/QxFunction_7.h b/include/QxFunction/QxFunction_7.h new file mode 100644 index 0000000..7760504 --- /dev/null +++ b/include/QxFunction/QxFunction_7.h @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** 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_FUNCTION_7_H_ +#define _QX_FUNCTION_7_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_7.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 7 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_7 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 7 parameters P1, P2, P3, P4, P5, P6, P7 + */ + template + class QxFunction_7 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_7); + + virtual int getParamCount() const { return 7; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_7 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_7 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_7 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + QX_FUNCTION_CLASS_FCT(QxFunction_7); + + virtual int getParamCount() const { return 7; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_7 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + try + { + pThis->m_fct(p1, p2, p3, p4, p5, p6, p7); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_7 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4, p5, p6, p7); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_7(const typename QxFunction_7::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_7(const typename QxFunction_7::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_7_H_ diff --git a/include/QxFunction/QxFunction_8.h b/include/QxFunction/QxFunction_8.h new file mode 100644 index 0000000..6f50c49 --- /dev/null +++ b/include/QxFunction/QxFunction_8.h @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** 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_FUNCTION_8_H_ +#define _QX_FUNCTION_8_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_8.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 8 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_8 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 8 parameters P1, P2, P3, P4, P5, P6, P7, P8 + */ + template + class QxFunction_8 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + typedef typename qx::trait::remove_attr::type type_P8; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_8); + + virtual int getParamCount() const { return 8; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_8 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7, p8); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_8 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7, p8); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_8 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + typedef typename qx::trait::remove_attr::type type_P8; + QX_FUNCTION_CLASS_FCT(QxFunction_8); + + virtual int getParamCount() const { return 8; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_8 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + try + { + pThis->m_fct(p1, p2, p3, p4, p5, p6, p7, p8); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_8 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4, p5, p6, p7, p8); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_8(const typename QxFunction_8::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_8(const typename QxFunction_8::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_8_H_ diff --git a/include/QxFunction/QxFunction_9.h b/include/QxFunction/QxFunction_9.h new file mode 100644 index 0000000..c04faa9 --- /dev/null +++ b/include/QxFunction/QxFunction_9.h @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** 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_FUNCTION_9_H_ +#define _QX_FUNCTION_9_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxFunction_9.h + * \author XDL Team + * \ingroup QxFunction + * \brief Concrete function class registered into QxOrm context with 9 parameters + */ + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxFunction + * \brief qx::QxFunction_9 : concrete function registered into QxOrm context defined into class Owner, returning an object of type R and with 9 parameters P1, P2, P3, P4, P5, P6, P7, P8, P9 + */ + template + class QxFunction_9 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + typedef typename qx::trait::remove_attr::type type_P8; + typedef typename qx::trait::remove_attr::type type_P9; + QX_FUNCTION_CLASS_MEMBER_FCT(QxFunction_9); + + virtual int getParamCount() const { return 9; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_9 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + QX_FUNCTION_FETCH_PARAM(type_P9, p9, get_param_9); + try + { + pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(void *pOwner, const T ¶ms, qx::any *ret, const QxFunction_9 *pThis) + { + QX_FUNCTION_INVOKE_START_WITH_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + QX_FUNCTION_FETCH_PARAM(type_P9, p9, get_param_9); + try + { + R retTmp = pThis->m_fct(static_cast(pOwner), p1, p2, p3, p4, p5, p6, p7, p8, p9); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + template + class QxFunction_9 : public IxFunction + { + + public: + typedef std::function type_fct; + typedef typename qx::trait::remove_attr::type type_P1; + typedef typename qx::trait::remove_attr::type type_P2; + typedef typename qx::trait::remove_attr::type type_P3; + typedef typename qx::trait::remove_attr::type type_P4; + typedef typename qx::trait::remove_attr::type type_P5; + typedef typename qx::trait::remove_attr::type type_P6; + typedef typename qx::trait::remove_attr::type type_P7; + typedef typename qx::trait::remove_attr::type type_P8; + typedef typename qx::trait::remove_attr::type type_P9; + QX_FUNCTION_CLASS_FCT(QxFunction_9); + + virtual int getParamCount() const { return 9; } + virtual qx_bool isValidParams(const QString ¶ms) const + { + Q_UNUSED(params); + return true; + } + virtual qx_bool isValidParams(const type_any_params ¶ms) const + { + Q_UNUSED(params); + return true; + } + + private: + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_9 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + QX_FUNCTION_FETCH_PARAM(type_P9, p9, get_param_9); + try + { + pThis->m_fct(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + + template + struct QxInvokerFct + { + static inline qx_bool invoke(const T ¶ms, qx::any *ret, const QxFunction_9 *pThis) + { + QX_FUNCTION_INVOKE_START_WITHOUT_OWNER(); + QX_FUNCTION_FETCH_PARAM(type_P1, p1, get_param_1); + QX_FUNCTION_FETCH_PARAM(type_P2, p2, get_param_2); + QX_FUNCTION_FETCH_PARAM(type_P3, p3, get_param_3); + QX_FUNCTION_FETCH_PARAM(type_P4, p4, get_param_4); + QX_FUNCTION_FETCH_PARAM(type_P5, p5, get_param_5); + QX_FUNCTION_FETCH_PARAM(type_P6, p6, get_param_6); + QX_FUNCTION_FETCH_PARAM(type_P7, p7, get_param_7); + QX_FUNCTION_FETCH_PARAM(type_P8, p8, get_param_8); + QX_FUNCTION_FETCH_PARAM(type_P9, p9, get_param_9); + try + { + R retTmp = pThis->m_fct(p1, p2, p3, p4, p5, p6, p7, p8, p9); + if (ret) + { + (*ret) = qx::any(retTmp); + } + } + QX_FUNCTION_CATCH_AND_RETURN_INVOKE(); + } + }; + }; + + namespace function + { + + template + IxFunction_ptr bind_fct_9(const typename QxFunction_9::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(qx_verify_owner_tmp::value, "qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + template + IxFunction_ptr bind_member_fct_9(const typename QxFunction_9::type_fct &fct) + { + typedef std::is_same qx_verify_owner_tmp; + static_assert(!qx_verify_owner_tmp::value, "! qx_verify_owner_tmp::value"); + IxFunction_ptr ptr = std::make_shared>(fct); + return ptr; + } + + } // namespace function +} // namespace qx + +#endif // _QX_FUNCTION_9_H_ diff --git a/include/QxFunction/QxParameters.h b/include/QxFunction/QxParameters.h new file mode 100644 index 0000000..d86a72c --- /dev/null +++ b/include/QxFunction/QxParameters.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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_PARAMETERS_H_ +#define _QX_PARAMETERS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxParameters.h + * \author XDL Team + * \ingroup QxFunction + * \brief qx::function::detail::get_param_X() : provide some helper functions to retrieve parameters for all qx::IxFunction registered into QxOrm context + */ + +#include + +namespace qx +{ + namespace function + { + namespace detail + { + + template + inline qx_bool get_param_1(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(1); } + + template + inline qx_bool get_param_2(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(2); } + + template + inline qx_bool get_param_3(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(3); } + + template + inline qx_bool get_param_4(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(4); } + + template + inline qx_bool get_param_5(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(5); } + + template + inline qx_bool get_param_6(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(6); } + + template + inline qx_bool get_param_7(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(7); } + + template + inline qx_bool get_param_8(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(8); } + + template + inline qx_bool get_param_9(const T ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_ANY(9); } + + template + inline qx_bool get_param_1(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(1); } + + template + inline qx_bool get_param_2(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(2); } + + template + inline qx_bool get_param_3(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(3); } + + template + inline qx_bool get_param_4(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(4); } + + template + inline qx_bool get_param_5(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(5); } + + template + inline qx_bool get_param_6(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(6); } + + template + inline qx_bool get_param_7(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(7); } + + template + inline qx_bool get_param_8(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(8); } + + template + inline qx_bool get_param_9(const QString ¶ms, P &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING(9); } + + template <> + inline qx_bool get_param_1(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(1); } + + template <> + inline qx_bool get_param_2(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(2); } + + template <> + inline qx_bool get_param_3(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(3); } + + template <> + inline qx_bool get_param_4(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(4); } + + template <> + inline qx_bool get_param_5(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(5); } + + template <> + inline qx_bool get_param_6(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(6); } + + template <> + inline qx_bool get_param_7(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(7); } + + template <> + inline qx_bool get_param_8(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(8); } + + template <> + inline qx_bool get_param_9(const QString ¶ms, QString &p, const qx::IxFunction *qx_fct) { QX_FUNCTION_GET_PARAM_TYPE_STRING_TO_QSTRING(9); } + + } // namespace detail + } // namespace function +} // namespace qx + +#endif // _QX_PARAMETERS_H_ diff --git a/include/QxHttpServer/QxHttpCookie.h b/include/QxHttpServer/QxHttpCookie.h new file mode 100644 index 0000000..67c712e --- /dev/null +++ b/include/QxHttpServer/QxHttpCookie.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_COOKIE_H_ +#define _QX_HTTP_COOKIE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpCookie.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP cookie (https://www.qxorm.com/qxorm_en/manual.html#manual_999) + */ + +namespace qx +{ + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpCookie : HTTP cookie (https://www.qxorm.com/qxorm_en/manual.html#manual_999) + */ + struct QX_DLL_EXPORT QxHttpCookie + { + + QByteArray name; //!< Cookie name + QByteArray value; //!< Cookie value + QByteArray domain; //!< Cookie domain : specifies those hosts to which the cookie will be sent, if not specified defaults to the host portion of the current document location (but not including subdomains) + QByteArray path; //!< Cookie path : indicates a URL path that must exist in the requested resource before sending the Cookie header + qlonglong maxAge; //!< Cookie max-age : number of seconds until the cookie expires (a zero or negative number will expire the cookie immediately) + bool secure; //!< Cookie secure : a secure cookie will only be sent to the server when a request is made using SSL and the HTTPS protocol + bool httpOnly; //!< Cookie http-only : HTTP-only cookies aren't accessible via JavaScript through the Document.cookie property, the XMLHttpRequest and Request APIs to mitigate attacks against cross-site scripting + + QxHttpCookie(); + QxHttpCookie(const QByteArray &name_, const QByteArray &value_, const QByteArray &domain_ = QByteArray(), const QByteArray &path_ = QByteArray("/"), qlonglong maxAge_ = 0, bool secure_ = false, bool httpOnly_ = false); + ~QxHttpCookie(); + + QByteArray toString() const; + static QHash parse(const QByteArray &cookies); + }; + +} // namespace qx + +#endif // _QX_HTTP_COOKIE_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpRequest.h b/include/QxHttpServer/QxHttpRequest.h new file mode 100644 index 0000000..773a08c --- /dev/null +++ b/include/QxHttpServer/QxHttpRequest.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_REQUEST_H_ +#define _QX_HTTP_REQUEST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpRequest.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP request (headers + body) + */ + +#include + +#include + +namespace qx +{ + + class QxHttpTransaction; + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpRequest : HTTP request (headers + body) + */ + class QX_DLL_EXPORT QxHttpRequest + { + + private: + struct QxHttpRequestImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxHttpRequest(QxHttpTransaction *transaction); + virtual ~QxHttpRequest(); + + QUrl &url(); + QString &command(); + QString &version(); + QByteArray &data(); + QHash &headers(); + QByteArray header(const QByteArray &key); + QHash &cookies(); + QxHttpCookie cookie(const QByteArray &name); + QHash &dispatchParams(); + QHash ¶ms(); + QString param(const QString &key); + QString &sourceAddress(); + long &sourcePort(); + QString guid() const; + }; + + typedef std::shared_ptr QxHttpRequest_ptr; + +} // namespace qx + +typedef qx::QxHttpRequest qx_http_request; + +#endif // _QX_HTTP_REQUEST_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpResponse.h b/include/QxHttpServer/QxHttpResponse.h new file mode 100644 index 0000000..4f4fa75 --- /dev/null +++ b/include/QxHttpServer/QxHttpResponse.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_RESPONSE_H_ +#define _QX_HTTP_RESPONSE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpResponse.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP response (headers + body) + */ + +#include + +#ifndef Q_MOC_RUN +#include +#endif // Q_MOC_RUN + +namespace qx +{ + + class QxHttpTransaction; + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpResponse : HTTP response (headers + body) + */ + class QX_DLL_EXPORT QxHttpResponse + { + + private: + struct QxHttpResponseImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxHttpResponse(QxHttpTransaction *transaction); + virtual ~QxHttpResponse(); + + int &status(); + QByteArray &data(); + QByteArray statusDesc(); + QHash &headers(); + QByteArray header(const QByteArray &key); + QHash &cookies(); + QxHttpCookie cookie(const QByteArray &name); + qx_bool writeChunked(const QByteArray &data); + bool isChunked() const; + }; + + typedef std::shared_ptr QxHttpResponse_ptr; + +} // namespace qx + +typedef qx::QxHttpResponse qx_http_response; + +#endif // _QX_HTTP_RESPONSE_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpServer.h b/include/QxHttpServer/QxHttpServer.h new file mode 100644 index 0000000..43447e7 --- /dev/null +++ b/include/QxHttpServer/QxHttpServer.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_SERVER_H_ +#define _QX_HTTP_SERVER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpServer.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP server which manages connections in a multi-threaded environment (support SSL/TLS, persistent connection, etc...) : https://www.qxorm.com/qxorm_en/manual.html#manual_96 + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include +#include +#include + +#ifndef Q_MOC_RUN +#include +#include +#include +#endif // Q_MOC_RUN + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +class QAbstractEventDispatcher; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +namespace qx +{ + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpServer : HTTP server which manages connections in a multi-threaded environment (support SSL/TLS, persistent connection, etc...) : https://www.qxorm.com/qxorm_en/manual.html#manual_96 + */ + class QX_DLL_EXPORT QxHttpServer : public QObject + { + + Q_OBJECT + + public: + typedef std::function type_fct_custom_request_handler; + + private: + struct QxHttpServerImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxHttpServer(QObject *parent = NULL); + virtual ~QxHttpServer(); + + Q_INVOKABLE void startServer(); + Q_INVOKABLE void stopServer(); + + void setCustomRequestHandler(type_fct_custom_request_handler fct); + QxHttpServer &dispatch(const QString &command, const QString &path, type_fct_custom_request_handler fct, long position = -1); + void beforeDispatching(type_fct_custom_request_handler fct); + void afterDispatching(type_fct_custom_request_handler fct); + void clearDispatcher(); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void setEventDispatcher(QAbstractEventDispatcher *pEventDispatcher); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + static void buildResponseStaticFile(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QString &serverPath, qlonglong chunkedSize = 0); + static void buildResponseQxRestApi(qx::QxHttpRequest &request, qx::QxHttpResponse &response); + + Q_SIGNALS: + + void error(const QString &err, qx::QxHttpTransaction_ptr transaction); + void transactionStarted(qx::QxHttpTransaction_ptr transaction); + void transactionFinished(qx::QxHttpTransaction_ptr transaction); + void serverStatusChanged(bool bIsRunning); + + private Q_SLOTS: + + void onError(const QString &err, qx::service::QxTransaction_ptr transaction); + void onServerIsRunning(bool bIsRunning, qx::service::QxServer *pServer); + void onTransactionStarted(qx::service::QxTransaction_ptr transaction); + void onTransactionFinished(qx::service::QxTransaction_ptr transaction); + void onCustomRequestHandler(qx::service::QxTransaction_ptr transaction); + }; + + typedef std::shared_ptr QxHttpServer_ptr; + +} // namespace qx + +typedef qx::QxHttpServer qx_http_server; + +#endif // _QX_HTTP_SERVER_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpSession.h b/include/QxHttpServer/QxHttpSession.h new file mode 100644 index 0000000..2859605 --- /dev/null +++ b/include/QxHttpServer/QxHttpSession.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_SESSION_H_ +#define _QX_HTTP_SESSION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpSession.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP session (https://www.qxorm.com/qxorm_en/manual.html#manual_998) + */ + +namespace qx +{ + + class QxHttpSessionManager; + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpSession : HTTP session (https://www.qxorm.com/qxorm_en/manual.html#manual_998) + */ + class QX_DLL_EXPORT QxHttpSession + { + + friend class qx::QxHttpSessionManager; + + private: + struct QxHttpSessionImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + public: // Some older compilers don't support std::shared_ptr with private custom deleter, but for Qt5 we assume that all compilers should support it +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + + QxHttpSession(); + ~QxHttpSession(); + + public: + QByteArray id(); + QDateTime lastAccess(); + void lastAccess(const QDateTime &dt); + QVariant get(const QByteArray &key); + void set(const QByteArray &key, const QVariant &value); + QHash getAll(); + void remove(const QByteArray &key); + void clear(); + }; + + typedef std::shared_ptr QxHttpSession_ptr; + +} // namespace qx + +typedef qx::QxHttpSession qx_http_session; +typedef qx::QxHttpSession_ptr qx_http_session_ptr; + +#endif // _QX_HTTP_SESSION_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpSessionManager.h b/include/QxHttpServer/QxHttpSessionManager.h new file mode 100644 index 0000000..7095dc8 --- /dev/null +++ b/include/QxHttpServer/QxHttpSessionManager.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_SESSION_MANAGER_H_ +#define _QX_HTTP_SESSION_MANAGER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpSessionManager.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP session manager (https://www.qxorm.com/qxorm_en/manual.html#manual_998) + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#ifndef Q_MOC_RUN +#include +#endif // Q_MOC_RUN + +#include +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpSessionManager : HTTP session manager (https://www.qxorm.com/qxorm_en/manual.html#manual_998) + */ + class QX_DLL_EXPORT QxHttpSessionManager : public QObject, public qx::QxSingleton + { + + Q_OBJECT + friend class qx::QxSingleton; + + private: + struct QxHttpSessionManagerImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + QxHttpSessionManager(); + virtual ~QxHttpSessionManager(); + + public: + static qx::QxHttpSession_ptr getSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName = QByteArray("qx_session_id"), bool autoCreateSession = true); + static qx::QxHttpSession_ptr createSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName = QByteArray("qx_session_id")); + static void removeSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName = QByteArray("qx_session_id")); + + private Q_SLOTS: + + void onCheckSessionTimeOut(); + + private: + static void deleteSession(qx::QxHttpSession *p); + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxHttpSessionManager) + +#endif // _QX_HTTP_SESSION_MANAGER_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxHttpServer/QxHttpTransaction.h b/include/QxHttpServer/QxHttpTransaction.h new file mode 100644 index 0000000..81a4788 --- /dev/null +++ b/include/QxHttpServer/QxHttpTransaction.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_HTTP_TRANSACTION_H_ +#define _QX_HTTP_TRANSACTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxHttpTransaction.h + * \author XDL Team + * \ingroup QxHttpServer + * \brief HTTP transaction (contains request from client and reply from server) + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxHttpServer + * \brief qx::QxHttpTransaction : HTTP transaction (contains request from client and reply from server) + */ + class QX_DLL_EXPORT QxHttpTransaction : public qx::service::QxTransaction + { + + Q_OBJECT + + private: + struct QxHttpTransactionImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxHttpTransaction(); + virtual ~QxHttpTransaction(); + + qx::QxHttpRequest &request(); + qx::QxHttpResponse &response(); + qx_bool writeChunked(const QByteArray &data); + + virtual void clear(); + virtual void executeServer(); + virtual qx_bool writeSocketServer(QTcpSocket &socket); + virtual qx_bool readSocketServer(QTcpSocket &socket); + }; + + typedef std::shared_ptr QxHttpTransaction_ptr; + +} // namespace qx + +typedef qx::QxHttpTransaction qx_http_transaction; + +#endif // _QX_HTTP_TRANSACTION_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxMemLeak.h b/include/QxMemLeak.h new file mode 100644 index 0000000..9264b46 --- /dev/null +++ b/include/QxMemLeak.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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_MEM_LEAK_H_ +#define _QX_MEM_LEAK_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxMemLeak.h + * \author Wu Yongwei + * \ingroup QxMemLeak + * \brief QxOrm library memory leak detection (by Wu Yongwei) + * + * QxMemLeak module provides a fast detection of memory leaks in Debug mode once the execution of the program is finished (with indication of the file and the line => MFC-style from Microsoft).
+ * This module is developed by Wu Yongwei and has undergone some modifications to be integrated into QxOrm library.
+ * If another tool is already used in your projects (Valgrind for example), this functionality should not be activated.
+ * To enable/disable QxMemLeak module, all is needed is to modify the constant _QX_USE_MEM_LEAK_DETECTION defined in the QxConfig.h file.
+ * A recompilation of QxOrm library is necessary to take into account this modification. + */ + +#include + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_INCLUDE_BOOST_SERIALIZE_EXPORT_HPP_INTO_QX_MEM_LEAK_HPP +#if _QX_USE_MODIFY_BOOST_SERIALIZATION_EXPORT_HPP +#include +#else +#include +#endif // _QX_USE_MODIFY_BOOST_SERIALIZATION_EXPORT_HPP +#endif // _QX_INCLUDE_BOOST_SERIALIZE_EXPORT_HPP_INTO_QX_MEM_LEAK_HPP +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#endif // _QX_MEM_LEAK_H_ diff --git a/include/QxMemLeak/bool_array.h b/include/QxMemLeak/bool_array.h new file mode 100644 index 0000000..52e1fdf --- /dev/null +++ b/include/QxMemLeak/bool_array.h @@ -0,0 +1,244 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file bool_array.h + * \ingroup QxMemLeak + * + * Header file for class bool_array (packed boolean array). + * + * \version 3.1, 2005/08/25 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _BOOL_ARRAY_H +#define _BOOL_ARRAY_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include // assert +#include // exit, free, and NULL +#include // std::bad_alloc +#include // std::out_of_range +#include // for exception constructors + +namespace qx { +namespace memory { + +#ifndef _BYTE_DEFINED +#define _BYTE_DEFINED +typedef unsigned char BYTE; +#endif // !_BYTE_DEFINED + +/** + * Class to represent a packed boolean array. + * + * This was first written in April 1995, before I knew of any existing + * implementation of this kind of classes. Of course, the C++ Standard + * Template Library now demands an implementation of packed boolean + * array as `vector<bool>', but the code here should still be useful + * for the following three reasons: (1) STL support of MSVC 6 did not + * implement this specialization (nor did it have a `bit_vector'); (2) I + * incorporated some useful member functions from the STL bitset into + * this `bool_array', including `reset', `set', `flip', and `count'; + * (3) In my tests under MSVC 6 and GCC 2.95.3/3.2.3 my code is really + * FASTER than vector<bool> or the normal boolean array. + */ +class QX_DLL_EXPORT bool_array +{ + /** Class to represent a reference to an array element. */ + class QX_DLL_EXPORT _Element + { + public: + _Element(BYTE* __ptr, unsigned long __idx); + bool operator=(bool ___value); + operator bool() const; + private: + BYTE* _M_byte_ptr; + size_t _M_byte_idx; + size_t _M_bit_idx; + }; + +public: + bool_array() : _M_byte_ptr(NULL), _M_length(0) {} + explicit bool_array(unsigned long __size); + ~bool_array() { if (_M_byte_ptr != NULL) free(_M_byte_ptr); } + + bool create(unsigned long __size); + void initialize(bool ___value); + + // Using unsigned type here can increase performance! + _Element operator[](unsigned long __idx); + bool at(unsigned long __idx) const; + void reset(unsigned long __idx); + void set(unsigned long __idx); + + unsigned long size() const { return _M_length; } + unsigned long count() const; + unsigned long count(unsigned long __beg, unsigned long __end) const; + void flip(); + +private: + BYTE* _M_byte_ptr; + unsigned long _M_length; + static BYTE _S_bit_count[256]; +}; + + +/* Inline functions */ + +/** + * Constructs a reference to an array element. + * + * @param __ptr pointer to the interal boolean data + * @param __idx index of the array element to access + */ +inline bool_array::_Element::_Element(BYTE* __ptr, unsigned long __idx) +{ + _M_byte_ptr = __ptr; + _M_byte_idx = (size_t)(__idx / 8); + _M_bit_idx = (size_t)(__idx % 8); +} + +/** + * Assigns a new boolean value to an array element. + * + * @param ___value the new boolean value + * @return the assigned boolean value + */ +inline bool bool_array::_Element::operator=(bool ___value) +{ + if (___value) + *(_M_byte_ptr + _M_byte_idx) |= 1 << _M_bit_idx; + else + *(_M_byte_ptr + _M_byte_idx) &= ~(1 << _M_bit_idx); + return ___value; +} + +/** + * Reads the boolean value from an array element. + * + * @return the boolean value of the accessed array element + */ +inline bool_array::_Element::operator bool() const +{ + return *(_M_byte_ptr + _M_byte_idx) & (1 << _M_bit_idx) ? true : false; +} + +/** + * Constructs the packed boolean array with a specific size. + * + * @param __size size of the array + * @throw std::out_of_range if \a __size equals \c 0 + * @throw std::bad_alloc if memory is insufficient + */ +inline bool_array::bool_array(unsigned long __size) + : _M_byte_ptr(NULL), _M_length(0) +{ + if (__size == 0) + throw std::out_of_range("invalid bool_array size"); + + if (!create(__size)) + throw std::bad_alloc(); +} + +/** + * Creates a reference to an array element. + * + * @param __idx index of the array element to access + */ +inline bool_array::_Element bool_array::operator[](unsigned long __idx) +{ + assert(_M_byte_ptr); + assert(__idx < _M_length); + return _Element(_M_byte_ptr, __idx); +} + +/** + * Reads the boolean value of an array element via an index. + * + * @param __idx index of the array element to access + * @return the boolean value of the accessed array element + * @throw std::out_of_range when the index is too big + */ +inline bool bool_array::at(unsigned long __idx) const +{ + size_t __byte_idx, __bit_idx; + if (__idx >= _M_length) + throw std::out_of_range("invalid bool_array subscript"); + __byte_idx = (size_t)(__idx / 8); + __bit_idx = (size_t)(__idx % 8); + return *(_M_byte_ptr + __byte_idx) & (1 << __bit_idx) ? true : false; +} + +/** + * Resets an array element to \c false via an index. + * + * @param __idx index of the array element to access + * @throw std::out_of_range when the index is too big + */ +inline void bool_array::reset(unsigned long __idx) +{ + size_t __byte_idx, __bit_idx; + if (__idx >= _M_length) + throw std::out_of_range("invalid bool_array subscript"); + __byte_idx = (size_t)(__idx / 8); + __bit_idx = (size_t)(__idx % 8); + *(_M_byte_ptr + __byte_idx) &= ~(1 << __bit_idx); +} + +/** + * Sets an array element to \c true via an index. + * + * @param __idx index of the array element to access + * @throw std::out_of_range when the index is too big + */ +inline void bool_array::set(unsigned long __idx) +{ + size_t __byte_idx, __bit_idx; + if (__idx >= _M_length) + throw std::out_of_range("invalid bool_array subscript"); + __byte_idx = (size_t)(__idx / 8); + __bit_idx = (size_t)(__idx % 8); + *(_M_byte_ptr + __byte_idx) |= 1 << __bit_idx; +} + +} // namespace memory +} // namespace qx + +#endif // _BOOL_ARRAY_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/class_level_lock.h b/include/QxMemLeak/class_level_lock.h new file mode 100644 index 0000000..5b93628 --- /dev/null +++ b/include/QxMemLeak/class_level_lock.h @@ -0,0 +1,139 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file class_level_lock.h + * \ingroup QxMemLeak + * + * In essence Loki ClassLevelLockable re-engineered to use a fast_mutex class. + * + * \version 1.13, 2007/12/30 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _CLASS_LEVEL_LOCK_H +#define _CLASS_LEVEL_LOCK_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include "fast_mutex.h" + +namespace qx { +namespace memory { + +#ifdef _NOTHREADS + /** + * Helper class for class-level locking. This is the + * single-threaded implementation. + */ + template + class class_level_lock + { + public: + /** Type that provides locking/unlocking semantics. */ + class lock + { + public: + lock() {} + }; + + typedef _Host volatile_type; + }; +#else + /** + * Helper class for class-level locking. This is the multi-threaded + * implementation. The main departure from Loki ClassLevelLockable + * is that there is an additional template parameter which can make + * the lock not lock at all even in multi-threaded environments. + * See static_mem_pool.h for real usage. + */ + template + class class_level_lock + { + static fast_mutex _S_mtx; + + public: + class lock; + friend class lock; + + /** Type that provides locking/unlocking semantics. */ + class lock + { + lock(const lock&); + lock& operator=(const lock&); + public: + lock() + { + if (_RealLock) + _S_mtx.lock(); + } + ~lock() + { + if (_RealLock) + _S_mtx.unlock(); + } + }; + + typedef volatile _Host volatile_type; + }; + +#if HAVE_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION + /** Partial specialization that makes null locking. */ + template + class class_level_lock<_Host, false> + { + public: + /** Type that provides locking/unlocking semantics. */ + class lock + { + public: + lock() {} + }; + + typedef _Host volatile_type; + }; +#endif // HAVE_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION + + template + fast_mutex class_level_lock<_Host, _RealLock>::_S_mtx; +#endif // _NOTHREADS + +} // namespace memory +} // namespace qx + +#endif // _CLASS_LEVEL_LOCK_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/cont_ptr_utils.h b/include/QxMemLeak/cont_ptr_utils.h new file mode 100644 index 0000000..790ded1 --- /dev/null +++ b/include/QxMemLeak/cont_ptr_utils.h @@ -0,0 +1,151 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file cont_ptr_utils.h + * \ingroup QxMemLeak + * + * Utility functors for containers of pointers (adapted from Scott + * Meyers' Effective STL). + * + * \version 1.4, 2007/09/12 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _CONT_PTR_UTILS_H +#define _CONT_PTR_UTILS_H + +#ifdef _MSC_VER +#pragma once +#endif + +namespace qx { +namespace memory { + +/** + * Functor to return objects pointed by a container of pointers. + * + * A typical usage might be like: + * @code + * vector v; + * ... + * transform(v.begin(), v.end(), + * ostream_iterator(cout, " "), + * dereference()); + * @endcode + */ +struct QX_DLL_EXPORT dereference +{ + template + const _Tp& operator()(const _Tp* __ptr) const + { + return *__ptr; + } +}; + +/** + * Functor to compare objects pointed by a container of pointers. + * + * @code + * vector v; + * ... + * sort(v.begin(), v.end(), dereference_less()); + * @endcode + * or + * @code + * set s; + * @endcode + */ +struct QX_DLL_EXPORT dereference_less +{ + template + bool operator()(_Pointer __ptr1, _Pointer __ptr2) const + { + return *__ptr1 < *__ptr2; + } +}; + +/** + * Functor to delete objects pointed by a container of pointers. + * + * A typical usage might be like: + * @code + * list l; + * ... + * for_each(l.begin(), l.end(), delete_object()); + * @endcode + */ +struct QX_DLL_EXPORT delete_object +{ + template + void operator()(_Pointer __ptr) const + { + delete __ptr; + } +}; + +/** + * Functor to output objects pointed by a container of pointers. + * + * A typical usage might be like: + * @code + * list l; + * ... + * for_each(l.begin(), l.end(), output_object(cout, " ")); + * @endcode + */ +template +struct output_object +{ + output_object(_OutputStrm& __outs, const _StringType& __sep) + : _M_outs(__outs), _M_sep(__sep) + {} + + template + void operator()(const _Tp* __ptr) const + { + _M_outs << *__ptr << _M_sep; + } + +private: + _OutputStrm& _M_outs; + _StringType _M_sep; +}; + +} // namespace memory +} // namespace qx + +#endif // _CONT_PTR_UTILS_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/debug_new.h b/include/QxMemLeak/debug_new.h new file mode 100644 index 0000000..948db86 --- /dev/null +++ b/include/QxMemLeak/debug_new.h @@ -0,0 +1,220 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file debug_new.h + * \ingroup QxMemLeak + * + * Header file for checking leaks caused by unmatched new/delete. + * + * \version 4.4, 2007/12/31 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _DEBUG_NEW_H +#define _DEBUG_NEW_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +#include + +/** + * @def HAVE_PLACEMENT_DELETE + * + * Macro to indicate whether placement delete operators are supported on + * a certain compiler. Some compilers, like Borland C++ Compiler 5.5.1 + * and Digital Mars Compiler 8.42, do not support them, and the user + * must define this macro to \c 0 to make the program compile. Also + * note that in that case memory leakage will occur if an exception is + * thrown in the initialization (constructor) of a dynamically created + * object. + */ +#ifndef HAVE_PLACEMENT_DELETE +#define HAVE_PLACEMENT_DELETE 1 +#endif + +/** + * @def _DEBUG_NEW_REDEFINE_NEW + * + * Macro to indicate whether redefinition of \c new is wanted. If one + * wants to define one's own operator new, to call + * operator new directly, or to call placement \c new, it + * should be defined to \c 0 to alter the default behaviour. Unless, of + * course, one is willing to take the trouble to write something like: + * @code + * # ifdef new + * # define _NEW_REDEFINED + * # undef new + * # endif + * + * // Code that uses new is here + * + * # ifdef _NEW_REDEFINED + * # ifdef DEBUG_NEW + * # define new DEBUG_NEW + * # endif + * # undef _NEW_REDEFINED + * # endif + * @endcode + */ +#ifndef _DEBUG_NEW_REDEFINE_NEW +#define _DEBUG_NEW_REDEFINE_NEW 1 +#endif + +/** + * @def _DEBUG_NEW_CALLER_ADDRESS + * + * The expression to return the caller address. print_position will + * later on use this address to print the position information of memory + * operation points. + */ +#ifndef _DEBUG_NEW_CALLER_ADDRESS +#ifdef __GNUC__ +#define _DEBUG_NEW_CALLER_ADDRESS __builtin_return_address(0) +#else +#define _DEBUG_NEW_CALLER_ADDRESS NULL +#endif +#endif + +/** + * @def DEBUG_NEW + * + * Macro to catch file/line information on allocation. If + * #_DEBUG_NEW_REDEFINE_NEW is \c 0, one can use this macro directly; + * otherwise \c new will be defined to it, and one must use \c new + * instead. + */ +#define DEBUG_NEW qx::memory::__debug_new_recorder(__FILE__, __LINE__, __FUNCTION__) ->* new + +#if _DEBUG_NEW_REDEFINE_NEW +#define new DEBUG_NEW +#endif // _DEBUG_NEW_REDEFINE_NEW + +#ifdef _DEBUG_NEW_EMULATE_MALLOC +#include +#ifdef new +#define malloc(s) ((void*)(new char[s])) +#else // new +#define malloc(s) ((void*)(DEBUG_NEW char[s])) +#endif // new +#define free(p) delete[] (char*)(p) +#endif // _DEBUG_NEW_EMULATE_MALLOC + +QX_DLL_EXPORT void * operator new(size_t size, const char * file, int line); +QX_DLL_EXPORT void * operator new[](size_t size, const char * file, int line); + +#if HAVE_PLACEMENT_DELETE +QX_DLL_EXPORT void operator delete(void * pointer, const char * file, int line) throw(); +QX_DLL_EXPORT void operator delete[](void * pointer, const char * file, int line) throw(); +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 +// MSVC 6 requires the following declarations; or the non-placement +// new[]/delete[] will not compile. +QX_DLL_EXPORT void * operator new[](size_t) throw(std::bad_alloc); +QX_DLL_EXPORT void operator delete[](void *) throw(); +#endif + +namespace qx { +namespace memory { + +/* Prototypes */ +QX_DLL_EXPORT int check_leaks(); +QX_DLL_EXPORT int check_mem_corruption(); + +/* Control variables */ +extern bool new_autocheck_flag; // default to true: call check_leaks() on exit +extern bool new_verbose_flag; // default to false: no verbose information +extern FILE* new_output_fp; // default to stderr: output to console +extern const char* new_progname;// default to NULL; should be assigned argv[0] + +/** + * Recorder class to remember the call context. + * + * The idea comes from Greg Herlihy's post in comp.lang.c++.moderated. + */ +class QX_DLL_EXPORT __debug_new_recorder +{ + const char* _M_file; + const int _M_line; + const char* _M_fct; + void _M_process(void* pointer); +public: + /** + * Constructor to remember the call context. The information will + * be used in __debug_new_recorder::operator->*. + */ + __debug_new_recorder(const char* file, int line, const char* fct) + : _M_file(file), _M_line(line), _M_fct(fct) {} + /** + * Operator to write the context information to memory. + * operator->* is chosen because it has the right + * precedence, it is rarely used, and it looks good: so people can + * tell the special usage more quickly. + */ + template _Tp* operator->*(_Tp* pointer) { _M_process(pointer); return pointer; }; + static void free_pointer(void* pointer, void* addr, bool is_array); +private: + __debug_new_recorder(const __debug_new_recorder&); + __debug_new_recorder& operator=(const __debug_new_recorder&); +}; + +/** + * Counter class for on-exit leakage check. + * + * This technique is learnt from The C++ Programming Language by + * Bjarne Stroustup. + */ +class QX_DLL_EXPORT __debug_new_counter +{ + static int _S_count; +public: + __debug_new_counter(); + ~__debug_new_counter(); +}; + +/** Counting object for each file including debug_new.h. */ +static __debug_new_counter __debug_new_count; + +} // namespace memory +} // namespace qx + +#endif // _DEBUG_NEW_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/fast_mutex.h b/include/QxMemLeak/fast_mutex.h new file mode 100644 index 0000000..57c8969 --- /dev/null +++ b/include/QxMemLeak/fast_mutex.h @@ -0,0 +1,367 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file fast_mutex.h + * \ingroup QxMemLeak + * + * A fast mutex implementation for POSIX and Win32. + * + * \version 1.18, 2005/05/06 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _FAST_MUTEX_H +#define _FAST_MUTEX_H + +#ifdef _MSC_VER +#pragma once +#endif + +# if !defined(_NOTHREADS) +# if !defined(_WIN32THREADS) && \ + (defined(_WIN32) && defined(_MT)) +// Automatically use _WIN32THREADS when specifying -MT/-MD in MSVC, +// or -mthreads in MinGW GCC. +# define _WIN32THREADS +# elif !defined(_PTHREADS) && \ + defined(_REENTRANT) +// Automatically use _PTHREADS when specifying -pthread in GCC. +// N.B. I do not detect on _PTHREAD_H since libstdc++-v3 under +// Linux will silently include anyway. +# define _PTHREADS +# endif +# endif + +# if !defined(_PTHREADS) && !defined(_WIN32THREADS) && !defined(_NOTHREADS) +# define _NOTHREADS +# endif + +# if defined(_NOTHREADS) +# if defined(_PTHREADS) || defined(_WIN32THREADS) +# undef _NOTHREADS +# error "Cannot define multi-threaded mode with -D_NOTHREADS" +# if defined(__MINGW32__) && defined(_WIN32THREADS) && !defined(_MT) +# error "Be sure to specify -mthreads with -D_WIN32THREADS" +# endif +# endif +# endif + +# ifndef _FAST_MUTEX_CHECK_INITIALIZATION +/** + * Macro to control whether to check for initialization status for each + * lock/unlock operation. Defining it to a non-zero value will enable + * the check, so that the construction/destruction of a static object + * using a static fast_mutex not yet constructed or already destroyed + * will work (with lock/unlock operations ignored). Defining it to zero + * will disable to check. + */ +# define _FAST_MUTEX_CHECK_INITIALIZATION 1 +# endif + +# if defined(_PTHREADS) && defined(_WIN32THREADS) +// Some C++ libraries have _PTHREADS defined even on Win32 platforms. +// Thus this hack. +# undef _PTHREADS +# endif + +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG +# include +# include +/** Macro for fast_mutex assertions. Real version (for debug mode). */ +# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \ + if (!(_Expr)) { \ + fprintf(stderr, "fast_mutex::%s\n", _Msg); \ + abort(); \ + } +#else +/** Macro for fast_mutex assertions. Fake version (for release mode). */ +# define _FAST_MUTEX_ASSERT(_Expr, _Msg) \ + ((void)0) +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + +# ifdef _PTHREADS +# include +/** + * Macro alias to `volatile' semantics. Here it is truly volatile since + * it is in a multi-threaded (POSIX threads) environment. + */ +# define __VOLATILE volatile + /** + * Class for non-reentrant fast mutexes. This is the implementation + * for POSIX threads. + */ + namespace qx { + namespace memory { + class fast_mutex + { + pthread_mutex_t _M_mtx_impl; +# if _FAST_MUTEX_CHECK_INITIALIZATION + bool _M_initialized; +# endif +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + bool _M_locked; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + public: + fast_mutex() +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + : _M_locked(false) +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + { + ::pthread_mutex_init(&_M_mtx_impl, NULL); +# if _FAST_MUTEX_CHECK_INITIALIZATION + _M_initialized = true; +# endif + } + ~fast_mutex() + { + _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); +# if _FAST_MUTEX_CHECK_INITIALIZATION + _M_initialized = false; +# endif + ::pthread_mutex_destroy(&_M_mtx_impl); + } + void lock() + { +# if _FAST_MUTEX_CHECK_INITIALIZATION + if (!_M_initialized) + return; +# endif + ::pthread_mutex_lock(&_M_mtx_impl); +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + // The following assertion should _always_ be true for a + // real `fast' pthread_mutex. However, this assertion can + // help sometimes, when people forget to use `-lpthread' and + // glibc provides an empty implementation. Having this + // assertion is also more consistent. + _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); + _M_locked = true; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + } + void unlock() + { +# if _FAST_MUTEX_CHECK_INITIALIZATION + if (!_M_initialized) + return; +# endif +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); + _M_locked = false; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + ::pthread_mutex_unlock(&_M_mtx_impl); + } + private: + fast_mutex(const fast_mutex&); + fast_mutex& operator=(const fast_mutex&); + }; + } // namespace memory + } // namespace qx +# endif // _PTHREADS + +# ifdef _WIN32THREADS +# include +/** + * Macro alias to `volatile' semantics. Here it is truly volatile since + * it is in a multi-threaded (Win32 threads) environment. + */ +# define __VOLATILE volatile + /** + * Class for non-reentrant fast mutexes. This is the implementation + * for Win32 threads. + */ + namespace qx { + namespace memory { + class fast_mutex + { + CRITICAL_SECTION _M_mtx_impl; +# if _FAST_MUTEX_CHECK_INITIALIZATION + bool _M_initialized; +# endif +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + bool _M_locked; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + public: + fast_mutex() +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + : _M_locked(false) +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + { + ::InitializeCriticalSection(&_M_mtx_impl); +# if _FAST_MUTEX_CHECK_INITIALIZATION + _M_initialized = true; +# endif + } + ~fast_mutex() + { + _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); +# if _FAST_MUTEX_CHECK_INITIALIZATION + _M_initialized = false; +# endif + ::DeleteCriticalSection(&_M_mtx_impl); + } + void lock() + { +# if _FAST_MUTEX_CHECK_INITIALIZATION + if (!_M_initialized) + return; +# endif + ::EnterCriticalSection(&_M_mtx_impl); +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); + _M_locked = true; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + } + void unlock() + { +# if _FAST_MUTEX_CHECK_INITIALIZATION + if (!_M_initialized) + return; +# endif +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); + _M_locked = false; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + ::LeaveCriticalSection(&_M_mtx_impl); + } + private: + fast_mutex(const fast_mutex&); + fast_mutex& operator=(const fast_mutex&); + }; + } // namespace memory + } // namespace qx +# endif // _WIN32THREADS + +# ifdef _NOTHREADS +/** + * Macro alias to `volatile' semantics. Here it is not truly volatile + * since it is in a single-threaded environment. + */ +# define __VOLATILE + /** + * Class for non-reentrant fast mutexes. This is the null + * implementation for single-threaded environments. + */ + namespace qx { + namespace memory { + class fast_mutex + { +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + bool _M_locked; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + public: + fast_mutex() +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + : _M_locked(false) +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + { + } + ~fast_mutex() + { + _FAST_MUTEX_ASSERT(!_M_locked, "~fast_mutex(): still locked"); + } + void lock() + { +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + _FAST_MUTEX_ASSERT(!_M_locked, "lock(): already locked"); + _M_locked = true; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + } + void unlock() + { +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + _FAST_MUTEX_ASSERT(_M_locked, "unlock(): not locked"); + _M_locked = false; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + } + private: + fast_mutex(const fast_mutex&); + fast_mutex& operator=(const fast_mutex&); + }; + } // namespace memory + } // namespace qx +# endif // _NOTHREADS + +namespace qx { +namespace memory { + +/** An acquistion-on-initialization lock class based on fast_mutex. */ +class QX_DLL_EXPORT fast_mutex_autolock +{ + fast_mutex& _M_mtx; +public: + explicit fast_mutex_autolock(fast_mutex& __mtx) : _M_mtx(__mtx) + { + _M_mtx.lock(); + } + ~fast_mutex_autolock() + { + _M_mtx.unlock(); + } +private: + fast_mutex_autolock(const fast_mutex_autolock&); + fast_mutex_autolock& operator=(const fast_mutex_autolock&); +}; + +} // namespace memory +} // namespace qx + +#endif // _FAST_MUTEX_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/fixed_mem_pool.h b/include/QxMemLeak/fixed_mem_pool.h new file mode 100644 index 0000000..e3c0791 --- /dev/null +++ b/include/QxMemLeak/fixed_mem_pool.h @@ -0,0 +1,330 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file fixed_mem_pool.h + * \ingroup QxMemLeak + * + * Definition of a fixed-size memory pool template for structs/classes. + * This is a easy-to-use class template for pre-allocated memory pools. + * The client side needs to do the following things: + * - Use one of the macros #DECLARE_FIXED_MEM_POOL, + * #DECLARE_FIXED_MEM_POOL__NOTHROW, and + * #DECLARE_FIXED_MEM_POOL__THROW_NOCHECK at the end of the class + * (say, \c class \e _Cls) definitions + * - Call fixed_mem_pool<_Cls>::initialize at the beginning of the + * program + * - Optionally, specialize fixed_mem_pool<_Cls>::bad_alloc_handler to + * change the behaviour when all memory blocks are allocated + * - Optionally, call fixed_mem_pool<_Cls>::deinitialize at exit of the + * program to check for memory leaks + * - Optionally, call fixed_mem_pool<_Cls>::get_alloc_count to check + * memory usage when the program is running + * + * \version 1.14, 2005/09/19 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _FIXED_MEM_POOL_H +#define _FIXED_MEM_POOL_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include "class_level_lock.h" +#include "mem_pool_base.h" + +/** + * Defines the alignment of memory blocks. + */ +#ifndef MEM_POOL_ALIGNMENT +#define MEM_POOL_ALIGNMENT 4 +#endif + +namespace qx { +namespace memory { + +/** + * Class template to manipulate a fixed-size memory pool. Please notice + * that only allocate and deallocate are protected by a lock. + * + * @param _Tp class to use the fixed_mem_pool + */ +template +class fixed_mem_pool +{ +public: + typedef typename class_level_lock >::lock lock; + static void* allocate(); + static void deallocate(void*); + static bool initialize(size_t __size); + static int deinitialize(); + static int get_alloc_count(); + static bool is_initialized(); +protected: + static bool bad_alloc_handler(); +private: + static size_t _S_align(size_t __size); + static void* _S_mem_pool_ptr; + static void* _S_first_avail_ptr; + static int _S_alloc_cnt; +}; + +/** Pointer to the allocated chunk of memory. */ +template +void* fixed_mem_pool<_Tp>::_S_mem_pool_ptr = NULL; + +/** Pointer to the first available memory block. */ +template +void* fixed_mem_pool<_Tp>::_S_first_avail_ptr = NULL; + +/** Count of allocations. */ +template +int fixed_mem_pool<_Tp>::_S_alloc_cnt = 0; + +/** + * Allocates a memory block from the memory pool. + * + * @return pointer to the allocated memory block + */ +template +inline void* fixed_mem_pool<_Tp>::allocate() +{ + lock __guard; + for (;;) + { + if (void* __result = _S_first_avail_ptr) + { + _S_first_avail_ptr = *(void**)_S_first_avail_ptr; + ++_S_alloc_cnt; + return __result; + } + else + if (!bad_alloc_handler()) + return NULL; + } +} + +/** + * Deallocates a memory block and returns it to the memory pool. + * + * @param __block_ptr pointer to the memory block to return + */ +template +inline void fixed_mem_pool<_Tp>::deallocate(void* __block_ptr) +{ + if (__block_ptr == NULL) + return; + lock __guard; + assert(_S_alloc_cnt != 0); + --_S_alloc_cnt; + *(void**)__block_ptr = _S_first_avail_ptr; + _S_first_avail_ptr = __block_ptr; +} + +/** + * Initializes the memory pool. + * + * @param __size number of memory blocks to put in the memory pool + * @return \c true if successful; \c false if memory insufficient + */ +template +bool fixed_mem_pool<_Tp>::initialize(size_t __size) +{ + size_t __block_size = _S_align(sizeof(_Tp)); + assert(!is_initialized()); + assert(__size > 0 && __block_size >= sizeof(void*)); + _S_mem_pool_ptr = mem_pool_base::alloc_sys(__size * __block_size); + _S_first_avail_ptr = _S_mem_pool_ptr; + if (_S_mem_pool_ptr == NULL) + return false; + char* __block_ = (char*)_S_mem_pool_ptr; + while (--__size != 0) + { + char* __next_ = __block_ + __block_size; + *(void**)__block_ = __next_; + __block_ = __next_; + } + *(void**)__block_ = NULL; + return true; +} + +/** + * Deinitializes the memory pool. + * + * @return \c 0 if all memory blocks are returned and the memory pool + * successfully freed; or a non-zero value indicating number of + * memory blocks still in allocation + */ +template +int fixed_mem_pool<_Tp>::deinitialize() +{ + if (_S_alloc_cnt != 0) + return _S_alloc_cnt; + assert(is_initialized()); + mem_pool_base::dealloc_sys(_S_mem_pool_ptr); + _S_mem_pool_ptr = NULL; + _S_first_avail_ptr = NULL; + return 0; +} + +/** + * Gets the allocation count. + * + * @return the number of memory blocks still in allocation + */ +template +inline int fixed_mem_pool<_Tp>::get_alloc_count() +{ + return _S_alloc_cnt; +} + +/** + * Is the memory pool initialized? + * + * @return \c true if it is successfully initialized; \c false otherwise + */ +template +inline bool fixed_mem_pool<_Tp>::is_initialized() +{ + return _S_mem_pool_ptr != NULL;; +} + +/** + * Bad allocation handler. Called when there are no memory blocks + * available in the memory pool. If this function returns \c false + * (default behaviour if not explicitly specialized), it indicates that + * it can do nothing and allocate() should return \c NULL; if this + * function returns \c true, it indicates that it has freed some memory + * blocks and allocate() should try allocating again. + */ +template +bool fixed_mem_pool<_Tp>::bad_alloc_handler() +{ + return false; +} + +/** + * Aligns the memory block size. + * + * @param __size size to be aligned + * @return aligned value of \a __size + */ +template +inline size_t fixed_mem_pool<_Tp>::_S_align(size_t __size) +{ + return (__size + MEM_POOL_ALIGNMENT - 1) + / MEM_POOL_ALIGNMENT * MEM_POOL_ALIGNMENT; +} + +} // namespace memory +} // namespace qx + +/** + * Declares the normal (exceptionable) overload of operator new + * and operator delete. + * + * @param _Cls class to use the fixed_mem_pool + * @see DECLARE_FIXED_MEM_POOL__THROW_NOCHECK, which, too, + * defines an operator new that will never return + * \c NULL, but requires more discipline on the + * programmer's side. + */ +#define DECLARE_FIXED_MEM_POOL(_Cls) \ +public: \ + static void* operator new(size_t __size) \ + { \ + assert(__size == sizeof(_Cls)); \ + if (void* __ptr = fixed_mem_pool<_Cls>::allocate()) \ + return __ptr; \ + else \ + throw std::bad_alloc(); \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr != NULL) \ + fixed_mem_pool<_Cls>::deallocate(__ptr); \ + } + +/** + * Declares the non-exceptionable overload of operator new and + * operator delete. + * + * @param _Cls class to use the fixed_mem_pool + */ +#define DECLARE_FIXED_MEM_POOL__NOTHROW(_Cls) \ +public: \ + static void* operator new(size_t __size) throw() \ + { \ + assert(__size == sizeof(_Cls)); \ + return fixed_mem_pool<_Cls>::allocate(); \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr != NULL) \ + fixed_mem_pool<_Cls>::deallocate(__ptr); \ + } + +/** + * Declares the exceptionable, non-checking overload of operator + * new and operator delete. + * + * N.B. Using this macro \e requires users to explicitly specialize + * fixed_mem_pool::bad_alloc_handler so that it shall never return + * \c false (it may throw exceptions, say, \c std::bad_alloc, or simply + * abort). Otherwise a segmentation fault might occur (instead of + * returning a \c NULL pointer). + * + * @param _Cls class to use the fixed_mem_pool + */ +#define DECLARE_FIXED_MEM_POOL__THROW_NOCHECK(_Cls) \ +public: \ + static void* operator new(size_t __size) \ + { \ + assert(__size == sizeof(_Cls)); \ + return fixed_mem_pool<_Cls>::allocate(); \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr != NULL) \ + fixed_mem_pool<_Cls>::deallocate(__ptr); \ + } + +#endif // _FIXED_MEM_POOL_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/mem_leak.h b/include/QxMemLeak/mem_leak.h new file mode 100644 index 0000000..f33132a --- /dev/null +++ b/include/QxMemLeak/mem_leak.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +/*** http://wyw.dcweb.cn/leakage.htm ***/ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#define _DEBUG_NEW_REDEFINE_NEW 0 +#include "debug_new.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4290) // C++ exception specification ignored +#endif // _MSC_VER + +#ifndef QX_MEM_LEAK_STATIC_OR_INLINE +#ifdef _MSC_VER +#define QX_MEM_LEAK_STATIC_OR_INLINE static +#else +#define QX_MEM_LEAK_STATIC_OR_INLINE inline +#endif // _MSC_VER +#endif // QX_MEM_LEAK_STATIC_OR_INLINE + +QX_MEM_LEAK_STATIC_OR_INLINE void *operator new(size_t size) throw(std::bad_alloc) { return operator new(size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); }; +QX_MEM_LEAK_STATIC_OR_INLINE void *operator new[](size_t size) throw(std::bad_alloc) { return operator new[](size, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); }; +QX_MEM_LEAK_STATIC_OR_INLINE void operator delete(void *pointer) throw() { qx::memory::__debug_new_recorder::free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, false); }; +QX_MEM_LEAK_STATIC_OR_INLINE void operator delete[](void *pointer) throw() { qx::memory::__debug_new_recorder::free_pointer(pointer, _DEBUG_NEW_CALLER_ADDRESS, true); }; + +#if HAVE_PLACEMENT_DELETE +QX_MEM_LEAK_STATIC_OR_INLINE void operator delete(void *pointer, const std::nothrow_t &) throw() { operator delete(pointer, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); }; +QX_MEM_LEAK_STATIC_OR_INLINE void operator delete[](void *pointer, const std::nothrow_t &) throw() { operator delete[](pointer, (char *)_DEBUG_NEW_CALLER_ADDRESS, 0); }; +#endif // HAVE_PLACEMENT_DELETE + +#ifdef new +#undef new +#endif // new +#define new DEBUG_NEW + +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG + +#if (!_QX_USE_MEM_LEAK_DETECTION) +#ifndef DEBUG_NEW +#define DEBUG_NEW new +#endif // DEBUG_NEW +#endif // (! _QX_USE_MEM_LEAK_DETECTION) + +#ifdef _QX_MODE_RELEASE +#ifndef DEBUG_NEW +#define DEBUG_NEW new +#endif // DEBUG_NEW +#endif // _QX_MODE_RELEASE diff --git a/include/QxMemLeak/mem_pool_base.h b/include/QxMemLeak/mem_pool_base.h new file mode 100644 index 0000000..75148ab --- /dev/null +++ b/include/QxMemLeak/mem_pool_base.h @@ -0,0 +1,77 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file mem_pool_base.h + * \ingroup QxMemLeak + * + * Header file for the memory pool base. + * + * \version 1.1, 2004/07/26 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _MEM_POOL_BASE_H +#define _MEM_POOL_BASE_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +namespace qx { +namespace memory { + +/** + * Base class for memory pools. + */ +class QX_DLL_EXPORT mem_pool_base +{ +public: + virtual ~mem_pool_base(); + virtual void recycle() = 0; + static void* alloc_sys(size_t __size); + static void dealloc_sys(void* __ptr); + + /** Structure to store the next available memory block. */ + struct _Block_list { _Block_list* _M_next; }; +}; + +} // namespace memory +} // namespace qx + +#endif // _MEM_POOL_BASE_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/object_level_lock.h b/include/QxMemLeak/object_level_lock.h new file mode 100644 index 0000000..7d9a924 --- /dev/null +++ b/include/QxMemLeak/object_level_lock.h @@ -0,0 +1,156 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file object_level_lock.h + * \ingroup QxMemLeak + * + * In essence Loki ObjectLevelLockable re-engineered to use a fast_mutex + * class. Check also Andrei Alexandrescu's article + * "Multithreading and the C++ Type System" for the ideas behind. + * + * \version 1.4, 2004/05/09 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _OBJECT_LEVEL_LOCK_H +#define _OBJECT_LEVEL_LOCK_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include "fast_mutex.h" + +namespace qx { +namespace memory { + +# ifdef _NOTHREADS + /** + * Helper class for object-level locking. This is the + * single-threaded implementation. + */ + template + class object_level_lock + { + public: + /** Type that provides locking/unlocking semantics. */ + class lock + { +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + const object_level_lock& _M_host; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + lock(const lock&); + lock& operator=(const lock&); + public: + explicit lock(const object_level_lock& __host) +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + : _M_host(__host) +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + {} +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + // The purpose of this method is allow one to write code + // like "assert(guard.get_locked_object() == this)" to + // ensure that the locked object is exactly the object being + // accessed. + const object_level_lock* get_locked_object() const + { + return &_M_host; + } +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + }; + + typedef _Host volatile_type; + }; +# else + /** + * Helper class for class-level locking. This is the multi-threaded + * implementation. + */ + template + class object_level_lock + { + mutable fast_mutex _M_mtx; + + public: + class lock; + friend class lock; + + /** Type that provides locking/unlocking semantics. */ + class lock + { + const object_level_lock& _M_host; + + lock(const lock&); + lock& operator=(const lock&); + public: + explicit lock(const object_level_lock& __host) : _M_host(__host) + { + _M_host._M_mtx.lock(); + } + ~lock() + { + _M_host._M_mtx.unlock(); + } +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + // The purpose of this method is allow one to write code + // like "assert(guard.get_locked_object() == this)" to + // ensure that the locked object is exactly the object being + // accessed. + const object_level_lock* get_locked_object() const + { + return &_M_host; + } +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + }; + + typedef volatile _Host volatile_type; + }; +# endif // _NOTHREADS + +} // namespace memory +} // namespace qx + +#endif // _OBJECT_LEVEL_LOCK_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/pctimer.h b/include/QxMemLeak/pctimer.h new file mode 100644 index 0000000..f832289 --- /dev/null +++ b/include/QxMemLeak/pctimer.h @@ -0,0 +1,112 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file pctimer.h + * \ingroup QxMemLeak + * + * Function to get a high-resolution timer for Win32/Cygwin/Unix. + * + * \version 1.6, 2004/08/02 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION +#ifndef _PCTIMER_H + +namespace qx { +namespace memory { + +typedef double pctimer_t; + +} // namespace memory +} // namespace qx + +#if defined(_WIN32) || defined(__CYGWIN__) + +#ifndef _WIN32 +#define _PCTIMER_NO_WIN32 +#endif /* _WIN32 */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif /* WIN32_LEAN_AND_MEAN */ +#include + +#ifdef _PCTIMER_NO_WIN32 +#undef _PCTIMER_NO_WIN32 +#undef _WIN32 +#endif /* _PCTIMER_NO_WIN32 */ + +namespace qx { +namespace memory { + +__inline pctimer_t pctimer(void) +{ + static LARGE_INTEGER __pcount, __pcfreq; + static int __initflag; + + if (!__initflag) + { + QueryPerformanceFrequency(&__pcfreq); + __initflag++; + } + + QueryPerformanceCounter(&__pcount); + return (double)__pcount.QuadPart / (double)__pcfreq.QuadPart; +} + +} // namespace memory +} // namespace qx + +#else /* Not Win32/Cygwin */ + +#include + +namespace qx { +namespace memory { + +__inline pctimer_t pctimer(void) +{ + struct timeval __tv; + gettimeofday(&__tv, NULL); + return (double)__tv.tv_sec + (double)__tv.tv_usec / 1000000; +} + +} // namespace memory +} // namespace qx + +#endif /* Win32/Cygwin */ + +#endif /* _PCTIMER_H */ +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/set_assign.h b/include/QxMemLeak/set_assign.h new file mode 100644 index 0000000..a7acddb --- /dev/null +++ b/include/QxMemLeak/set_assign.h @@ -0,0 +1,162 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file set_assign.h + * \ingroup QxMemLeak + * + * Definition of template functions set_assign_union and set_assign_difference. + * + * \version 1.5, 2004/07/26 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _SET_ASSIGN_H +#define _SET_ASSIGN_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +namespace qx { +namespace memory { + +template +_Container& set_assign_union(_Container& __dest, + _InputIter __first, + _InputIter __last) +{ + typename _Container::iterator __first_dest = __dest.begin(); + typename _Container::iterator __last_dest = __dest.end(); + while (__first_dest != __last_dest && __first != __last) + { + if (*__first_dest < *__first) + ++__first_dest; + else if (*__first < *__first_dest) + { + __dest.insert(__first_dest, *__first); + ++__first; + } + else // *__first_dest == *__first + { + ++__first_dest; + ++__first; + } + } + if (__first != __last) + std::copy(__first, __last, inserter(__dest, __last_dest)); + return __dest; +} + +template +_Container& set_assign_union(_Container& __dest, + _InputIter __first, + _InputIter __last, + _Compare __comp) +{ + typename _Container::iterator __first_dest = __dest.begin(); + typename _Container::iterator __last_dest = __dest.end(); + while (__first_dest != __last_dest && __first != __last) + { + if (__comp(*__first_dest, *__first)) + ++__first_dest; + else if (__comp(*__first, *__first_dest)) + { + __dest.insert(__first_dest, *__first); + ++__first; + } + else // *__first_dest is equivalent to *__first + { + ++__first_dest; + ++__first; + } + } + if (__first != __last) + std::copy(__first, __last, inserter(__dest, __last_dest)); + return __dest; +} + +template +_Container& set_assign_difference(_Container& __dest, + _InputIter __first, + _InputIter __last) +{ + typename _Container::iterator __first_dest = __dest.begin(); + typename _Container::iterator __last_dest = __dest.end(); + while (__first_dest != __last_dest && __first != __last) + { + if (*__first_dest < *__first) + ++__first_dest; + else if (*__first < *__first_dest) + ++__first; + else // *__first_dest == *__first + { + __dest.erase(__first_dest++); + ++__first; + } + } + return __dest; +} + +template +_Container& set_assign_difference(_Container& __dest, + _InputIter __first, + _InputIter __last, + _Compare __comp) +{ + typename _Container::iterator __first_dest = __dest.begin(); + typename _Container::iterator __last_dest = __dest.end(); + while (__first_dest != __last_dest && __first != __last) + { + if (__comp(*__first_dest, *__first)) + ++__first_dest; + else if (__comp(*__first, *__first_dest)) + ++__first; + else // *__first_dest is equivalent to *__first + { + __dest.erase(__first_dest++); + ++__first; + } + } + return __dest; +} + +} // namespace memory +} // namespace qx + +#endif // _SET_ASSIGN_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/static_assert.h b/include/QxMemLeak/static_assert.h new file mode 100644 index 0000000..dd7d9a2 --- /dev/null +++ b/include/QxMemLeak/static_assert.h @@ -0,0 +1,63 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file static_assert.h + * \ingroup QxMemLeak + * + * Template class to check validity duing compile time (adapted from Loki). + * + * \version 1.2, 2005/11/22 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION +#ifndef STATIC_ASSERT + +namespace qx { +namespace memory { + +template struct __nvwa_compile_time_error; +template <> struct __nvwa_compile_time_error {}; + +} // namespace memory +} // namespace qx + +#define STATIC_ASSERT(_Expr, _Msg) \ + { \ + __nvwa_compile_time_error<((_Expr) != 0)> ERROR_##_Msg; \ + (void)ERROR_##_Msg; \ + } + +#endif // STATIC_ASSERT +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxMemLeak/static_mem_pool.h b/include/QxMemLeak/static_mem_pool.h new file mode 100644 index 0000000..7f1c832 --- /dev/null +++ b/include/QxMemLeak/static_mem_pool.h @@ -0,0 +1,395 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/*! + * \file static_mem_pool.h + * \ingroup QxMemLeak + * + * Header file for the `static' memory pool. + * + * \version 1.20, 2007/10/20 + * \author Wu Yongwei + * + */ + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#ifndef _STATIC_MEM_POOL_H +#define _STATIC_MEM_POOL_H + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include "class_level_lock.h" +#include "mem_pool_base.h" + +/* Defines Work-around for Microsoft Visual C++ 6.0 and Borland C++ 5.5.1 */ +# if (defined(_MSC_VER) && _MSC_VER < 1300) \ + || (defined(__BORLANDC__) && __BORLANDC__ < 0x600) +# define __PRIVATE public +# else +# define __PRIVATE private +# endif + +/* Defines the macro for debugging output */ +# ifdef _STATIC_MEM_POOL_DEBUG +# include +# define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \ + { \ + if (_Lck) { \ + static_mem_pool_set::lock __guard; \ + std::cerr << "static_mem_pool: " << _Msg << std::endl; \ + } else { \ + std::cerr << "static_mem_pool: " << _Msg << std::endl; \ + } \ + } +# else +# define _STATIC_MEM_POOL_TRACE(_Lck, _Msg) \ + ((void)0) +# endif + +namespace qx { +namespace memory { + +/** + * Singleton class to maintain a set of existing instantiations of + * static_mem_pool. + */ +class QX_DLL_EXPORT static_mem_pool_set +{ +public: + typedef class_level_lock::lock lock; + static static_mem_pool_set& instance(); + void recycle(); + void add(mem_pool_base* __memory_pool_p); + +__PRIVATE: + ~static_mem_pool_set(); +private: + static_mem_pool_set(); + + typedef std::vector container_type; + container_type _M_memory_pool_set; + + /* Forbid their use */ + static_mem_pool_set(const static_mem_pool_set&); + const static_mem_pool_set& operator=(const static_mem_pool_set&); +}; + +/** + * Singleton class template to manage the allocation/deallocation of + * memory blocks of one specific size. + * + * @param _Sz size of elements in the static_mem_pool + * @param _Gid group id of a static_mem_pool: if it is negative, + * simultaneous accesses to this static_mem_pool will be + * protected from each other; otherwise no protection is + * given + */ +template +class static_mem_pool : public mem_pool_base +{ + typedef typename class_level_lock, (_Gid < 0)> + ::lock lock; +public: + /** + * Gets the instance of the static memory pool. It will create the + * instance if it does not already exist. Generally this function + * is now not needed. + * + * @return reference to the instance of the static memory pool + * @see instance_known + */ + static static_mem_pool& instance() + { + lock __guard; + if (!_S_instance_p) + { + _S_instance_p = _S_create_instance(); + } + return *_S_instance_p; + } + /** + * Gets the known instance of the static memory pool. The instance + * must already exist. Generally the static initializer of the + * template guarantees it. + * + * @return reference to the instance of the static memory pool + */ + static static_mem_pool& instance_known() + { + assert(_S_instance_p != NULL); + return *_S_instance_p; + } + /** + * Allocates memory and returns its pointer. The template will try + * to get it from the memory pool first, and request memory from the + * system if there is no free memory in the pool. + * + * @return pointer to allocated memory if successful; \c NULL + * otherwise + */ + void* allocate() + { + { + lock __guard; + if (_S_memory_block_p) + { + void* __result = _S_memory_block_p; + _S_memory_block_p = _S_memory_block_p->_M_next; + return __result; + } + } + return _S_alloc_sys(_S_align(_Sz)); + } + /** + * Deallocates memory by putting the memory block into the pool. + * + * @param __ptr pointer to memory to be deallocated + */ + void deallocate(void* __ptr) + { + assert(__ptr != NULL); + lock __guard; + _Block_list* __block_ = reinterpret_cast<_Block_list*>(__ptr); + __block_->_M_next = _S_memory_block_p; + _S_memory_block_p = __block_; + } + virtual void recycle(); + +private: + static_mem_pool() + { + _STATIC_MEM_POOL_TRACE(true, "static_mem_pool<" << _Sz << ',' + << _Gid << "> is created"); + } + ~static_mem_pool() + { +#ifndef _QX_MODE_RELEASE +#ifndef QT_NO_DEBUG + // Empty the pool to avoid false memory leakage alarms. This is + // generally not necessary for release binaries. + _Block_list* __block_ = _S_memory_block_p; + while (__block_) + { + _Block_list* __next_ = __block_->_M_next; + dealloc_sys(__block_); + __block_ = __next_; + } + _S_memory_block_p = NULL; +#endif // QT_NO_DEBUG +#endif // _QX_MODE_RELEASE + _S_instance_p = NULL; + _S_destroyed = true; + _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ',' + << _Gid << "> is destroyed"); + } + static size_t _S_align(size_t __size) + { + return __size >= sizeof(_Block_list) ? __size : sizeof(_Block_list); + } + static void* _S_alloc_sys(size_t __size); + static static_mem_pool* _S_create_instance(); + + static bool _S_destroyed; + static static_mem_pool* _S_instance_p; + static mem_pool_base::_Block_list* _S_memory_block_p; + + /* Forbid their use */ + static_mem_pool(const static_mem_pool&); + const static_mem_pool& operator=(const static_mem_pool&); +}; + +template bool + static_mem_pool<_Sz, _Gid>::_S_destroyed = false; +template mem_pool_base::_Block_list* + static_mem_pool<_Sz, _Gid>::_S_memory_block_p = NULL; +template static_mem_pool<_Sz, _Gid>* + static_mem_pool<_Sz, _Gid>::_S_instance_p = _S_create_instance(); + +/** + * Recycles half of the free memory blocks in the memory pool to the + * system. It is called when a memory request to the system (in other + * instances of the static memory pool) fails. + */ +template +void static_mem_pool<_Sz, _Gid>::recycle() +{ + // Only here the global lock in static_mem_pool_set is obtained + // before the pool-specific lock. However, no race conditions are + // found so far. + lock __guard; + _Block_list* __block_ = _S_memory_block_p; + while (__block_) + { + if (_Block_list* __temp_ = __block_->_M_next) + { + _Block_list* __next_ = __temp_->_M_next; + __block_->_M_next = __next_; + dealloc_sys(__temp_); + __block_ = __next_; + } + else + { + break; + } + } + _STATIC_MEM_POOL_TRACE(false, "static_mem_pool<" << _Sz << ',' + << _Gid << "> is recycled"); +} + +template +void* static_mem_pool<_Sz, _Gid>::_S_alloc_sys(size_t __size) +{ + static_mem_pool_set::lock __guard; + void* __result = mem_pool_base::alloc_sys(__size); + if (!__result) + { + static_mem_pool_set::instance().recycle(); + __result = mem_pool_base::alloc_sys(__size); + } + return __result; +} + +template +static_mem_pool<_Sz, _Gid>* static_mem_pool<_Sz, _Gid>::_S_create_instance() +{ + if (_S_destroyed) + throw std::runtime_error("dead reference detected"); + + static_mem_pool_set::instance(); // Force its creation + static_mem_pool* __inst_p = new static_mem_pool(); + try + { + static_mem_pool_set::instance().add(__inst_p); + } + catch (...) + { + _STATIC_MEM_POOL_TRACE(true, + "Exception occurs in static_mem_pool_set::add"); + // The strange cast below is to work around a bug in GCC 2.95.3 + delete static_cast(__inst_p); + throw; + } + return __inst_p; +} + +} // namespace memory +} // namespace qx + +#define DECLARE_STATIC_MEM_POOL(_Cls) \ +public: \ + static void* operator new(size_t __size) \ + { \ + assert(__size == sizeof(_Cls)); \ + void* __ptr; \ + __ptr = static_mem_pool:: \ + instance_known().allocate(); \ + if (__ptr == NULL) \ + throw std::bad_alloc(); \ + return __ptr; \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr) \ + static_mem_pool:: \ + instance_known().deallocate(__ptr); \ + } + +#define DECLARE_STATIC_MEM_POOL__NOTHROW(_Cls) \ +public: \ + static void* operator new(size_t __size) throw() \ + { \ + assert(__size == sizeof(_Cls)); \ + return static_mem_pool:: \ + instance_known().allocate(); \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr) \ + static_mem_pool:: \ + instance_known().deallocate(__ptr); \ + } + +#define DECLARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \ +public: \ + static void* operator new(size_t __size) \ + { \ + assert(__size == sizeof(_Cls)); \ + void* __ptr; \ + __ptr = static_mem_pool:: \ + instance_known().allocate(); \ + if (__ptr == NULL) \ + throw std::bad_alloc(); \ + return __ptr; \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr) \ + static_mem_pool:: \ + instance_known().deallocate(__ptr); \ + } + +#define DECLARE_STATIC_MEM_POOL_GROUPED__NOTHROW(_Cls, _Gid) \ +public: \ + static void* operator new(size_t __size) throw() \ + { \ + assert(__size == sizeof(_Cls)); \ + return static_mem_pool:: \ + instance_known().allocate(); \ + } \ + static void operator delete(void* __ptr) \ + { \ + if (__ptr) \ + static_mem_pool:: \ + instance_known().deallocate(__ptr); \ + } + +// OBSOLETE: no longer needed +#define PREPARE_STATIC_MEM_POOL(_Cls) \ + std::cerr << "PREPARE_STATIC_MEM_POOL is obsolete!\n"; + +// OBSOLETE: no longer needed +#define PREPARE_STATIC_MEM_POOL_GROUPED(_Cls, _Gid) \ + std::cerr << "PREPARE_STATIC_MEM_POOL_GROUPED is obsolete!\n"; + +#undef __PRIVATE + +#endif // _STATIC_MEM_POOL_H +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/include/QxModelView.h b/include/QxModelView.h new file mode 100644 index 0000000..ce0d1ea --- /dev/null +++ b/include/QxModelView.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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_MODEL_VIEW_H_ +#define _QX_MODEL_VIEW_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxModelView.h + * \author XDL Team + * \ingroup QxModelView + * \brief Include all headers required to use QxModelView module : https://www.qxorm.com/qxorm_en/manual.html#manual_90 + */ + +#include + +#include +#include +#include +#include +#include + +#endif // _QX_MODEL_VIEW_H_ diff --git a/include/QxModelView/IxModel.h b/include/QxModelView/IxModel.h new file mode 100644 index 0000000..6ff451e --- /dev/null +++ b/include/QxModelView/IxModel.h @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** 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 _IX_MODEL_H_ +#define _IX_MODEL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxModel.h + * \author XDL Team + * \ingroup QxModelView + * \brief Interface to manage Qt model/view architecture with classes registered into QxOrm context (Qt widgets and/or QML views) + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#ifndef Q_MOC_RUN +#include +#include +#include +#include +#include +#include +#include +#include +#endif // Q_MOC_RUN + +namespace qx +{ + namespace model_view + { + namespace detail + { + + template + struct QxNestedModel; + template + struct QxNestedModel_Generic; + template + struct QxNestedModel_Container; + + } // namespace detail + } // namespace model_view +} // namespace qx + +namespace qx +{ + + /*! + * \ingroup QxModelView + * \brief qx::IxModel : interface to manage Qt model/view architecture with classes registered into QxOrm context (Qt widgets and/or QML views) + * + * QxModelView module provides an easy way to work with Qt model/view engine with all classes registered into QxOrm context : + * - Qt widgets : QTableView or QListView for example to display/modify a database table content ; + * - QML : each property defined in QxOrm context is exposed to QML engine : QxModelView module makes easier integration between QML and databases. + * + * qx::IxModel interface provides a generic way for all models linked to persistents classes registered into QxOrm context. All methods of this class prefixed by qx call functions from qx::dao namespace and then communicate with database. + * + * The qxBlogModelView sample project in ./test/ directory of QxOrm package shows how to create quickly a model and associate it to the Qt model/view engine (first with a Qt widget, then with a QML view). + * + * 1- Here is an example to display/modify data from 'author' table (go to qxBlog tutorial for 'author' class definition) in a QTableView : + * \code + // Create a model and fetch all data from database + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + + // Associate the model to a QTableView and display it + QTableView tableView; + tableView.setModel(pModel); + tableView.show(); + * \endcode + * + * 2- Here is another example in QML (with Qt5, QxModelView module works fine with Qt4 too) : + * \code + // Create a model and fetch all data from database + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + + // Associate the model to a QML view and display it + QQuickView qmlView; + qmlView.rootContext()->setContextProperty("myModel", pModel); + qmlView.setSource(QUrl("qrc:/documents/main.qml")); + qmlView.show(); + * \endcode + * + * And here is the 'main.qml' file content : + * \code + import QtQuick 2.1 + import QtQuick.Controls 1.0 + + Item { + width: 400 + height: 300 + Row { + height: 20 + spacing: 20 + Button { + text: "Clear" + onClicked: myModel.clear() + } + Button { + text: "Fetch All" + onClicked: myModel.qxFetchAll_() + } + Button { + text: "Save" + onClicked: myModel.qxSave_() + } + } + ListView { + y: 30 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "id: " + author_id } + TextField { + text: name + onTextChanged: name = text + } + } + } + } + * \endcode + * + * As you can see in the 'main.qml' file, 'author_id' and 'name' properties of 'author' model ('myModel' variable) can be automatically read and write (because they are registered into QxOrm context). + * Moreover, qx::IxModel interface provides a list of methods for QML side (Q_INVOKABLE) to communicate with database : for example, the 'Save' button will save the model in database without having to write a C++ function. + * + * Note : a QxEntityEditor plugin generates automatically the code to manage models with relationships. Then it is possible to work with nested C++ models. + */ + class QX_DLL_EXPORT IxModel : public QAbstractItemModel + { + + Q_OBJECT + + template + friend struct qx::model_view::detail::QxNestedModel; + template + friend struct qx::model_view::detail::QxNestedModel_Generic; + template + friend struct qx::model_view::detail::QxNestedModel_Container; + + public: + enum e_auto_update_database + { + e_no_auto_update, + e_auto_update_on_field_change + }; + + typedef QHash type_relation_by_name; + typedef QList type_lst_relation_by_name; + typedef QHash> type_child_to_its_relation; + + protected: + IxClass *m_pClass; //!< Class introspection registered into QxOrm context associated to the model + IxClass *m_pModelClass; //!< If model itself is registered into QxOrm context, then you can use this property to work with introspection engine + IxDataMemberX *m_pDataMemberX; //!< List of properties defined into QxOrm context + IxDataMember *m_pDataMemberId; //!< Primary key (property id) defined into QxOrm context + IxCollection *m_pCollection; //!< Interface to store a list of items + QHash m_lstRoleNames; //!< List of model's role names to expose data to QML + QList m_lstDataMember; //!< List of data member exposed by the model + QHash m_lstDataMemberByKey; //!< List of data member key to get column index in model + QHash m_lstHeadersData; //!< List of headers data by role and data member key + QStringList m_lstColumns; //!< List of columns exposed by the model (if empty, all columns) + QSqlDatabase m_database; //!< Database connexion to execute SQL queries (if empty, default database connexion) + QSqlError m_lastError; //!< Last SQL error + IxModel *m_pParent; //!< Parent model, NULL if current model is the root model + type_lst_relation_by_name m_lstChild; //!< List of child model : QxEntityEditor uses this property to manage relationships and create complex data structure + type_child_to_its_relation m_hChild; //!< Reverse link to m_lstChild, used in setData() to save relations + e_auto_update_database m_eAutoUpdateDatabase; //!< Auto-update database on field change (detected by the setData() method) + IxDataMember *m_pDataMemberRelationToParent; //!< The data member holding relationship to its parent model (if one exists), used only by nested models + long m_lManualInsertIndex; //!< Index to insert manually items to the collection + QHash m_hCustomProperties; //!< Use this generic hash-table to define extra-properties in your custom classes which inherit from qx::IxModel interface (instead of creating new properties) ==> this will ensure that sizeof(qx::IxModel) == sizeof(YourCustomClass), this is important with nested models feature + + public: + IxModel(QObject *parent = 0); + virtual ~IxModel(); + + IxClass *getClass() const; + IxClass *getModelClass() const; + IxCollection *getCollection() const; + QSqlDatabase getDatabase() const; + QSqlError getLastError() const; + Q_INVOKABLE QString getLastErrorAsString() const; + Q_INVOKABLE QStringList getListOfColumns() const; + QHash getListOfHeaders() const; //!< Obsolete : use headerData() instead + IxDataMember *getDataMember(int column) const; + Q_INVOKABLE QString getDataMemberKey(int column) const; + Q_INVOKABLE int getRowCount() const; + Q_INVOKABLE QVariant getModelValue(int row, const QString &column) const; + Q_INVOKABLE int getColumnIndex(const QString &sColumnName) const; + Q_INVOKABLE int getAutoUpdateDatabase_() const; + e_auto_update_database getAutoUpdateDatabase() const; + Q_INVOKABLE virtual bool getShowEmptyLine() const = 0; //!< Can be useful when a model is displayed in a table (QTableView for example) to add automatically an empty row at the end of the table to insert quickly new items (for example, same style like QxEntityEditor list of properties/relationships) + Q_INVOKABLE QVariant getCustomProperty(const QString &key) const; + Q_INVOKABLE QObject *getParentModel() const; //!< Can be used to figure out whether this model has a parent model (used only by nested models) + Q_INVOKABLE void dumpModel(bool bJsonFormat = true) const; + Q_INVOKABLE QObject *cloneModel(); + + void setDatabase(const QSqlDatabase &db); + Q_INVOKABLE void setListOfColumns(const QStringList &lst); + void setListOfHeaders(const QHash &lst); //!< Obsolete : use setHeaderData() instead + Q_INVOKABLE bool setModelValue(int row, const QString &column, const QVariant &value); + void setParentModel(IxModel *pParent); + Q_INVOKABLE void setAutoUpdateDatabase_(int i); + void setAutoUpdateDatabase(e_auto_update_database e); + Q_INVOKABLE virtual void setShowEmptyLine(bool b) = 0; + Q_INVOKABLE void setCustomProperty(const QString &key, const QVariant &val); + + Q_INVOKABLE QString toJson(int row = -1) const; //!< On QML side, use JSON.parse() to create a javascript object after calling this qx::IxModel::toJson() method + Q_INVOKABLE bool fromJson(const QString &json, int row = -1); //!< On QML side, use JSON.stringify() on a javascript object before calling this qx::IxModel::fromJson() method + + Q_INVOKABLE QVariant getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase = false, const QString &sAppendRelations = QString()); //!< Depending on relationship type (1-1, 1-n, n-1, n-n) : can return a QVariantMap type or a QVariantList type + Q_INVOKABLE bool setRelationshipValues(int row, const QString &relation, const QVariant &values); //!< Depending on relationship type (1-1, 1-n, n-1, n-n) : values parameter can be a QVariantMap type or a QVariantList type + + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxFetchById(const QVariant &id, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxFetchAll(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxFetchRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + virtual QSqlError qxInsertRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) = 0; + virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxSaveRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxSaveRowData(int row, const QStringList &column = QStringList(), QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDeleteRow(int row, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxDestroyRow(int row, QSqlDatabase *pDatabase = NULL) = 0; + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) = 0; + virtual qx_bool qxExist(const QVariant &id, QSqlDatabase *pDatabase = NULL) = 0; + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) = 0; + virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList &groups = QStringList()) = 0; + + Q_INVOKABLE int qxCount_(const QString &sQuery); + Q_INVOKABLE bool qxFetchById_(const QVariant &id, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxFetchAll_(const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxFetchByQuery_(const QString &sQuery, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxFetchRow_(int row, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxInsert_(const QStringList &relation = QStringList(), bool bUseExecBatch = false); + Q_INVOKABLE bool qxInsertRow_(int row, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxUpdate_(const QString &sQuery, const QStringList &relation = QStringList(), bool bUseExecBatch = false); + Q_INVOKABLE bool qxUpdateRow_(int row, const QString &sQuery, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxSave_(const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxSaveRow_(int row, const QStringList &relation = QStringList()); + Q_INVOKABLE bool qxDeleteById_(const QVariant &id); + Q_INVOKABLE bool qxDeleteAll_(); + Q_INVOKABLE bool qxDeleteByQuery_(const QString &sQuery); + Q_INVOKABLE bool qxDeleteRow_(int row); + Q_INVOKABLE bool qxDestroyById_(const QVariant &id); + Q_INVOKABLE bool qxDestroyAll_(); + Q_INVOKABLE bool qxDestroyByQuery_(const QString &sQuery); + Q_INVOKABLE bool qxDestroyRow_(int row); + Q_INVOKABLE bool qxExecuteQuery_(const QString &sQuery); + Q_INVOKABLE bool qxExist_(const QVariant &id); + Q_INVOKABLE QString qxValidate_(const QStringList &groups = QStringList()); + Q_INVOKABLE QString qxValidateRow_(int row, const QStringList &groups = QStringList()); + + QSqlError saveChildRelations(IxModel *pChild); + QVariant getIdFromChild(IxModel *pChild) const; //!< Used to save foreign key in a nested model + QPair getChildPosition(IxModel *pChild) const; + + protected: + void raiseEvent_headerDataChanged(Qt::Orientation orientation, int first, int last); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); + void raiseEvent_layoutAboutToBeChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); + void raiseEvent_layoutChanged(const QList &parents = QList(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void raiseEvent_layoutAboutToBeChanged(); + void raiseEvent_layoutChanged(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + public: + Q_INVOKABLE void clear(bool bUpdateColumns = false); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual Qt::DropActions supportedDropActions() const; + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + virtual bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole); + bool setHeaderData(const QString &sColumnName, const QVariant &value, int role = Qt::EditRole); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + virtual QHash roleNames() const; + virtual Qt::DropActions supportedDragActions() const; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + protected: + virtual QObject *cloneModelImpl() = 0; + virtual void dumpModelImpl(bool bJsonFormat) const = 0; + virtual void *getRowItemAsVoidPtr(int row) const = 0; + virtual bool isDirtyRow(int row) const = 0; + virtual void insertDirtyRowToModel() = 0; + virtual void updateShowEmptyLine() = 0; + virtual void syncNestedModel(int row, const QStringList &relation); + virtual void syncAllNestedModel(const QStringList &relation); + void syncNestedModelRecursive(IxModel *pNestedModel, const QStringList &relation); + + void generateRoleNames(); + QSqlDatabase *database(QSqlDatabase *other); + IxModel *getChild(long row, const QString &relation); + void insertChild(long row, const QString &relation, IxModel *pChild); + void removeListOfChild(long row); + bool removeRowsGeneric(int row, int count); + bool removeRowsAutoUpdateOnFieldChange(int row, int count); + +#ifndef _QX_NO_JSON + + virtual QString toJson_Helper(int row) const = 0; + virtual bool fromJson_Helper(const QString &json, int row) = 0; + + virtual QVariant getRelationshipValues_Helper(int row, const QString &relation, bool bLoadFromDatabase, const QString &sAppendRelations) = 0; + virtual bool setRelationshipValues_Helper(int row, const QString &relation, const QVariant &values) = 0; + +#endif // _QX_NO_JSON + }; + +} // namespace qx + +#endif // _IX_MODEL_H_ diff --git a/include/QxModelView/QxModel.h b/include/QxModelView/QxModel.h new file mode 100644 index 0000000..d564dde --- /dev/null +++ b/include/QxModelView/QxModel.h @@ -0,0 +1,1136 @@ +/**************************************************************************** +** +** 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_MODEL_H_ +#define _QX_MODEL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxModel.h + * \author XDL Team + * \ingroup QxModelView + * \brief All classes registered into QxOrm context can be used with Qt model/view architecture (Qt widgets and/or QML views) + */ + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#ifndef _QX_NO_JSON +#include +#include +#endif // _QX_NO_JSON + +namespace qx +{ + namespace model_view + { + namespace detail + { + + template + struct QxNestedModel; + template + struct QxNestedModel_Generic; + template + struct QxNestedModel_Container; + + } // namespace detail + } // namespace model_view +} // namespace qx + +namespace qx +{ + + /*! + * \ingroup QxModelView + * \brief qx::QxModel : all classes registered into QxOrm context can be used with Qt model/view architecture (Qt widgets and/or QML views) + * + * QxModelView module provides an easy way to work with Qt model/view engine with all classes registered into QxOrm context : + * - Qt widgets : QTableView or QListView for example to display/modify a database table content ; + * - QML : each property defined in QxOrm context is exposed to QML engine : QxModelView module makes easier integration between QML and databases. + * + * qx::IxModel interface provides a generic way for all models linked to persistents classes registered into QxOrm context. All methods of this class prefixed by qx call functions from qx::dao namespace and then communicate with database. + * + * The qxBlogModelView sample project in ./test/ directory of QxOrm package shows how to create quickly a model and associate it to the Qt model/view engine (first with a Qt widget, then with a QML view). + * + * 1- Here is an example to display/modify data from 'author' table (go to qxBlog tutorial for 'author' class definition) in a QTableView : + * \code + // Create a model and fetch all data from database + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + + // Associate the model to a QTableView and display it + QTableView tableView; + tableView.setModel(pModel); + tableView.show(); + * \endcode + * + * 2- Here is another example in QML (with Qt5, QxModelView module works fine with Qt4 too) : + * \code + // Create a model and fetch all data from database + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + + // Associate the model to a QML view and display it + QQuickView qmlView; + qmlView.rootContext()->setContextProperty("myModel", pModel); + qmlView.setSource(QUrl("qrc:/documents/main.qml")); + qmlView.show(); + * \endcode + * + * And here is the 'main.qml' file content : + * \code + import QtQuick 2.1 + import QtQuick.Controls 1.0 + + Item { + width: 400 + height: 300 + Row { + height: 20 + spacing: 20 + Button { + text: "Clear" + onClicked: myModel.clear() + } + Button { + text: "Fetch All" + onClicked: myModel.qxFetchAll_() + } + Button { + text: "Save" + onClicked: myModel.qxSave_() + } + } + ListView { + y: 30 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "id: " + author_id } + TextField { + text: name + onTextChanged: name = text + } + } + } + } + * \endcode + * + * As you can see in the 'main.qml' file, 'author_id' and 'name' properties of 'author' model ('myModel' variable) can be automatically read and write (because they are registered into QxOrm context). + * Moreover, qx::IxModel interface provides a list of methods for QML side (Q_INVOKABLE) to communicate with database : for example, the 'Save' button will save the model in database without having to write a C++ function. + * + * Note : a QxEntityEditor plugin generates automatically the code to manage models with relationships. Then it is possible to work with nested C++ models. + */ + template + class QxModel : public B // B type must inherit from qx::IxModel and must not define new data-members (use 'm_hCustomProperties' or QObject dynamic properties if you need new properties in your derived class) + { + + template + friend struct qx::model_view::detail::QxNestedModel; + template + friend struct qx::model_view::detail::QxNestedModel_Generic; + template + friend struct qx::model_view::detail::QxNestedModel_Container; + + public: + typedef std::shared_ptr type_ptr; + typedef typename qx::trait::get_primary_key::type type_primary_key; + typedef qx::QxCollection type_collection; + typedef B type_base_class; + + enum + { + qx_is_valid = (qx::trait::is_qx_registered::value && std::is_base_of::value) + }; + + protected: + type_collection m_model; //!< Model associated to a class registered into QxOrm context + std::shared_ptr> m_pDirtyRow; //!< When displayed in a QTableView, this will cause an empty line awaiting user input to be displayed at the bottom (enabled with setShowEmptyLine() method) + + public: + QxModel(QObject *parent = 0) : B(parent) { qx::QxModel::init(); } + QxModel(qx::IxModel *other, QObject *parent) : B(parent) { qx::QxModel::initFrom(other); } + virtual ~QxModel() { ; } + + protected: + void init() + { + static_assert(qx_is_valid, "qx_is_valid"); + this->m_pClass = qx::QxClass::getSingleton(); + qAssert(this->m_pClass != NULL); + this->m_pDataMemberX = (this->m_pClass ? this->m_pClass->getDataMemberX() : NULL); + qAssert(this->m_pDataMemberX != NULL); + this->m_pDataMemberId = (this->m_pDataMemberX ? this->m_pDataMemberX->getId_WithDaoStrategy() : NULL); + this->m_pCollection = (&m_model); + this->generateRoleNames(); + } + + void initFrom(qx::IxModel *pOther) + { + init(); + qx::QxModel *pOtherWrk = static_cast *>(pOther); + m_model = pOtherWrk->m_model; + this->m_lManualInsertIndex = pOtherWrk->m_lManualInsertIndex; + this->setParentModel(pOtherWrk->m_pParent); + if (this->m_pParent) + { + this->m_eAutoUpdateDatabase = this->m_pParent->getAutoUpdateDatabase(); + } + this->m_hCustomProperties = pOtherWrk->m_hCustomProperties; + } + + public: + virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) + { + if (parent.isValid()) + { + return false; + } + if ((row < 0) || (count <= 0)) + { + return false; + } + this->beginInsertRows(QModelIndex(), row, (row + count - 1)); + for (int i = 0; i < count; ++i) + { + type_ptr pItem = type_ptr(new T()); + insertItem(row, pItem); + } + this->endInsertRows(); + return true; + } + + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) + { + IxDataMember *pDataMember = this->getDataMember(column); + if (!pDataMember) + { + return; + } + m_model.sort(qx::model_view::QxModelRowCompare((order == Qt::AscendingOrder), pDataMember)); + this->raiseEvent_layoutChanged(); + } + + virtual bool getShowEmptyLine() const { return m_pDirtyRow.get(); } + + virtual void setShowEmptyLine(bool b) + { + if (b == getShowEmptyLine()) + { + return; + } + if (b) + { + addDirtyRow(); + return; + } + this->beginRemoveRows(QModelIndex(), this->rowCount(), this->rowCount()); + m_pDirtyRow.reset(); + this->endRemoveRows(); + } + + public: + /*! + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + */ + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + return qx::dao::count(query, this->database(pDatabase)); + } + + /*! + * \brief Return the number of lines in the table (database) mapped to the C++ class T (registered into QxOrm context) and filtered by a user SQL query + * \param lCount Output parameter with the number of lines in the table associated to the SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library (optional parameter) + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + */ + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + this->m_lastError = qx::dao::count(lCount, query, this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Clear the model and fetch an object (retrieve all its properties) of type T (registered into QxOrm context) mapped to a table in the database + * \param id Row id to be fetched (retrieve all properties from database) + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxFetchById(const QVariant &id, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + this->clear(); + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxFetchById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxFetchById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + + type_primary_key primaryKey; + qx::cvt::from_variant(id, primaryKey); + this->beginInsertRows(QModelIndex(), 0, 0); + m_model.insert(primaryKey, pItem); + + if (relation.count() == 0) + { + this->m_lastError = qx::dao::fetch_by_id((*pItem), this->database(pDatabase), this->m_lstColumns); + } + else + { + this->m_lastError = qx::dao::fetch_by_id_with_relation(relation, (*pItem), this->database(pDatabase)); + } + this->updateShowEmptyLine(); + this->endInsertRows(); + return this->m_lastError; + } + + /*! + * \brief Clear the model and fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxFetchAll(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + this->clear(); + type_collection tmp; + if (relation.count() == 0) + { + this->m_lastError = qx::dao::fetch_all(tmp, this->database(pDatabase), this->m_lstColumns); + } + else + { + this->m_lastError = qx::dao::fetch_all_with_relation(relation, tmp, this->database(pDatabase)); + } + + if (tmp.count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + m_model = tmp; + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + /*! + * \brief Clear the model and fetch a list of objects (retrieve all elements and properties associated) of type T (container registered into QxOrm context) mapped to a table in the database and filtered by a user SQL query + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + this->clear(); + type_collection tmp; + if (relation.count() == 0) + { + this->m_lastError = qx::dao::fetch_by_query(query, tmp, this->database(pDatabase), this->m_lstColumns); + } + else + { + this->m_lastError = qx::dao::fetch_by_query_with_relation(relation, query, tmp, this->database(pDatabase)); + } + + if (tmp.count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + m_model = tmp; + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + /*! + * \brief Get an item in the model at line row and fetch all its properties mapped to a table in the database, then all views attached to this model are automatically updated + * \param row Get an item in the model at line row + * \param relation List of relationships keys to be fetched (eager fetch instead of default lazy fetch for a relation) : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxFetchRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return QSqlError(); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::fetch_by_id((*pItem), this->database(pDatabase), this->m_lstColumns); + } + else + { + this->m_lastError = qx::dao::fetch_by_id_with_relation(relation, (*pItem), this->database(pDatabase)); + } + if (this->m_lastError.isValid()) + { + return this->m_lastError; + } + + QModelIndex idxTopLeft = this->index(row, 0); + QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1)); + this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight); + updateKey(row); + return this->m_lastError; + } + + /*! + * \brief Insert all items in the model into database + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance inserting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::insert(m_model, this->database(pDatabase), bUseExecBatch); + } + else + { + this->m_lastError = qx::dao::insert_with_relation(relation, m_model, this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + /*! + * \brief Insert an item of the model at line row into database + * \param row Insert an item in the model at line row + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxInsertRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::insert((*pItem), this->database(pDatabase)); + } + else + { + this->m_lastError = qx::dao::insert_with_relation(relation, (*pItem), this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + updateKey(row); + } + return this->m_lastError; + } + + /*! + * \brief Update all items in the model into database + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \param bUseExecBatch If true then use the QSqlQuery::execBatch() method to improve performance updating a list of instances in database + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::update_by_query(query, m_model, this->database(pDatabase), this->m_lstColumns, bUseExecBatch); + } + else + { + this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, m_model, this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + /*! + * \brief Update an item of the model at line row into database + * \param row Update an item in the model at line row + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + if ((row < 0) || (row >= m_model.count())) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::update_by_query(query, (*pItem), this->database(pDatabase), this->m_lstColumns); + } + else + { + this->m_lastError = qx::dao::update_by_query_with_relation(relation, query, (*pItem), this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + updateKey(row); + } + return this->m_lastError; + } + + /*! + * \brief Save all items (insert or update) in the model into database + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::save(m_model, this->database(pDatabase)); + } + else + { + this->m_lastError = qx::dao::save_with_relation(relation, m_model, this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + /*! + * \brief Save an item of the model at line row into database + * \param row Save an item (insert or update) in the model at line row + * \param relation List of relationships keys to be inserted in others tables of database : use "|" separator to put many relationships keys into this parameter + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxSaveRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + if ((row < 0) || (row >= m_model.count())) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + if (relation.count() == 0) + { + this->m_lastError = qx::dao::save((*pItem), this->database(pDatabase)); + } + else + { + this->m_lastError = qx::dao::save_with_relation(relation, (*pItem), this->database(pDatabase)); + } + if (!this->m_lastError.isValid()) + { + updateKey(row); + } + return this->m_lastError; + } + + /*! + * \brief Used internally by qx::IxModel::setData() method with e_auto_update_on_field_change option, save an item (even if it is the dirty row item) of the model at line row into database + * \param row Save an item (insert or update) in the model at line row + * \param column List of columns of model to save in database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxSaveRowData(int row, const QStringList &column = QStringList(), QSqlDatabase *pDatabase = NULL) + { + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxSaveRowData()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return QSqlError(); + } + QVariant id = this->m_pDataMemberId->toVariant(pItem.get()); + bool bExist = qx::trait::is_valid_primary_key(id); + if (bExist) + { + bExist = qx::dao::exist((*pItem), this->database(pDatabase)); + } + if (bExist) + { + this->m_lastError = qx::dao::update((*pItem), this->database(pDatabase), column); + } + else + { + this->m_lastError = qx::dao::insert((*pItem), this->database(pDatabase)); + } + return this->m_lastError; + } + + /*! + * \brief Delete a line of a table (database) mapped to a C++ object of type T (registered into QxOrm context), if no error occurred then you should remove row from the model + * \param id Row id to be deleted from database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + this->m_lastError = qx::dao::delete_by_id((*pItem), this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context), if no error occurred then you should clear the model + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) + { + this->m_lastError = qx::dao::delete_all(this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete all lines of a table (database) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query, if no error occurred then you should refresh the model + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + this->m_lastError = qx::dao::delete_by_query(query, this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete in database the item at line row in the model, if no error occurred then you should remove row from the model + * \param row Delete in database the item in the model at line row + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDeleteRow(int row, QSqlDatabase *pDatabase = NULL) + { + if ((row < 0) || (row >= m_model.count())) + { + return QSqlError(); + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + this->m_lastError = qx::dao::delete_by_id((*pItem), this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete a line of a table (even if a logical delete is defined) mapped to a C++ object of type T (registered into QxOrm context), if no error occurred then you should remove row from the model + * \param id Row id to be deleted from database + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + this->m_lastError = qx::dao::destroy_by_id((*pItem), this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete all lines of a table (even if a logical delete is defined) mapped to a C++ class T (registered into QxOrm context), if no error occurred then you should clear the model + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) + { + this->m_lastError = qx::dao::destroy_all(this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete all lines of a table (even if a logical delete is defined) mapped to a C++ class T (registered into QxOrm context) and filtered by a user SQL query, if no error occurred then you should refresh the model + * \param query Define a user SQL query added to default SQL query builded by QxOrm library + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + this->m_lastError = qx::dao::destroy_by_query(query, this->database(pDatabase)); + return this->m_lastError; + } + + /*! + * \brief Delete in database (even if a logical delete is defined) the item at line row in the model, if no error occurred then you should remove row from the model + * \param row Delete in database the item in the model at line row + * \param pDatabase Connection to database (you can manage your own connection pool for example, you can also define a transaction, etc.); if NULL, a valid connection for the current thread is provided by qx::QxSqlDatabase singleton class (optional parameter) + * \return Empty QSqlError object (from Qt library) if no error occurred; otherwise QSqlError contains a description of database error executing SQL query + */ + virtual QSqlError qxDestroyRow(int row, QSqlDatabase *pDatabase = NULL) + { + if ((row < 0) || (row >= m_model.count())) + { + return QSqlError(); + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + this->m_lastError = qx::dao::destroy_by_id((*pItem), this->database(pDatabase)); + return this->m_lastError; + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + this->clear(); + type_collection tmp; + this->m_lastError = qx::dao::execute_query(query, tmp, this->database(pDatabase)); + + if (tmp.count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + m_model = tmp; + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + virtual qx_bool qxExist(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + return qx_bool(false); + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + return qx::dao::exist((*pItem), this->database(pDatabase)); + } + + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) + { + return qx::validate(m_model, groups); + } + + virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList &groups = QStringList()) + { + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return qx::QxInvalidValueX(); + } + return qx::validate((*pItem), groups); + } + + protected: + type_ptr getRowItemAt(int row) const + { + if ((row >= 0) && (row < m_model.count())) + { + return m_model.getByIndex(row); + } + if (m_pDirtyRow && (m_pDirtyRow->first == row)) + { + return m_pDirtyRow->second; + } + return type_ptr(); + } + + virtual void *getRowItemAsVoidPtr(int row) const { return getRowItemAt(row).get(); } + + virtual void dumpModelImpl(bool bJsonFormat) const { qx::dump(m_model, bJsonFormat); } + + virtual QObject *cloneModelImpl() + { + qx::QxModel *pClone = new qx::QxModel(this, NULL); + std::shared_ptr pModel = qx::clone(pClone->m_model); + if (pModel) + { + pClone->m_model = (*pModel); + } + return static_cast(pClone); + } + + virtual void updateShowEmptyLine() + { + if (m_pDirtyRow) + { + m_pDirtyRow->first = m_model.count(); + } + } + + virtual bool isDirtyRow(int row) const { return (m_pDirtyRow && (m_pDirtyRow->first == row)); } + + virtual void insertDirtyRowToModel() + { + if (!m_pDirtyRow) + { + return; + } + int row = m_pDirtyRow->first; + insertItem(row, m_pDirtyRow->second); + if (this->m_pParent) + { + this->m_pParent->saveChildRelations(this); + } + updateKey(row); + addDirtyRow(); + } + + void addDirtyRow() + { + this->beginInsertRows(QModelIndex(), m_model.count(), m_model.count()); + m_pDirtyRow.reset(new QPair(m_model.count(), type_ptr(new T()))); + IxSqlRelation *pRelationParent = (this->m_pDataMemberRelationToParent ? this->m_pDataMemberRelationToParent->getSqlRelation() : NULL); + IxSqlRelation::relation_type eRelationParentType = (pRelationParent ? pRelationParent->getRelationType() : IxSqlRelation::no_relation); + if (this->m_pParent && ((eRelationParentType == IxSqlRelation::many_to_many) || (eRelationParentType == IxSqlRelation::many_to_one))) + { + this->m_pDataMemberRelationToParent->fromVariant(m_pDirtyRow->second.get(), this->m_pParent->getIdFromChild(this)); + } + this->endInsertRows(); + } + + void insertItem(int row, const type_ptr &pItem) + { + if (!pItem) + { + return; + } + type_primary_key primaryKey; + this->m_lManualInsertIndex = (this->m_lManualInsertIndex - 1); + QVariant vNewId(static_cast(this->m_lManualInsertIndex)); + qx::cvt::from_variant(vNewId, primaryKey); + m_model.insert(row, primaryKey, pItem); + this->updateShowEmptyLine(); + } + + void updateKey(int row) + { + if ((row < 0) || (row >= m_model.count())) + { + return; + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem || !this->m_pDataMemberId) + { + return; + } + type_primary_key currPrimaryKey = m_model.getKeyByIndex(row); + QVariant vCurrPrimaryKey = qx::cvt::to_variant(currPrimaryKey); + QVariant vNextPrimaryKey = this->m_pDataMemberId->toVariant(pItem.get()); + if ((vCurrPrimaryKey == vNextPrimaryKey) || (!vNextPrimaryKey.isValid())) + { + return; + } + if (!qx::trait::is_valid_primary_key(vNextPrimaryKey)) + { + return; + } + type_primary_key updatedPrimaryKey; + qx::cvt::from_variant(vNextPrimaryKey, updatedPrimaryKey); + if (m_model.exist(updatedPrimaryKey)) + { + return; + } + m_model.removeByIndex(row); + m_model.insert(row, updatedPrimaryKey, pItem); + } + + void updateAllKeys() + { + for (long l = 0; l < m_model.count(); l++) + { + updateKey(l); + } + } + + protected: +#ifndef _QX_NO_JSON + + virtual QString toJson_Helper(int row) const + { + if (row == -1) + { + return qx::serialization::json::to_string(m_model); + } + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return QString(); + } + return qx::serialization::json::to_string(*pItem); + } + + virtual bool fromJson_Helper(const QString &json, int row) + { + if (row == -1) + { + this->clear(); + type_collection tmp; + if (!qx::serialization::json::from_string(tmp, json)) + { + return false; + } + this->beginResetModel(); + m_model = tmp; + this->updateShowEmptyLine(); + this->endResetModel(); + return true; + } + + type_ptr pItem = getRowItemAt(row); + if (!pItem) + { + return false; + } + if (!qx::serialization::json::from_string((*pItem), json)) + { + return false; + } + + QModelIndex idxTopLeft = this->index(row, 0); + QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1)); + this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight); + updateKey(row); + return true; + } + + virtual QVariant getRelationshipValues_Helper(int row, const QString &relation, bool bLoadFromDatabase, const QString &sAppendRelations) + { + if ((row < 0) || (row >= m_model.count())) + { + return QVariant(); + } + if (!this->m_pDataMemberId || !this->m_pDataMemberX || !this->m_pDataMemberX->exist(relation)) + { + return QVariant(); + } + IxDataMember *pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); + if (!pDataMember) + { + return QVariant(); + } + IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); + if (!pRelation) + { + return QVariant(); + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return QVariant(); + } + type_ptr pItemTemp = pItem; + + if (bLoadFromDatabase) + { + QString sRelation = relation; + if (!sAppendRelations.isEmpty() && !sAppendRelations.startsWith("->") && !sAppendRelations.startsWith(">>")) + { + sRelation += "->" + sAppendRelations; + } + else if (!sAppendRelations.isEmpty()) + { + sRelation += sAppendRelations; + } + pItemTemp = type_ptr(new T()); + QVariant id = this->m_pDataMemberId->toVariant(pItem.get()); + this->m_pDataMemberId->fromVariant(pItemTemp.get(), id); + QSqlError daoError = qx::dao::fetch_by_id_with_relation(sRelation, (*pItemTemp)); + if (daoError.isValid()) + { + return QVariant(); + } + } + + QJsonValue json = pDataMember->toJson(pItemTemp.get()); + if (json.isNull()) + { + return QVariant(); + } + if (json.isArray()) + { + return json.toArray().toVariantList(); + } + return json.toObject().toVariantMap(); + } + + virtual bool setRelationshipValues_Helper(int row, const QString &relation, const QVariant &values) + { + if ((row < 0) || (row >= m_model.count())) + { + return false; + } + if ((values.type() != QVariant::List) && (values.type() != QVariant::Map)) + { + return false; + } + if (!this->m_pDataMemberId || !this->m_pDataMemberX || !this->m_pDataMemberX->exist(relation)) + { + return false; + } + IxDataMember *pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); + if (!pDataMember) + { + return false; + } + IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); + if (!pRelation) + { + return false; + } + type_ptr pItem = m_model.getByIndex(row); + if (!pItem) + { + return false; + } + + QJsonValue json; + if (values.type() == QVariant::List) + { + json = QJsonArray::fromVariantList(values.toList()); + } + else if (values.type() == QVariant::Map) + { + json = QJsonObject::fromVariantMap(values.toMap()); + } + if (!pDataMember->fromJson(pItem.get(), json)) + { + return false; + } + + QModelIndex idxTopLeft = this->index(row, 0); + QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1)); + this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight); + return true; + } + +#endif // _QX_NO_JSON + }; + +} // namespace qx + +#endif // _QX_MODEL_H_ diff --git a/include/QxModelView/QxModelRowCompare.h b/include/QxModelView/QxModelRowCompare.h new file mode 100644 index 0000000..8ef96f5 --- /dev/null +++ b/include/QxModelView/QxModelRowCompare.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_MODEL_ROW_COMPARE_H_ +#define _QX_MODEL_ROW_COMPARE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxModelRowCompare.h + * \author XDL Team + * \ingroup QxModelView + * \brief Functor used to provide sort feature for all models based on qx::IxModel interface (please note that you can also use QSortFilterProxyModel Qt class to sort your model) + */ + +#include + +namespace qx +{ + namespace model_view + { + + QX_DLL_EXPORT bool compareQVariant(const QVariant &v1, const QVariant &v2, bool bAscending) QX_USED; + + /*! + * \ingroup QxModelView + * \brief qx::QxModelRowCompare : functor used to provide sort feature for all models based on qx::IxModel interface (please note that you can also use QSortFilterProxyModel Qt class to sort your model) + */ + template + struct QxModelRowCompare + { + + bool m_bAscendingOrder; //!< Sort your model using ascending or descending order + qx::IxDataMember *m_pDataMember; //!< Data member associated to the model column to sort + + QxModelRowCompare(bool bAscendingOrder, qx::IxDataMember *pDataMember) : m_bAscendingOrder(bAscendingOrder), m_pDataMember(pDataMember) { qAssert(m_pDataMember != NULL); } + + bool operator()(const T &t1, const T &t2) const + { + if (!m_pDataMember || !t1.second || !t2.second) + { + return false; + } + QVariant v1 = m_pDataMember->toVariant(&(*t1.second)); + QVariant v2 = m_pDataMember->toVariant(&(*t2.second)); + return qx::model_view::compareQVariant(v1, v2, m_bAscendingOrder); + } + }; + + } // namespace model_view +} // namespace qx + +#endif // _QX_MODEL_ROW_COMPARE_H_ diff --git a/include/QxModelView/QxModelService.h b/include/QxModelView/QxModelService.h new file mode 100644 index 0000000..249cba6 --- /dev/null +++ b/include/QxModelView/QxModelService.h @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** 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_MODEL_SERVICE_H_ +#define _QX_MODEL_SERVICE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxModelService.h + * \author XDL Team + * \ingroup QxModelView + * \brief qx::QxModelService provides an easy way to connect your model to the QxService module (all queries are executed over network using client/server communication) + */ + +#include + +namespace qx +{ + + /*! + * \ingroup QxModelView + * \brief qx::QxModelService : provides an easy way to connect your model to the QxService module (all queries are executed over network using client/server communication) + * + * T template parameter is a persistent class registered into QxOrm context + * S template parameter is a service class generated by QxEntityEditor (or your own service class providing all methods) + */ + template + class QxModelService : public qx::QxModel + { + + public: + typedef typename qx::QxModel::type_ptr type_ptr; + typedef typename qx::QxModel::type_primary_key type_primary_key; + typedef typename qx::QxModel::type_collection type_collection; + typedef std::shared_ptr type_collection_ptr; + typedef B type_base_class; + + public: + QxModelService(QObject *parent = 0) : qx::QxModel(parent) { ; } + QxModelService(qx::IxModel *other, QObject *parent) : qx::QxModel(other, parent) { ; } + virtual ~QxModelService() { ; } + + virtual long qxCount(const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + long lCount = 0; + this->qxCount(lCount, query, pDatabase); + return lCount; + } + + virtual QSqlError qxCount(long &lCount, const qx::QxSqlQuery &query = qx::QxSqlQuery(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + S services; + this->m_lastError = services.count(lCount, query); + return this->m_lastError; + } + + virtual QSqlError qxFetchById(const QVariant &id, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + this->clear(); + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxFetchById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxFetchById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + + type_primary_key primaryKey; + qx::cvt::from_variant(id, primaryKey); + this->beginInsertRows(QModelIndex(), 0, 0); + this->m_model.insert(primaryKey, pItem); + + S services; + this->m_lastError = services.fetchById(pItem, this->m_lstColumns, relation); + this->updateShowEmptyLine(); + this->endInsertRows(); + return this->m_lastError; + } + + virtual QSqlError qxFetchAll(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + this->clear(); + + S services; + type_collection_ptr tmp = std::make_shared(); + this->m_lastError = services.fetchAll(tmp, this->m_lstColumns, relation); + + if (tmp->count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + this->m_model = (*tmp); + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery &query, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + this->clear(); + + S services; + type_collection_ptr tmp = std::make_shared(); + this->m_lastError = services.fetchByQuery(query, tmp, this->m_lstColumns, relation); + + if (tmp->count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + this->m_model = (*tmp); + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + virtual QSqlError qxFetchRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.fetchById(pItem, this->m_lstColumns, relation); + if (this->m_lastError.isValid()) + { + return this->m_lastError; + } + + QModelIndex idxTopLeft = this->index(row, 0); + QModelIndex idxBottomRight = this->index(row, (this->m_lstDataMember.count() - 1)); + this->raiseEvent_dataChanged(idxTopLeft, idxBottomRight); + this->updateKey(row); + return this->m_lastError; + } + + virtual QSqlError qxInsert(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(pDatabase); + Q_UNUSED(bUseExecBatch); + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + + type_collection_ptr tmp = std::make_shared(); + (*tmp) = this->m_model; + + S services; + this->m_lastError = services.insert(tmp, relation); + + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + virtual QSqlError qxInsertRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.insert(pItem, relation); + + if (!this->m_lastError.isValid()) + { + this->updateKey(row); + } + return this->m_lastError; + } + + virtual QSqlError qxUpdate(const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL, bool bUseExecBatch = false) + { + Q_UNUSED(pDatabase); + Q_UNUSED(bUseExecBatch); + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + + type_collection_ptr tmp = std::make_shared(); + (*tmp) = this->m_model; + + S services; + this->m_lastError = services.update(tmp, query, this->m_lstColumns, relation); + + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + virtual QSqlError qxUpdateRow(int row, const qx::QxSqlQuery &query = qx::QxSqlQuery(), const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.update(pItem, query, this->m_lstColumns, relation); + + if (!this->m_lastError.isValid()) + { + this->updateKey(row); + } + return this->m_lastError; + } + + virtual QSqlError qxSave(const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if (relation.count() > 0) + { + this->syncAllNestedModel(relation); + } + + type_collection_ptr tmp = std::make_shared(); + (*tmp) = this->m_model; + + S services; + this->m_lastError = services.save(tmp, relation); + + if (!this->m_lastError.isValid()) + { + this->updateAllKeys(); + } + return this->m_lastError; + } + + virtual QSqlError qxSaveRow(int row, const QStringList &relation = QStringList(), QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + if (relation.count() > 0) + { + this->syncNestedModel(row, relation); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.save(pItem, relation); + + if (!this->m_lastError.isValid()) + { + this->updateKey(row); + } + return this->m_lastError; + } + + virtual QSqlError qxDeleteById(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + + S services; + this->m_lastError = services.deleteById(pItem); + return this->m_lastError; + } + + virtual QSqlError qxDeleteAll(QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + S services; + this->m_lastError = services.deleteAll(); + return this->m_lastError; + } + + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + S services; + this->m_lastError = services.deleteByQuery(query); + return this->m_lastError; + } + + virtual QSqlError qxDeleteRow(int row, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.deleteById(pItem); + return this->m_lastError; + } + + virtual QSqlError qxDestroyById(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxDeleteById()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + this->m_lastError = QSqlError("[QxOrm] problem with 'qxDeleteById()' method : 'data member id not registered'", "", QSqlError::UnknownError); + return this->m_lastError; + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + + S services; + this->m_lastError = services.destroyById(pItem); + return this->m_lastError; + } + + virtual QSqlError qxDestroyAll(QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + S services; + this->m_lastError = services.destroyAll(); + return this->m_lastError; + } + + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + S services; + this->m_lastError = services.destroyByQuery(query); + return this->m_lastError; + } + + virtual QSqlError qxDestroyRow(int row, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + if ((row < 0) || (row >= this->m_model.count())) + { + return QSqlError(); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QSqlError(); + } + + S services; + this->m_lastError = services.destroyById(pItem); + return this->m_lastError; + } + + virtual QSqlError qxExecuteQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + this->clear(); + + S services; + type_collection_ptr tmp = std::make_shared(); + this->m_lastError = services.executeQuery(query, tmp); + + if (tmp->count() <= 0) + { + return this->m_lastError; + } + this->beginResetModel(); + this->m_model = (*tmp); + this->updateShowEmptyLine(); + this->endResetModel(); + return this->m_lastError; + } + + virtual qx_bool qxExist(const QVariant &id, QSqlDatabase *pDatabase = NULL) + { + Q_UNUSED(pDatabase); + type_ptr pItem = type_ptr(new T()); + if (!this->m_pDataMemberId) + { + qDebug("[QxOrm] problem with 'qxExist()' method : '%s'", "data member id not registered"); + qAssert(false); + } + if (!this->m_pDataMemberId) + { + return qx_bool(false); + } + this->m_pDataMemberId->fromVariant(pItem.get(), id); + + S services; + return services.exist(pItem); + } + + virtual qx::QxInvalidValueX qxValidate(const QStringList &groups = QStringList()) + { + Q_UNUSED(groups); + S services; + type_collection_ptr tmp = std::make_shared(); + (*tmp) = this->m_model; + return services.isValid(tmp); + } + + virtual qx::QxInvalidValueX qxValidateRow(int row, const QStringList &groups = QStringList()) + { + Q_UNUSED(groups); + if ((row < 0) || (row >= this->m_model.count())) + { + return qx::QxInvalidValueX(); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return qx::QxInvalidValueX(); + } + + S services; + return services.isValid(pItem); + } + + protected: +#ifndef _QX_NO_JSON + + virtual QVariant getRelationshipValues_Helper(int row, const QString &relation, bool bLoadFromDatabase, const QString &sAppendRelations) + { + if ((row < 0) || (row >= this->m_model.count())) + { + return QVariant(); + } + if (!this->m_pDataMemberId || !this->m_pDataMemberX || !this->m_pDataMemberX->exist(relation)) + { + return QVariant(); + } + IxDataMember *pDataMember = this->m_pDataMemberX->get_WithDaoStrategy(relation); + if (!pDataMember) + { + return QVariant(); + } + IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); + if (!pRelation) + { + return QVariant(); + } + type_ptr pItem = this->m_model.getByIndex(row); + if (!pItem) + { + return QVariant(); + } + type_ptr pItemTemp = pItem; + + if (bLoadFromDatabase) + { + QString sRelation = relation; + if (!sAppendRelations.isEmpty() && !sAppendRelations.startsWith("->") && !sAppendRelations.startsWith(">>")) + { + sRelation += "->" + sAppendRelations; + } + else if (!sAppendRelations.isEmpty()) + { + sRelation += sAppendRelations; + } + pItemTemp = type_ptr(new T()); + QVariant id = this->m_pDataMemberId->toVariant(pItem.get()); + this->m_pDataMemberId->fromVariant(pItemTemp.get(), id); + + S services; + QStringList columns; + QSqlError daoError = services.fetchById(pItemTemp, columns, QStringList() << sRelation); + if (daoError.isValid()) + { + return QVariant(); + } + } + + QJsonValue json = pDataMember->toJson(pItemTemp.get()); + if (json.isNull()) + { + return QVariant(); + } + if (json.isArray()) + { + return json.toArray().toVariantList(); + } + return json.toObject().toVariantMap(); + } + +#endif // _QX_NO_JSON + }; + +} // namespace qx + +#endif // _QX_MODEL_SERVICE_H_ diff --git a/include/QxModelView/QxNestedModel.h b/include/QxModelView/QxNestedModel.h new file mode 100644 index 0000000..8433386 --- /dev/null +++ b/include/QxModelView/QxNestedModel.h @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** 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_NESTED_MODEL_H_ +#define _QX_NESTED_MODEL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxNestedModel.h + * \author XDL Team + * \ingroup QxModelView + * \brief qx::model_view::create_nested_model is used by QxEntityEditor to manage complex data structure to work with relationships in QML views and Qt model/view architecture + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace model_view + { + + template + qx::IxModel *create_nested_model(qx::IxModel *pParent, const QModelIndex &idxParent, T &t); + + template + qx::IxModel *create_nested_model_with_type(qx::IxModel *pParent, const QModelIndex &idxParent, T &t, M *pModelType); + + template + void sync_nested_model(qx::IxModel *pModel, T &t); + + } // namespace model_view +} // namespace qx + +namespace qx +{ + namespace model_view + { + namespace detail + { + + template + struct QxNestedModel; + + template + struct QxNestedModel_Helper + { + + static std::shared_ptr clone(T &t) + { + std::shared_ptr p = std::make_shared(); + (*p) = t; + return p; + } + + static void synchronize(T &t1, T &t2) + { + t1 = t2; + } + }; + + template + struct QxNestedModel_Helper + { + + static std::shared_ptr clone(T &t) + { + std::shared_ptr p; + p.reset(qx::clone_to_nude_ptr(t)); + qAssert(p); + return p; + } + + static void synchronize(T &t1, T &t2) + { + qx::IxClass *pClass = qx::QxClass::getSingleton(); + qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get_WithDaoStrategy(l); + if (!pDataMember) + { + continue; + } + QVariant value = pDataMember->toVariant(&t2); + pDataMember->fromVariant((&t1), value); + } + } + }; + + template + struct QxNestedModel_Creator + { + static qx::IxModel *newModel(qx::IxModel *pParent) { return new M(pParent); } + }; + + template + struct QxNestedModel_Creator + { + static qx::IxModel *newModel(qx::IxModel *pParent) { return new qx::QxModel(pParent); } + }; + + template + struct QxNestedModel_Generic + { + + typedef typename qx::QxModel::type_collection type_collection; + typedef typename qx::QxModel::type_primary_key type_primary_key; + typedef typename qx::QxModel::type_ptr type_ptr; + + enum + { + is_valid = qx::trait::is_qx_registered::value + }; + + static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t) + { + static_assert(is_valid, "is_valid"); + qx::IxModel *pModel = qx::model_view::detail::QxNestedModel_Creator::value>::newModel(pParent); + pModel->setParentModel(pParent); + type_collection *pListOfItems = static_cast(pModel->getCollection()); + long &idx = pModel->m_lManualInsertIndex; + type_primary_key key; + + pModel->beginInsertRows(idxParent, 0, 0); + type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper::value>::clone(t); + qx::IxDataMember *pDataMemberId = pModel->m_pDataMemberId; + if (!pDataMemberId) + { + qAssert(false); + pModel->endInsertRows(); + return pModel; + } + QVariant value = pDataMemberId->toVariant(&t); + if (!qx::trait::is_valid_primary_key(value)) + { + idx--; + value = QVariant(static_cast(idx)); + } + qx::cvt::from_variant(value, key); + pListOfItems->insert(0, key, ptr); + pModel->endInsertRows(); + return pModel; + } + + static inline void synchronize(qx::IxModel *pModel, T &t) + { + if (!pModel) + { + qAssert(false); + return; + } + type_collection *pListOfItems = static_cast(pModel->getCollection()); + if (!pListOfItems || (pListOfItems->count() <= 0)) + { + return; + } + type_ptr ptr = pListOfItems->getByIndex(0); + if (!ptr) + { + return; + } + qx::model_view::detail::QxNestedModel_Helper::value>::synchronize(t, (*ptr)); + } + }; + + template + struct QxNestedModel_Container + { + + typedef qx::trait::generic_container type_generic_container; + typedef typename type_generic_container::type_value_qx type_data; + typedef typename type_generic_container::type_item type_item; + typedef typename qx::QxModel::type_collection type_collection; + typedef typename qx::QxModel::type_primary_key type_primary_key; + typedef typename qx::QxModel::type_ptr type_ptr; + + enum + { + is_valid = qx::trait::is_qx_registered::value + }; + + static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t) + { + int iCurrRow = 0; + static_assert(is_valid, "is_valid"); + qx::IxModel *pModel = qx::model_view::detail::QxNestedModel_Creator::value>::newModel(pParent); + pModel->setParentModel(pParent); + long lCount = static_cast(type_generic_container::size(t)); + if (lCount <= 0) + { + return pModel; + } + + pModel->beginInsertRows(idxParent, 0, (lCount - 1)); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + insertItem(pModel, (*it), iCurrRow); + iCurrRow++; + } + pModel->endInsertRows(); + return pModel; + } + + template + static inline bool insert(qx::IxModel *pModel, U &item, int iRow) + { + if (!pModel) + { + qAssert(false); + return false; + } + type_collection *pListOfItems = static_cast(pModel->getCollection()); + long &idx = pModel->m_lManualInsertIndex; + type_primary_key key; + + type_ptr ptr = qx::model_view::detail::QxNestedModel_Helper::value>::clone(item); + qx::IxDataMember *pDataMemberId = pModel->m_pDataMemberId; + if (!pDataMemberId) + { + qAssert(false); + return false; + } + QVariant value = pDataMemberId->toVariant(&item); + if (!qx::trait::is_valid_primary_key(value)) + { + idx--; + value = QVariant(static_cast(idx)); + } + qx::cvt::from_variant(value, key); + pListOfItems->insert(iRow, key, ptr); + return true; + } + + static inline void synchronize(qx::IxModel *pModel, T &t) + { + if (!pModel) + { + qAssert(false); + return; + } + type_generic_container::clear(t); + type_collection *pListOfItems = static_cast(pModel->getCollection()); + + for (long l = 0; l < pListOfItems->count(); l++) + { + type_ptr ptr = pListOfItems->getByIndex(l); + if (!ptr) + { + continue; + } + type_item item = type_generic_container::createItem(); + type_data &item_val = item.value_qx(); + qx::model_view::detail::QxNestedModel_Helper::value>::synchronize(item_val, (*ptr)); + QVariant vKey = QVariant(static_cast(l)); + qx::cvt::from_variant(vKey, item.key()); + type_generic_container::insertItem(t, item); + } + } + + private: + template + static inline bool insertItem(qx::IxModel *pModel, U &item, int iRow) + { + return insertItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::insert(pModel, item, iRow); + } + + template + struct insertItem_Helper + { + static inline bool insert(qx::IxModel *pModel, U &item, int iRow) + { + return (item ? qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, (*item), iRow) : true); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(qx::IxModel *pModel, std::pair &item, int iRow) + { + return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(qx::IxModel *pModel, const std::pair &item, int iRow) + { + return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct insertItem_Helper, false> + { + static inline bool insert(qx::IxModel *pModel, QPair &item, int iRow) + { + return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(qx::IxModel *pModel, const QPair &item, int iRow) + { + return qx::model_view::detail::QxNestedModel_Container::insertItem(pModel, item.second, iRow); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct insertItem_Helper + { + enum + { + is_same_type = std::is_same::type_data, U>::value + }; + static bool insert(qx::IxModel *pModel, U &item, int iRow) + { + static_assert(is_same_type, "is_same_type"); + return qx::model_view::detail::QxNestedModel_Container::insert(pModel, item, iRow); + } + }; + }; + + template + struct QxNestedModel_Ptr + { + + static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t) + { + return (t ? create_Helper(pParent, idxParent, (*t)) : create_NullHelper(pParent, idxParent)); + } + + static inline void synchronize(qx::IxModel *pModel, T &t) + { + if (!t) + { + qx::trait::construct_ptr::get(t); + }; + if (t) + { + qx::model_view::sync_nested_model(pModel, (*t)); + } + } + + private: + template + static inline qx::IxModel *create_Helper(qx::IxModel *pParent, const QModelIndex &idxParent, U &u) + { + return qx::model_view::detail::QxNestedModel::create(pParent, idxParent, u); + } + + static inline qx::IxModel *create_NullHelper(qx::IxModel *pParent, const QModelIndex &idxParent) + { + M *pModelType = NULL; + Q_UNUSED(pModelType); + T t; + qx::trait::construct_ptr::get(t); + if (!t) + { + qAssert(false); + return NULL; + } + qx::IxModel *pModel = qx::model_view::create_nested_model_with_type(pParent, idxParent, (*t), pModelType); + if (pModel) + { + pModel->clear(); + } + qAssert(pModel != NULL); + return pModel; + } + }; + + template + struct QxNestedModel + { + + typedef typename std::conditional::value, qx::model_view::detail::QxNestedModel_Ptr, qx::model_view::detail::QxNestedModel_Generic>::type type_model_view_1; + typedef typename std::conditional::value, qx::model_view::detail::QxNestedModel_Ptr, type_model_view_1>::type type_model_view_2; + typedef typename std::conditional::value, qx::model_view::detail::QxNestedModel_Container, type_model_view_2>::type type_model_view_3; + + static inline qx::IxModel *create(qx::IxModel *pParent, const QModelIndex &idxParent, T &t) + { + return type_model_view_3::create(pParent, idxParent, t); + } + + static inline void synchronize(qx::IxModel *pModel, T &t) + { + type_model_view_3::synchronize(pModel, t); + } + }; + + } // namespace detail + } // namespace model_view +} // namespace qx + +namespace qx +{ + namespace model_view + { + + /*! + * \ingroup QxModelView + * \brief qx::model_view::create_nested_model is used by QxEntityEditor to manage complex data structure to work with relationships in QML views and Qt model/view architecture + * \param pParent Parent model, qx::model_view::create_nested_model creates a child model associated to this parent model (a NULL value means that the created model is a root model) + * \param idxParent Index parent model, qx::model_view::create_nested_model creates a child model indexed by this parent index model (an empty index means that the created model is a root model) + * \param t Item which contain all values exposed by the model to the views, t item can be a simple type, a pointer, a smart pointer, or a collection of items + */ + template + qx::IxModel *create_nested_model(qx::IxModel *pParent, const QModelIndex &idxParent, T &t) + { + return qx::model_view::detail::QxNestedModel::create(pParent, idxParent, t); + } + + template + qx::IxModel *create_nested_model_with_type(qx::IxModel *pParent, const QModelIndex &idxParent, T &t, M *pModelType) + { + Q_UNUSED(pModelType); + static_assert((std::is_base_of::value || std::is_same::value), "(std::is_base_of::value || std::is_same::value)"); + return qx::model_view::detail::QxNestedModel::create(pParent, idxParent, t); + } + + template + void sync_nested_model(qx::IxModel *pModel, T &t) + { + qx::model_view::detail::QxNestedModel::synchronize(pModel, t); + } + + } // namespace model_view +} // namespace qx + +#endif // _QX_NESTED_MODEL_H_ diff --git a/include/QxOrm.h b/include/QxOrm.h new file mode 100644 index 0000000..f863747 --- /dev/null +++ b/include/QxOrm.h @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** 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_ORM_H_ +#define _QX_ORM_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \defgroup QxCommon QxCommon : QxOrm library common tools and macros + * \defgroup QxCollection QxCollection : QxOrm library container (keep insertion order + quick access by index + quick access by key) + * \defgroup QxSingleton QxSingleton : QxOrm library thread-safe singleton pattern + * \defgroup QxFactory QxFactory : QxOrm library factory pattern used by introspection engine + * \defgroup QxDataMember QxDataMember : QxOrm library data member (or property) used by introspection engine + * \defgroup QxFunction QxFunction : QxOrm library function used by introspection engine + * \defgroup QxRegister QxRegister : QxOrm library register context used by introspection engine (class, function, property...) + * \defgroup QxSerialize QxSerialize : QxOrm library serialization engine based on 'boost::serialization' library + * \defgroup QxTraits QxTraits : QxOrm library traits (template metaprogramming) not available in 'boost::type_traits' library + * \defgroup QxDao QxDao : QxOrm library database communication used by persistence engine (ORM - Object Relational Mapping) + * \defgroup QxValidator QxValidator : QxOrm library validation engine using validator pattern + * \defgroup QxModelView QxModelView : All classes registered into QxOrm context can be used with Qt model/view architecture (Qt widgets and/or QML views) + * \defgroup QxRestApi QxRestApi : QxOrm library REST API to send requests in JSON format from external application, from web-site or from QML view + * \defgroup QxService QxService : QxOrm library services engine to provide easy and powerful way to create C++ application server (to transfer data over network) + * \defgroup QxHttpServer QxHttpServer : QxOrm library HTTP server (based on QxService module) : support SSL/TLS, persistent connection, deliver static files, REST API, etc... + * \defgroup QxCache QxCache : QxOrm library basic thread-safe cache feature to backup and restore any kind of objects (for example, object fetched from database) + * \defgroup QxConvert QxConvert : QxOrm library conversion tools to-from QString type and to-from QVariant type + * \defgroup QxExtras QxExtras : QxOrm library extra-tools (for example : enable std::optional for C++17 compilers, enable boost::optional feature without enabling all boost features) + * \defgroup QxMemLeak QxMemLeak : QxOrm library memory leak detection (by Wu Yongwei) + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef _QX_ENABLE_MONGODB +#include +#endif // _QX_ENABLE_MONGODB + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include +#include +#include + +#ifndef _QX_NO_JSON +#include +#include +#endif // _QX_NO_JSON + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _QX_ENABLE_QT_NETWORK +#include +#include +#include +#include +#include +#include +#include +#endif // _QX_ENABLE_QT_NETWORK + +#endif // _QX_ORM_H_ diff --git a/include/QxOrm_Impl.h b/include/QxOrm_Impl.h new file mode 100644 index 0000000..06624e6 --- /dev/null +++ b/include/QxOrm_Impl.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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_ORM_IMPL_H_ +#define _QX_ORM_IMPL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxOrm_Impl.h + * \author XDL Team + * \brief QxOrm_Impl.h file should be included in all *.cpp files which depend on QxOrm library if you are using QxMemLeak module or boost::serialization engine. Otherwise, include QxOrm_Impl.h file is optional (not required). + */ + +#include + +#endif // _QX_ORM_IMPL_H_ diff --git a/include/QxPrecompiled.h b/include/QxPrecompiled.h new file mode 100644 index 0000000..12dd6ed --- /dev/null +++ b/include/QxPrecompiled.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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_ORM_PRECOMPILED_HEADER_H_ +#define _QX_ORM_PRECOMPILED_HEADER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _MSC_VER +#if (_MSC_VER < 1800) // MSVC 2012 and below +#ifndef _VARIADIC_MAX +#define _VARIADIC_MAX 10 // to manage correctly std::tuple +#endif // _VARIADIC_MAX +#endif // (_MSC_VER < 1800) +#endif // _MSC_VER + +#ifdef _MSC_VER +#pragma warning(disable : 4503) /* -- Disable 4503 warning because of boost template -- */ +#pragma warning(disable : 4100) /* -- Disable warning 'unreferenced formal parameter' -- */ +#pragma warning(disable : 4996) +#pragma warning(disable : 4661) +#endif // _MSC_VER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4396) +#endif // _MSC_VER + +#ifndef _QX_ENABLE_BOOST +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define _QX_ENABLE_BOOST +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // _QX_ENABLE_BOOST + +#ifdef _QX_ENABLE_BOOST +#define BOOST_ALL_NO_LIB /* -- Disable auto-link feature provided by boost -- */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // _QX_ENABLE_BOOST + +#ifdef BOOST_DLLEXPORT +#undef BOOST_DLLEXPORT +#define BOOST_DLLEXPORT /* Nothing */ +#endif // BOOST_DLLEXPORT + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _MSC_VER +#include /* -- To avoid warning 4100 => header in precompiled header -- */ +#include +#include +#endif // _MSC_VER +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#include +#include + +#endif // _QX_ORM_PRECOMPILED_HEADER_H_ diff --git a/include/QxRegister/IxClass.h b/include/QxRegister/IxClass.h new file mode 100644 index 0000000..c039c52 --- /dev/null +++ b/include/QxRegister/IxClass.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 _IX_CLASS_H_ +#define _IX_CLASS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxClass.h + * \author XDL Team + * \ingroup QxRegister + * \brief Common interface for all classes registered into QxOrm context + */ + +#ifndef _QX_NO_RTTI +#include +#endif // _QX_NO_RTTI + +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + + class IxSqlRelation; + + /*! + * \ingroup QxRegister + * \brief qx::IxClass : common interface for all classes registered into QxOrm context + */ + class QX_DLL_EXPORT IxClass : public qx::QxPropertyBag + { + + private: + struct IxClassImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + protected: + IxClass(); + virtual ~IxClass() = 0; + + public: + QString getKey() const; + QString getName() const; + const char *getNamePtr() const; + QString getDescription() const; + long getVersion() const; + qx::dao::strategy::inheritance getDaoStrategy() const; + qx::QxSoftDelete getSoftDelete() const; + bool isFinalClass() const; + bool isDaoReadOnly() const; + bool isRegistered() const; + IxDataMemberX *getDataMemberX() const; + IxFunctionX *getFctMemberX() const; + IxFunctionX *getFctStaticX() const; + std::shared_ptr> getSqlRelationX(); + std::shared_ptr> getSqlDataMemberX(); + + void setKey(const QString &s); + void setName(const QString &s); + void setDescription(const QString &s); + void setDaoStrategy(qx::dao::strategy::inheritance e); + void setSoftDelete(const qx::QxSoftDelete &o); + void setDaoReadOnly(bool b); + void setVersion(long l); + + virtual bool isAbstract() const = 0; + virtual bool implementIxPersistable() const = 0; + virtual IxClass *getBaseClass() const = 0; + virtual IxValidatorX *getAllValidator(); + + IxDataMember *getId(bool bRecursive = false) const; + bool isKindOf(const QString &sClassName) const; + QString dumpClass() const; + +#ifndef _QX_NO_RTTI + virtual const std::type_info &typeInfo() const = 0; + bool isKindOf(const std::type_info &typeInfo) const; +#endif // _QX_NO_RTTI + + protected: + void updateClassX(); + void setRegistered(bool b); + void setFinalClass(bool b); + void setDataMemberX(IxDataMemberX *p); + void setFctMemberX(IxFunctionX *p); + void setFctStaticX(IxFunctionX *p); + IxValidatorX_ptr &getAllValidatorRef(); + }; + + typedef std::shared_ptr IxClass_ptr; + +} // namespace qx + +#endif // _IX_CLASS_H_ diff --git a/include/QxRegister/IxTypeInfo.h b/include/QxRegister/IxTypeInfo.h new file mode 100644 index 0000000..65ba9db --- /dev/null +++ b/include/QxRegister/IxTypeInfo.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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 _IX_TYPE_INFO_H_ +#define _IX_TYPE_INFO_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +namespace qx +{ + + class IxTypeInfo + { + + public: + IxTypeInfo() { ; } + virtual ~IxTypeInfo() { ; } + + virtual QString className() const = 0; + }; + +} // namespace qx + +#endif // _IX_TYPE_INFO_H_ diff --git a/include/QxRegister/QxClass.h b/include/QxRegister/QxClass.h new file mode 100644 index 0000000..d8d5c4d --- /dev/null +++ b/include/QxRegister/QxClass.h @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** 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_CLASS_H_ +#define _QX_CLASS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxClass.h + * \author XDL Team + * \ingroup QxRegister + * \brief Concrete class registered into QxOrm context + */ + +#include + +#include + +#include + +#include + +#include +#include +#include + +#include + +namespace qx +{ + + namespace trait + { + template + struct is_ix_persistable; + } // namespace trait + + /*! + * \ingroup QxRegister + * \brief qx::register_class(T & t) : specialize this template to register a class of type T into QxOrm context + */ + template + void register_class(T &t) + { + Q_UNUSED(t); + qAssert(false); + }; + + /*! + * \ingroup QxRegister + * \brief qx::QxClass : concrete class of type T registered into QxOrm context (this class is a singleton and is thread-safe) + */ + template + class QxClass : public IxClass, public QxSingleton> + { + + friend class QxSingleton>; + + public: + typedef typename qx::trait::get_primary_key::type type_primary_key; + typedef typename qx::trait::get_base_class::type type_base_class; + typedef IxFunction::type_any_params type_any_params; + + enum + { + is_valid_base_class = ((!std::is_same::value) && (std::is_base_of::value || std::is_same::value)) + }; + + protected: + QMutex m_oMutexClass; //!< Mutex -> 'QxClass' is thread-safe + + protected: + QxClass() : IxClass(), QxSingleton>(QString("qx::QxClass_") + qx::trait::get_class_name::get_xml_tag()) { init(); } + virtual ~QxClass() { ; } + + public: + QxDataMemberX *dataMemberX() const { return static_cast *>(this->getDataMemberX()); } + IxFunctionX *fctMemberX() const { return this->getFctMemberX(); } + IxFunctionX *fctStaticX() const { return this->getFctStaticX(); } + + IxDataMember *id(type_primary_key T::*pDataMemberId, const QString &sKey, long lVersion = 0); + IxDataMember *id(const QString &sKey, long lVersion); + IxDataMember *data(const QString &sKey, long lVersion); + + template + IxDataMember *data(V U::*pData, const QString &sKey, long lVersion = 0, bool bSerialize = true, bool bDao = true); + template + IxSqlRelation *relationOneToOne(V U::*pData, const QString &sKey, long lVersion = 0); + template + IxSqlRelation *relationManyToOne(V U::*pData, const QString &sKey, long lVersion = 0); + template + IxSqlRelation *relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion = 0); + template + IxSqlRelation *relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion = 0); + + template + IxDataMember *pimpl(V U::*pData, const QString &sKey = QString("_PIMPL_")); + template + IxDataMember *id(type_primary_key U::*pDataMemberId, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxDataMember *data(V U::*pData, const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl); + template + IxSqlRelation *relationOneToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationManyToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion, IxDataMember *pImpl); + template + IxSqlRelation *relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion, IxDataMember *pImpl); + + template + IxFunction *fct_0(const typename QxFunction_0::type_fct &fct, const QString &sKey); + template + IxFunction *fct_1(const typename QxFunction_1::type_fct &fct, const QString &sKey); + template + IxFunction *fct_2(const typename QxFunction_2::type_fct &fct, const QString &sKey); + template + IxFunction *fct_3(const typename QxFunction_3::type_fct &fct, const QString &sKey); + template + IxFunction *fct_4(const typename QxFunction_4::type_fct &fct, const QString &sKey); + template + IxFunction *fct_5(const typename QxFunction_5::type_fct &fct, const QString &sKey); + template + IxFunction *fct_6(const typename QxFunction_6::type_fct &fct, const QString &sKey); + template + IxFunction *fct_7(const typename QxFunction_7::type_fct &fct, const QString &sKey); + template + IxFunction *fct_8(const typename QxFunction_8::type_fct &fct, const QString &sKey); + template + IxFunction *fct_9(const typename QxFunction_9::type_fct &fct, const QString &sKey); + + template + IxFunction *fctStatic_0(const typename QxFunction_0::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_1(const typename QxFunction_1::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_2(const typename QxFunction_2::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_3(const typename QxFunction_3::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_4(const typename QxFunction_4::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_5(const typename QxFunction_5::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_6(const typename QxFunction_6::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_7(const typename QxFunction_7::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_8(const typename QxFunction_8::type_fct &fct, const QString &sKey); + template + IxFunction *fctStatic_9(const typename QxFunction_9::type_fct &fct, const QString &sKey); + + static qx_bool invoke(const QString &sKey, T *pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) + { + IxFunctionX *pFctX = QxClass::getSingleton()->fctMemberX(); + IxFunction_ptr pFct = ((pFctX && pFctX->exist(sKey)) ? pFctX->getByKey(sKey) : IxFunction_ptr()); + return invokeHelper::invoke(sKey, pOwner, params, ret, pFct); + } + static qx_bool invoke(const QString &sKey, T *pOwner, const type_any_params ¶ms, qx::any *ret = NULL) + { + IxFunctionX *pFctX = QxClass::getSingleton()->fctMemberX(); + IxFunction_ptr pFct = ((pFctX && pFctX->exist(sKey)) ? pFctX->getByKey(sKey) : IxFunction_ptr()); + return invokeHelper::invoke(sKey, pOwner, params, ret, pFct); + } + static qx_bool invokeStatic(const QString &sKey, const QString ¶ms = QString(), qx::any *ret = NULL) + { + IxFunctionX *pFctX = QxClass::getSingleton()->fctStaticX(); + IxFunction_ptr pFct = ((pFctX && pFctX->exist(sKey)) ? pFctX->getByKey(sKey) : IxFunction_ptr()); + return invokeHelper::invoke(sKey, params, ret, pFct); + } + static qx_bool invokeStatic(const QString &sKey, const type_any_params ¶ms, qx::any *ret = NULL) + { + IxFunctionX *pFctX = QxClass::getSingleton()->fctStaticX(); + IxFunction_ptr pFct = ((pFctX && pFctX->exist(sKey)) ? pFctX->getByKey(sKey) : IxFunction_ptr()); + return invokeHelper::invoke(sKey, params, ret, pFct); + } + + virtual bool isAbstract() const + { + return std::is_abstract::value; + } + + virtual bool implementIxPersistable() const + { + return implementIxPersistable_Helper::get(); + } + +#ifndef _QX_NO_RTTI + virtual const std::type_info &typeInfo() const + { + return typeid(T); + } +#endif // _QX_NO_RTTI + + virtual IxClass *getBaseClass() const + { + return (std::is_same::value ? NULL : QxClass::getSingleton()); + } + +#if _QX_SUPPORT_COVARIANT_RETURN_TYPE + virtual QxValidatorX *getAllValidator() + { + if (!this->getAllValidatorRef()) + { + this->getAllValidatorRef().reset(new QxValidatorX()); + IxClass::getAllValidator(); + } + return static_cast *>(this->getAllValidatorRef().get()); + } +#else // _QX_SUPPORT_COVARIANT_RETURN_TYPE + virtual IxValidatorX *getAllValidator() + { + if (!this->getAllValidatorRef()) + { + this->getAllValidatorRef().reset(new QxValidatorX()); + IxClass::getAllValidator(); + } + return this->getAllValidatorRef().get(); + } +#endif // _QX_SUPPORT_COVARIANT_RETURN_TYPE + + private: + void init(); + IxFunction *insertFct(IxFunction_ptr pFct, const QString &sKey); + IxFunction *insertFctStatic(IxFunction_ptr pFct, const QString &sKey); + + void registerClass() { qx::register_class>(*this); } + + void beforeRegisterClass() + { + static_assert(is_valid_base_class, "is_valid_base_class"); + QMutexLocker locker(&m_oMutexClass); + QxClass::getSingleton(); + bool bNeedReg = (!this->isRegistered()); + this->setRegistered(true); + if (bNeedReg) + { + registerClass(); + } + } + + template + struct invokeHelper + { + static qx_bool invoke(const QString &sKey, U *pOwner, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : QxClass::invoke(sKey, static_cast(pOwner), params, ret)); + } + + static qx_bool invoke(const QString &sKey, U *pOwner, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : QxClass::invoke(sKey, static_cast(pOwner), params, ret)); + } + + static qx_bool invoke(const QString &sKey, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + return (pFct ? pFct->invoke(params, ret) : QxClass::invokeStatic(sKey, params, ret)); + } + + static qx_bool invoke(const QString &sKey, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + return (pFct ? pFct->invoke(params, ret) : QxClass::invokeStatic(sKey, params, ret)); + } + }; + + template + struct invokeHelper + { + static qx_bool invoke(const QString &sKey, U *pOwner, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : qx_bool(false)); + } + + static qx_bool invoke(const QString &sKey, U *pOwner, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : qx_bool(false)); + } + + static qx_bool invoke(const QString &sKey, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + return (pFct ? pFct->invoke(params, ret) : qx_bool(false)); + } + + static qx_bool invoke(const QString &sKey, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + return (pFct ? pFct->invoke(params, ret) : qx_bool(false)); + } + }; + + template + struct invokeHelper + { + static qx_bool invoke(const QString &sKey, qx::trait::no_base_class_defined *pOwner, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(pOwner); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, qx::trait::no_base_class_defined *pOwner, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(pOwner); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + }; + + template + struct invokeHelper + { + static qx_bool invoke(const QString &sKey, QObject *pOwner, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(pOwner); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, QObject *pOwner, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(pOwner); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, const QString ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + + static qx_bool invoke(const QString &sKey, const type_any_params ¶ms, qx::any *ret, IxFunction_ptr pFct) + { + Q_UNUSED(sKey); + Q_UNUSED(params); + Q_UNUSED(ret); + Q_UNUSED(pFct); + return qx_bool(false); + } + }; + + private: + template + struct implementIxPersistable_Helper + { + static bool get() { return qx::trait::is_ix_persistable::value; } + }; + + template + struct implementIxPersistable_Helper + { + static bool get() { return false; } + }; + + template + struct implementIxPersistable_Helper + { + static bool get() { return false; } + }; + }; + +} // namespace qx + +#include "../../inl/QxRegister/QxClass.inl" + +#endif // _QX_CLASS_H_ diff --git a/include/QxRegister/QxClassName.h b/include/QxRegister/QxClassName.h new file mode 100644 index 0000000..b9ee2d2 --- /dev/null +++ b/include/QxRegister/QxClassName.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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_CLASS_NAME_H_ +#define _QX_CLASS_NAME_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxClassName.h + * \author XDL Team + * \ingroup QxRegister + * \brief Provide a class helper to retrieve the class name under const char * format + */ + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxRegister + * \brief qx::QxClassName : class helper to retrieve the class name of type T under const char * format + */ + template + class QxClassName + { + + public: + static inline const char *get() { return qxGetClassName::value, 0>::get(); } + static inline const char *get_xml_tag() { return qxGetClassName::value, 0>::get_xml_tag(); } + + private: + template + struct qxGetClassName + { + static inline const char *get() { return QX_GET_CLASS_NAME_WITH_TYPENAME(T); } + static inline const char *get_xml_tag() { return QX_GET_CLASS_NAME_XML_TAG_WITH_TYPENAME(T); } + }; + + template + struct qxGetClassName + { + static inline const char *get() { return qx::QxClass::getSingleton()->getNamePtr(); } + static inline const char *get_xml_tag() { return qx::QxClass::getSingleton()->getNamePtr(); } + }; + }; + +} // namespace qx + +#endif // _QX_CLASS_NAME_H_ diff --git a/include/QxRegister/QxClassX.h b/include/QxRegister/QxClassX.h new file mode 100644 index 0000000..964c192 --- /dev/null +++ b/include/QxRegister/QxClassX.h @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** 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_CLASS_X_H_ +#define _QX_CLASS_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxClassX.h + * \author XDL Team + * \ingroup QxRegister + * \brief List of all classes registered into QxOrm context + */ + +#include + +#include + +#include + +#include + +#include +#include + +namespace qx +{ + + /*! + * \ingroup QxRegister + * \brief qx::QxClassX : list of all classes registered into QxOrm context (this container is a singleton) + */ + class QX_DLL_EXPORT QxClassX : public QxSingleton + { + + friend class QxSingleton; + friend class IxClass; + + public: + typedef IxFunction::type_any_params type_any_params; + typedef std::function type_fct_save_qvariant_usertype; + typedef std::function type_fct_load_qvariant_usertype; + + protected: + QxCollection m_lstClass; //!< Collection of classes registered into QxOrm context + QHash m_lstSqlTypeByClassName; //!< List of SQL types by class name + QHash m_lstValidatorMessage; //!< List of validator message when an invalid value is detected + type_fct_save_qvariant_usertype m_fctSaveQVariantUserType; //!< Serialization of QVariant UserType => function to save a QVariant UserType (cf. QxSerialize_QVariant.cpp file) + type_fct_load_qvariant_usertype m_fctLoadQVariantUserType; //!< Serialization of QVariant UserType => function to load a QVariant UserType (cf. QxSerialize_QVariant.cpp file) + + private: + QxClassX(); + virtual ~QxClassX(); + + QxCollection *getAll(); + IxClass *get(const QString &sKey) const; + bool exist(const QString &sKey) const; + bool insert(const QString &sKey, IxClass *pClass); + bool remove(const QString &sKey); + void clear(); + void initSqlTypeByClassName(); + void initValidatorMessage(); + +#ifndef _QX_NO_RTTI + const std::type_info &typeInfo(const QString &sKey) const; +#endif // _QX_NO_RTTI + + public: + static qx::any create(const QString &sKey); + static IxClass *getClass(const QString &sKey); + static IxDataMemberX *getDataMemberX(const QString &sKey); + static IxFunctionX *getFctMemberX(const QString &sKey); + static IxFunctionX *getFctStaticX(const QString &sKey); + static IxDataMember *getDataMember(const QString &sClassKey, const QString &sDataKey, bool bRecursive = true); + static IxFunction *getFctMember(const QString &sClassKey, const QString &sFctKey, bool bRecursive = true); + static IxFunction *getFctStatic(const QString &sClassKey, const QString &sFctKey, bool bRecursive = true); + static bool implementIxPersistable(const QString &sKey, bool bTraceIfFalse = true); + + static QxCollection *getAllClasses(); + static void registerAllClasses(bool bInitAllRelations = true, bool bInitValidator = true); + static QString dumpAllClasses(); + static QString dumpSqlSchema(); + + static QHash *getAllValidatorMessage() { return (&QxClassX::getSingleton()->m_lstValidatorMessage); } + static QHash *getAllSqlTypeByClassName() { return (&QxClassX::getSingleton()->m_lstSqlTypeByClassName); } + static QString getSqlTypeByClassName(const QString &sClassName) { return QxClassX::getAllSqlTypeByClassName()->value(sClassName); } + +#ifndef _QX_NO_RTTI + static const std::type_info &getTypeInfo(const QString &sClassName) { return QxClassX::getSingleton()->typeInfo(sClassName); } +#endif // _QX_NO_RTTI + + static type_fct_save_qvariant_usertype getFctSaveQVariantUserType() { return QxClassX::getSingleton()->m_fctSaveQVariantUserType; } + static type_fct_load_qvariant_usertype getFctLoadQVariantUserType() { return QxClassX::getSingleton()->m_fctLoadQVariantUserType; } + static void setFctSaveQVariantUserType(type_fct_save_qvariant_usertype fct) { QxClassX::getSingleton()->m_fctSaveQVariantUserType = fct; } + static void setFctLoadQVariantUserType(type_fct_load_qvariant_usertype fct) { QxClassX::getSingleton()->m_fctLoadQVariantUserType = fct; } + + template + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) + { + typedef typename std::conditional::value, QxClassX::invoke_ptr, QxClassX::invoke_default>::type type_invoke_1; + typedef typename std::conditional::value, QxClassX::invoke_ptr, type_invoke_1>::type type_invoke_2; + return type_invoke_2::invoke(sClassKey, sFctKey, pOwner, params, ret); + } + + template + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const type_any_params ¶ms, qx::any *ret = NULL) + { + typedef typename std::conditional::value, QxClassX::invoke_ptr, QxClassX::invoke_default>::type type_invoke_1; + typedef typename std::conditional::value, QxClassX::invoke_ptr, type_invoke_1>::type type_invoke_2; + return type_invoke_2::invoke(sClassKey, sFctKey, pOwner, params, ret); + } + + static qx_bool invokeStatic(const QString &sClassKey, const QString &sFctKey, const QString ¶ms = QString(), qx::any *ret = NULL); + static qx_bool invokeStatic(const QString &sClassKey, const QString &sFctKey, const type_any_params ¶ms, qx::any *ret = NULL); + + private: + template + struct invoke_ptr + { + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) + { + return QxClassX::invokeVoidPtr(sClassKey, sFctKey, static_cast(&(*pOwner)), params, ret); + } + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const type_any_params ¶ms, qx::any *ret = NULL) + { + return QxClassX::invokeVoidPtr(sClassKey, sFctKey, static_cast(&(*pOwner)), params, ret); + } + }; + + template + struct invoke_default + { + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const QString ¶ms = QString(), qx::any *ret = NULL) + { + return QxClassX::invokeVoidPtr(sClassKey, sFctKey, static_cast(&pOwner), params, ret); + } + static inline qx_bool invoke(const QString &sClassKey, const QString &sFctKey, U &pOwner, const type_any_params ¶ms, qx::any *ret = NULL) + { + return QxClassX::invokeVoidPtr(sClassKey, sFctKey, static_cast(&pOwner), params, ret); + } + }; + + static qx_bool invokeVoidPtr(const QString &sClassKey, const QString &sFctKey, void *pOwner, const QString ¶ms = QString(), qx::any *ret = NULL); + static qx_bool invokeVoidPtr(const QString &sClassKey, const QString &sFctKey, void *pOwner, const type_any_params ¶ms, qx::any *ret = NULL); + + static bool isValid_DataMember(IxDataMember *p); + static bool isValid_SqlRelation(IxDataMember *p); + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClassX) + +#endif // _QX_CLASS_X_H_ diff --git a/include/QxRegister/QxRegister.h b/include/QxRegister/QxRegister.h new file mode 100644 index 0000000..0a03aaa --- /dev/null +++ b/include/QxRegister/QxRegister.h @@ -0,0 +1,517 @@ +/**************************************************************************** +** +** 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_REGISTER_H_ +#define _QX_REGISTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxRegister.h + * \author XDL Team + * \ingroup QxRegister + * \brief Provide macros to register a class into QxOrm context + */ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4094) +#endif // _MSC_VER + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#define QX_REGISTER_CLASS_MAPPING_FCT_HPP(dllImportExport, className) \ + namespace qx \ + { \ + template <> \ + dllImportExport void register_class(QxClass &t) QX_USED; \ + } + +#define QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(dllImportExport, className) \ + dllImportExport QDataStream &operator<<(QDataStream &stream, const className &t) QX_USED; \ + dllImportExport QDataStream &operator>>(QDataStream &stream, className &t) QX_USED; + +#define QX_REGISTER_SERIALIZE_QDATASTREAM_CPP(className) \ + QDataStream &operator<<(QDataStream &stream, const className &t) \ + { \ + return qx::QxSerializeRegistered::save(stream, t); \ + } \ + QDataStream &operator>>(QDataStream &stream, className &t) \ + { \ + return qx::QxSerializeRegistered::load(stream, t); \ + } + +#define QX_REGISTER_CLASS_MAPPING_FCT_EMPTY_CPP(className) \ + namespace qx \ + { \ + template <> \ + void register_class(QxClass &t) { Q_UNUSED(t); } \ + } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(Archive, className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + inline void serialize(Archive &ar, className &t, const unsigned int file_version) \ + { \ + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered< className >::value"); \ + typedef std::conditional, qx::serialization::detail::loader>::type type_invoker; \ + type_invoker::invoke(ar, t, file_version); \ + } \ + } \ + } // namespace boost::serialization +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, Archive, className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + dllImportExport void serialize(Archive &ar, className &t, const unsigned int file_version) QX_USED; \ + } \ + } // namespace boost::serialization +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(Archive, className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + inline void serialize(Archive &ar, className &t, const unsigned int file_version) \ + { \ + Q_UNUSED(ar); \ + Q_UNUSED(t); \ + Q_UNUSED(file_version); \ + } \ + } \ + } // namespace boost::serialization +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_ARCHIVE_TEMPLATE_HPP(className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + template \ + void serialize(Archive &ar, className &t, const unsigned int file_version); \ + } \ + } // namespace boost::serialization +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::polymorphic_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_binary_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_binary_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_text_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_text_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_xml_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::polymorphic_xml_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::binary_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::text_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::text_iarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_EMPTY_CPP(boost::archive::xml_iarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::polymorphic_iarchive, className) \ + QX_SERIALIZE_ARCHIVE_TEMPLATE_HPP(className) +#else // _QX_SERIALIZE_POLYMORPHIC +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_POLYMORPHIC_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_POLYMORPHIC_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_POLYMORPHIC +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::binary_iarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::binary_iarchive, className) +#else // _QX_SERIALIZE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_TEXT +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_TEXT_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::text_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::text_iarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::text_oarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::text_iarchive, className) +#else // _QX_SERIALIZE_TEXT +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_TEXT_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_TEXT_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_XML +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_XML_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::xml_iarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::xml_iarchive, className) +#else // _QX_SERIALIZE_XML +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_XML_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_XML_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_PORTABLE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(eos::portable_oarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(eos::portable_iarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, eos::portable_oarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, eos::portable_iarchive, className) +#else // _QX_SERIALIZE_PORTABLE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_PORTABLE_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_PORTABLE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_WIDE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::binary_wiarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::binary_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_BINARY +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_WIDE_TEXT +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::text_woarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::text_wiarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::text_woarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::text_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_TEXT +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_TEXT_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_TEXT_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_TEXT +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_WIDE_XML +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_XML_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_IMPLEMENT_ARCHIVE_CPP(boost::archive::xml_wiarchive, className) +// --- +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_ARCHIVE_HPP(dllImportExport, boost::archive::xml_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_XML +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_XML_CPP(className) /* Nothing */ +#define QX_SERIALIZE_LIST_ARCHIVE_WIDE_XML_HPP(dllImportExport, className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_XML +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_TEXT_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_XML_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_WIDE_XML_CPP(className) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_SERIALIZE_LIST_ARCHIVE_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_LIST_ARCHIVE_WIDE_XML_HPP(dllImportExport, className) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_WRITE_BOOST_CLASS_EXPORT_IN_HPP_FILE +#define QX_BOOST_CLASS_EXPORT_HPP(className) BOOST_CLASS_EXPORT_GUID(className, #className) +#else +#define QX_BOOST_CLASS_EXPORT_HPP(className) /* Nothing */ +#endif // _QX_WRITE_BOOST_CLASS_EXPORT_IN_HPP_FILE +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_WRITE_BOOST_CLASS_EXPORT_IN_CPP_FILE +#define QX_BOOST_CLASS_EXPORT_CPP(className) BOOST_CLASS_EXPORT_GUID(className, #className) +#else +#define QX_BOOST_CLASS_EXPORT_CPP(className) /* Nothing */ +#endif // _QX_WRITE_BOOST_CLASS_EXPORT_IN_CPP_FILE +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_FRIEND_CLASS(className) \ + template \ + friend void qx::register_class(T &t); + +#define QX_DLL_EXPORT_TEMPLATE_QX_CLASS_HPP(className) \ + QX_DLL_EXPORT_TEMPLATE_HPP(class, qx::QxDataMemberX) \ + QX_DLL_EXPORT_TEMPLATE_HPP(class, qx::QxSingleton>) \ + QX_DLL_EXPORT_TEMPLATE_HPP(class, qx::QxClass) \ + QX_DLL_EXPORT_TEMPLATE_HPP(class, qx::QxSingleton>) + +#define QX_DLL_EXPORT_TEMPLATE_QX_CLASS_CPP(className) \ + QX_DLL_EXPORT_TEMPLATE_CPP(class, qx::QxDataMemberX) \ + QX_DLL_EXPORT_TEMPLATE_CPP(class, qx::QxSingleton>) \ + QX_DLL_EXPORT_TEMPLATE_CPP(class, qx::QxClass) \ + QX_DLL_EXPORT_TEMPLATE_CPP(class, qx::QxSingleton>) + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_SET_REGISTERED(className) \ + QX_REGISTER_CLASS_NAME(className) \ + QX_REGISTER_BASE_CLASS(className, baseClass) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_HPP(className, classNameFormatted) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME(className, classNameFormatted) \ + QX_BOOST_CLASS_EXPORT_HPP(className) \ + QX_CLASS_VERSION(className, version) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_SET_REGISTERED(className) \ + QX_REGISTER_CLASS_NAME(className) \ + QX_REGISTER_BASE_CLASS(className, baseClass) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_HPP(className, classNameFormatted) \ + QX_CLASS_VERSION(className, version) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_HPP(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, className) + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_BOOST_CLASS_EXPORT_CPP(className) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_SERIALIZE_IMPLEMENT_LIST_ARCHIVE_CPP(className) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_CPP(className) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, className) + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _MSC_VER +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_SERIALIZE_LIST_ARCHIVE_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_EXPORT_HELPER, className) +// --- +#define QX_REGISTER_HPP_EXPORT_DLL(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, className) +#else // _MSC_VER +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_HPP(className) \ + QX_BOOST_EXPORT_SERIALIZATION_HPP(className) \ + QX_SERIALIZE_LIST_ARCHIVE_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_EXPORT_HELPER, className) +// --- +#define QX_REGISTER_HPP_EXPORT_DLL(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, className) +#endif // _MSC_VER + +#else // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _MSC_VER +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_EXPORT_HELPER, className) +// --- +#define QX_REGISTER_HPP_EXPORT_DLL(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, className) +#else // _MSC_VER +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_HPP(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_EXPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_EXPORT_HELPER, className) +// --- +#define QX_REGISTER_HPP_EXPORT_DLL(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL(className, baseClass, version, className) +#endif // _MSC_VER + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_HPP(className) \ + QX_BOOST_EXPORT_SERIALIZATION_HPP(className) \ + QX_SERIALIZE_LIST_ARCHIVE_HPP(QX_DLL_IMPORT_HELPER, className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_IMPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_IMPORT_HELPER, className) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL(className, baseClass, version, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP(className, baseClass, version, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_HPP(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(QX_DLL_IMPORT_HELPER, className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_HPP(QX_DLL_IMPORT_HELPER, className) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_HPP_IMPORT_DLL(className, baseClass, version) \ + QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL(className, baseClass, version, className) + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL(className, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_CPP(className) \ + QX_BOOST_EXPORT_SERIALIZATION_CPP(className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_CPP(className) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL(className, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_CPP(className) \ + QX_REGISTER_SERIALIZE_QDATASTREAM_CPP(className) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_CPP_EXPORT_DLL(className) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL(className, className) + +#ifdef _MSC_VER +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL(className, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) +// --- +#define QX_REGISTER_CPP_IMPORT_DLL(className) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL(className, className) +#else // _MSC_VER +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL(className, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_CPP(className) \ + QX_BOOST_EXPORT_SERIALIZATION_CPP(className) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL(className, classNameFormatted) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + QX_DLL_EXPORT_TEMPLATE_QX_CLASS_CPP(className) +#endif // _QX_ENABLE_BOOST_SERIALIZATION +// --- +#define QX_REGISTER_CPP_IMPORT_DLL(className) \ + QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL(className, className) +#endif // _MSC_VER + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_ABSTRACT_CLASS(className) \ + BOOST_SERIALIZATION_ASSUME_ABSTRACT(className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + template \ + inline void load_construct_data(Archive &ar, className *t, const unsigned int file_version) \ + { \ + Q_UNUSED(ar); \ + Q_UNUSED(t); \ + Q_UNUSED(file_version); \ + } \ + } \ + } // namespace boost::serialization +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_REGISTER_ABSTRACT_CLASS(className) /* Nothing */ +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +/* -- Create your macro (in your precompiled header) replacing "MY_DLL" +#ifdef _BUILDING_MY_DLL +#define QX_REGISTER_HPP_MY_DLL QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_MY_DLL QX_REGISTER_CPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_MY_DLL QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_MY_DLL QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL +#else +#define QX_REGISTER_HPP_MY_DLL QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_MY_DLL QX_REGISTER_CPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_MY_DLL QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_MY_DLL QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL +#endif // _BUILDING_MY_DLL +*/ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_REGISTER_H_ diff --git a/include/QxRegister/QxRegisterInternalHelper.h b/include/QxRegister/QxRegisterInternalHelper.h new file mode 100644 index 0000000..db027f0 --- /dev/null +++ b/include/QxRegister/QxRegisterInternalHelper.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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_REGISTER_INTERNAL_HELPER_H_ +#define _QX_REGISTER_INTERNAL_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_INTERNAL_HELPER_HPP(dllImportExport, className, version) \ + QX_CLASS_VERSION(className, version) \ + QX_REGISTER_CLASS_NAME(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(dllImportExport, className) \ + QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(className) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER(className) + +#define QX_REGISTER_INTERNAL_HELPER_START_FILE_CPP(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_EMPTY_CPP(className) \ + QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(className) + +#define QX_REGISTER_INTERNAL_HELPER_END_FILE_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(className) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER_CPP(className) + +#else // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_REGISTER_INTERNAL_HELPER_HPP(dllImportExport, className, version) \ + QX_CLASS_VERSION(className, version) \ + QX_REGISTER_CLASS_NAME(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_HPP(dllImportExport, className) + +#define QX_REGISTER_INTERNAL_HELPER_START_FILE_CPP(className) \ + QX_REGISTER_CLASS_MAPPING_FCT_EMPTY_CPP(className) + +#define QX_REGISTER_INTERNAL_HELPER_END_FILE_CPP(className) /* Nothing */ + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#endif // _QX_REGISTER_INTERNAL_HELPER_H_ diff --git a/include/QxRegister/QxRegisterQtProperty.h b/include/QxRegister/QxRegisterQtProperty.h new file mode 100644 index 0000000..1b0da8a --- /dev/null +++ b/include/QxRegister/QxRegisterQtProperty.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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_REGISTER_QT_META_PROPERTY_H_ +#define _QX_REGISTER_QT_META_PROPERTY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxRegisterQtProperty.h + * \author XDL Team + * \ingroup QxRegister + * \brief Register automatically Qt meta-property defined with Q_PROPERTY() macro into QxOrm context + */ + +#include +#include + +#include + +#include + +#define QX_REGISTER_ALL_QT_PROPERTIES(className, propertyId) \ + namespace qx \ + { \ + template <> \ + void register_class(QxClass &t) \ + { \ + qx::register_all_qt_properties(t, propertyId); \ + } \ + } + +namespace qx +{ + + template + void register_all_qt_properties(QxClass &t, const QString &sPropertyId) + { + static_assert(qx::trait::qt_meta_object::is_valid, "qx::trait::qt_meta_object::is_valid"); + + const QMetaObject *pMetaObject = qx::trait::qt_meta_object::get(); + int iIndexId = (sPropertyId.isEmpty() ? -2 : (pMetaObject ? pMetaObject->indexOfProperty(qPrintable(sPropertyId)) : -1)); + if (!pMetaObject || (iIndexId == -1)) + { + qAssert(false); + return; + } + + for (int i = pMetaObject->propertyOffset(); i < pMetaObject->propertyCount(); i++) + { + QMetaProperty prop = pMetaObject->property(i); + if (i == iIndexId) + { + t.id(sPropertyId, 0); + } + else + { + t.data(prop.name(), 0); + } + } + } + +} // namespace qx + +#endif // _QX_REGISTER_QT_META_PROPERTY_H_ diff --git a/include/QxRegister/QxVersion.h b/include/QxRegister/QxVersion.h new file mode 100644 index 0000000..ea7c563 --- /dev/null +++ b/include/QxRegister/QxVersion.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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_VERSION_H_ +#define _QX_VERSION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxVersion.h + * \author XDL Team + * \ingroup QxRegister + * \brief Register a version number per class + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#define QX_CLASS_VERSION(C, V) BOOST_CLASS_VERSION(C, V) + +#else // _QX_ENABLE_BOOST_SERIALIZATION + +namespace qx +{ + + template + struct version + { + enum + { + value = 0 + }; + }; + +} // namespace qx + +#define QX_CLASS_VERSION(C, V) \ + namespace qx \ + { \ + template <> \ + struct version \ + { \ + enum \ + { \ + value = V \ + }; \ + }; \ + } + +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // _QX_VERSION_H_ diff --git a/include/QxRestApi/QxRestApi.h b/include/QxRestApi/QxRestApi.h new file mode 100644 index 0000000..8bbb75c --- /dev/null +++ b/include/QxRestApi/QxRestApi.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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_REST_API_H_ +#define _QX_REST_API_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxRestApi.h + * \author XDL Team + * \ingroup QxRestApi + * \brief Provide a REST API to send requests in JSON format from external application, from web-site or from QML view (https://www.qxorm.com/qxorm_en/manual.html#manual_97) + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#ifndef _QX_NO_JSON +#include +#include +#include +#include +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxRestApi + * \brief qx::QxRestApi : provide a REST API to send requests in JSON format from external application, from web-site or from QML view (https://www.qxorm.com/qxorm_en/manual.html#manual_97) + */ + class QX_DLL_EXPORT QxRestApi : public QObject + { + + Q_OBJECT + + private: + struct QxRestApiImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + public: + QxRestApi(QObject *parent = NULL); + virtual ~QxRestApi(); + + Q_INVOKABLE QString processRequest(const QString &request); + Q_INVOKABLE void clearAll(); + + Q_INVOKABLE QString getErrorDesc() const; + Q_INVOKABLE int getErrorCode() const; + QSqlError getError() const; + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) +#if (QT_VERSION >= 0x050300) // Double check here to support Qt4 (which doesn't manage macro expansion in the moc process) + Q_INVOKABLE QString getNativeErrorCode() const; +#endif // (QT_VERSION >= 0x050300) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + + Q_INVOKABLE void setEntity(const QString &entity); + Q_INVOKABLE void setAction(const QString &action); + Q_INVOKABLE void setFunction(const QString &fct); + Q_INVOKABLE void setColumns(const QStringList &columns); + Q_INVOKABLE void setRelations(const QStringList &relations); + Q_INVOKABLE void setOutputFormat(const QStringList &outputFormat); + Q_INVOKABLE void setDatabase(const QString &database); + Q_INVOKABLE void setQuery(const QString &query); + Q_INVOKABLE void setData(const QString &data); + Q_INVOKABLE void setUseExecBatch(bool useExecBatch); + +#ifndef _QX_NO_JSON + QJsonValue processRequest(const QJsonValue &request); + void setData(const QJsonValue &data); +#endif // _QX_NO_JSON + }; + +} // namespace qx + +#endif // _QX_REST_API_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QFlags.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QFlags.h new file mode 100644 index 0000000..b8e5220 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QFlags.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QFLAGS_H_ +#define _QX_SERIALIZE_QDATASTREAM_QFLAGS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QFlags.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QFlags + */ + +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) + +template +QDataStream &operator<<(QDataStream &stream, const QFlags &t) +{ + qint64 iFlags = static_cast(t); + stream << iFlags; + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, QFlags &t) +{ + qint64 iFlags = 0; + stream >> iFlags; + t = QFlags(QFlag(static_cast(iFlags))); + return stream; +} + +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) +#endif // _QX_SERIALIZE_QDATASTREAM_QFLAGS_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.h new file mode 100644 index 0000000..bec3752 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QOBJECT_H_ +#define _QX_SERIALIZE_QDATASTREAM_QOBJECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QObject.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QObject (serialize dynamic properties) + */ + +#include +#include + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const QObject &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, QObject &t) QX_USED; + +#endif // _QX_SERIALIZE_QDATASTREAM_QOBJECT_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QScopedPointer.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QScopedPointer.h new file mode 100644 index 0000000..baab071 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QScopedPointer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#ifndef _QX_SERIALIZE_QDATASTREAM_QSCOPEDPOINTER_H_ +#define _QX_SERIALIZE_QDATASTREAM_QSCOPEDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QScopedPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QScopedPointer + */ + +#include +#include + +template +QDataStream &operator<<(QDataStream &stream, const QScopedPointer &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, QScopedPointer &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t.reset(new T()); + stream >> (*t); + } + else + { + t.reset(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_QSCOPEDPOINTER_H_ +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSharedPointer.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSharedPointer.h new file mode 100644 index 0000000..619e665 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSharedPointer.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QSHAREDPOINTER_H_ +#define _QX_SERIALIZE_QDATASTREAM_QSHAREDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QSharedPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QSharedPointer + */ + +#include +#include + +template +QDataStream &operator<<(QDataStream &stream, const QSharedPointer &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, QSharedPointer &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t = QSharedPointer(new T()); + stream >> (*t); + } + else + { + t = QSharedPointer(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_QSHAREDPOINTER_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.h new file mode 100644 index 0000000..80cd2b5 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QSQLERROR_H_ +#define _QX_SERIALIZE_QDATASTREAM_QSQLERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QSqlError.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QSqlError + */ + +#include + +#include + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const QSqlError &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, QSqlError &t) QX_USED; + +#endif // _QX_SERIALIZE_QDATASTREAM_QSQLERROR_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_QWeakPointer.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QWeakPointer.h new file mode 100644 index 0000000..364d534 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_QWeakPointer.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QWEAKPOINTER_H_ +#define _QX_SERIALIZE_QDATASTREAM_QWEAKPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_QWeakPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type QWeakPointer + */ + +#include +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const QWeakPointer &t) +{ + QSharedPointer ptr = t.toStrongRef(); + stream << ptr; + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, QWeakPointer &t) +{ + QSharedPointer ptr; + stream >> ptr; + t = QWeakPointer(ptr); + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_QWEAKPOINTER_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_all_include.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_all_include.h new file mode 100644 index 0000000..ac192c0 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_all_include.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_ALL_INCLUDE_H_ +#define _QX_SERIALIZE_QDATASTREAM_ALL_INCLUDE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_all_include.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Include all Qt QDataStream serialization method (save/load) provided by QxOrm library + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _QX_SERIALIZE_QDATASTREAM_ALL_INCLUDE_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_optional.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_optional.h new file mode 100644 index 0000000..1b16f55 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_optional.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_OPTIONAL_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_OPTIONAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_optional.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::optional + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::optional &t) +{ + qint8 iHasData = (t ? 1 : 0); + stream << iHasData; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::optional &t) +{ + qint8 iHasData = 0; + stream >> iHasData; + if (iHasData) + { + t = T(); + stream >> (*t); + } + else + { + t = boost::none; + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_OPTIONAL_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_scoped_ptr.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_scoped_ptr.h new file mode 100644 index 0000000..c95c8bb --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_scoped_ptr.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_SCOPED_PTR_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_SCOPED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_scoped_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::scoped_ptr + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::scoped_ptr &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::scoped_ptr &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t.reset(new T()); + stream >> (*t); + } + else + { + t.reset(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_SCOPED_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_shared_ptr.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_shared_ptr.h new file mode 100644 index 0000000..c0246dc --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_shared_ptr.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_SHARED_PTR_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_shared_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::shared_ptr + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::shared_ptr &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::shared_ptr &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t.reset(new T()); + stream >> (*t); + } + else + { + t.reset(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_SHARED_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_tuple.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_tuple.h new file mode 100644 index 0000000..af2470c --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_tuple.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_TUPLE_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_tuple.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::tuple + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + stream << boost::get<5>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + stream << boost::get<5>(t); + stream << boost::get<6>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + stream << boost::get<5>(t); + stream << boost::get<6>(t); + stream << boost::get<7>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + stream << boost::get<5>(t); + stream << boost::get<6>(t); + stream << boost::get<7>(t); + stream << boost::get<8>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::tuple &t) +{ + stream << boost::get<0>(t); + stream << boost::get<1>(t); + stream << boost::get<2>(t); + stream << boost::get<3>(t); + stream << boost::get<4>(t); + stream << boost::get<5>(t); + stream << boost::get<6>(t); + stream << boost::get<7>(t); + stream << boost::get<8>(t); + stream << boost::get<9>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + stream >> boost::get<5>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + stream >> boost::get<5>(t); + stream >> boost::get<6>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + stream >> boost::get<5>(t); + stream >> boost::get<6>(t); + stream >> boost::get<7>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + stream >> boost::get<5>(t); + stream >> boost::get<6>(t); + stream >> boost::get<7>(t); + stream >> boost::get<8>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::tuple &t) +{ + stream >> boost::get<0>(t); + stream >> boost::get<1>(t); + stream >> boost::get<2>(t); + stream >> boost::get<3>(t); + stream >> boost::get<4>(t); + stream >> boost::get<5>(t); + stream >> boost::get<6>(t); + stream >> boost::get<7>(t); + stream >> boost::get<8>(t); + stream >> boost::get<9>(t); + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_TUPLE_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_map.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_map.h new file mode 100644 index 0000000..4521202 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_map.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_MAP_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_unordered_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::unordered_map and boost::unordered_multimap + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::unordered_map &t) +{ + typedef typename boost::unordered_map::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << itr->first; + stream << itr->second; + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::unordered_map &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + + for (quint64 i = 0; i < uiSize; ++i) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(std::make_pair(key, value)); + } + + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::unordered_multimap &t) +{ + typedef typename boost::unordered_multimap::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << itr->first; + stream << itr->second; + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::unordered_multimap &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + + for (quint64 i = 0; i < uiSize; ++i) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(std::make_pair(key, value)); + } + + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_MAP_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_set.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_set.h new file mode 100644 index 0000000..74c5208 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_boost_unordered_set.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_SET_H_ +#define _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_boost_unordered_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type boost::unordered_set and boost::unordered_multiset + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const boost::unordered_set &t) +{ + typedef typename boost::unordered_set::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::unordered_set &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.insert(tmp); + } + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const boost::unordered_multiset &t) +{ + typedef typename boost::unordered_multiset::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, boost::unordered_multiset &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.insert(tmp); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_BOOST_UNORDERED_SET_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.h new file mode 100644 index 0000000..c1d5103 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_PRIMITIVE_TYPE_H_ +#define _QX_SERIALIZE_QDATASTREAM_PRIMITIVE_TYPE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_primitive_type.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for primitive types (long, etc...) + */ + +#include + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const long &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, long &t) QX_USED; + +#endif // _QX_SERIALIZE_QDATASTREAM_PRIMITIVE_TYPE_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.h new file mode 100644 index 0000000..5dfce1e --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_QX_REGISTERED_CLASS_H_ +#define _QX_SERIALIZE_QDATASTREAM_QX_REGISTERED_CLASS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_qx_registered_class.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a generic Qt QDataStream serialization method (save/load) for classes registered into QxOrm context (void qx::register_class() function), it is possible to specialize qx::QxSerializeRegistered template to implement your own serialization method for a specific class + */ + +#include + +#include + +#include +#include + +namespace qx +{ + + struct QX_DLL_EXPORT QxSerializeRegistered_Helper + { + + static QDataStream &save(QDataStream &stream, IxClass *pClass, const void *pOwner); + static QDataStream &load(QDataStream &stream, IxClass *pClass, void *pOwner); + + private: + static void saveHelper(QDataStream &stream, IxClass *pClass, const void *pOwner); + static void loadHelper(QDataStream &stream, IxClass *pClass, void *pOwner); + }; + + template + struct QxSerializeRegistered + { + + enum + { + is_valid = qx::trait::is_qx_registered::value + }; + + static QDataStream &save(QDataStream &stream, const T &t) + { + static_assert(is_valid, "is_valid"); + return qx::QxSerializeRegistered_Helper::save(stream, qx::QxClass::getSingleton(), (&t)); + } + + static QDataStream &load(QDataStream &stream, T &t) + { + static_assert(is_valid, "is_valid"); + return qx::QxSerializeRegistered_Helper::load(stream, qx::QxClass::getSingleton(), (&t)); + } + }; + +} // namespace qx + +#endif // _QX_SERIALIZE_QDATASTREAM_QX_REGISTERED_CLASS_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_list.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_list.h new file mode 100644 index 0000000..bc92f67 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_list.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_LIST_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_list.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::list + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::list &t) +{ + typedef typename std::list::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::list &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.push_back(tmp); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_LIST_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_map.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_map.h new file mode 100644 index 0000000..03559ad --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_map.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_MAP_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::map + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::map &t) +{ + typedef typename std::map::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << itr->first; + stream << itr->second; + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::map &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + + for (quint64 i = 0; i < uiSize; ++i) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(std::make_pair(key, value)); + } + + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_MAP_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_pair.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_pair.h new file mode 100644 index 0000000..a02e43b --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_pair.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_SERIALIZE_QDATASTREAM_STD_PAIR_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_PAIR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_pair.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::pair + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::pair &t) +{ + stream << t.first; + stream << t.second; + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::pair &t) +{ + stream >> t.first; + stream >> t.second; + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_PAIR_H_ +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_set.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_set.h new file mode 100644 index 0000000..1412c3f --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_set.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_SET_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::set + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::set &t) +{ + typedef typename std::set::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::set &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.insert(tmp); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_SET_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_shared_ptr.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_shared_ptr.h new file mode 100644 index 0000000..dd3dcb6 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_shared_ptr.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_SHARED_PTR_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_shared_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::shared_ptr (C++11 compilation option _QX_CPP_11_SMART_PTR must be defined) + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::shared_ptr &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::shared_ptr &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t = std::make_shared(); + stream >> (*t); + } + else + { + t.reset(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_SHARED_PTR_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.h new file mode 100644 index 0000000..ba75390 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_STRING_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_STRING_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_string.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::string and std::wstring + */ + +#include + +#include + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const std::string &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, std::string &t) QX_USED; + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const std::wstring &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, std::wstring &t) QX_USED; + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_STRING_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_tuple.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_tuple.h new file mode 100644 index 0000000..209027f --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_tuple.h @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_TUPLE_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_tuple.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::tuple (C++11 compilation option _QX_CPP_11_TUPLE must be defined) + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + stream << std::get<5>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + stream << std::get<5>(t); + stream << std::get<6>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + stream << std::get<5>(t); + stream << std::get<6>(t); + stream << std::get<7>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + stream << std::get<5>(t); + stream << std::get<6>(t); + stream << std::get<7>(t); + stream << std::get<8>(t); + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::tuple &t) +{ + stream << std::get<0>(t); + stream << std::get<1>(t); + stream << std::get<2>(t); + stream << std::get<3>(t); + stream << std::get<4>(t); + stream << std::get<5>(t); + stream << std::get<6>(t); + stream << std::get<7>(t); + stream << std::get<8>(t); + stream << std::get<9>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + stream >> std::get<5>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + stream >> std::get<5>(t); + stream >> std::get<6>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + stream >> std::get<5>(t); + stream >> std::get<6>(t); + stream >> std::get<7>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + stream >> std::get<5>(t); + stream >> std::get<6>(t); + stream >> std::get<7>(t); + stream >> std::get<8>(t); + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::tuple &t) +{ + stream >> std::get<0>(t); + stream >> std::get<1>(t); + stream >> std::get<2>(t); + stream >> std::get<3>(t); + stream >> std::get<4>(t); + stream >> std::get<5>(t); + stream >> std::get<6>(t); + stream >> std::get<7>(t); + stream >> std::get<8>(t); + stream >> std::get<9>(t); + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_TUPLE_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unique_ptr.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unique_ptr.h new file mode 100644 index 0000000..859987f --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unique_ptr.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_UNIQUE_PTR_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_UNIQUE_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_unique_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::unique_ptr (C++11 compilation option _QX_CPP_11_SMART_PTR must be defined) + */ + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::unique_ptr &t) +{ + qint8 iIsNull = (t ? 0 : 1); + stream << iIsNull; + if (t) + { + stream << (*t); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::unique_ptr &t) +{ + qint8 iIsNull = 0; + stream >> iIsNull; + if (!iIsNull) + { + t.reset(new T()); + stream >> (*t); + } + else + { + t.reset(); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_UNIQUE_PTR_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_map.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_map.h new file mode 100644 index 0000000..6b2aea8 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_map.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_UNORDERED_MAP_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_unordered_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::unordered_map and std::unordered_multimap (C++11 compilation option _QX_CPP_11_CONTAINER must be defined) + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::unordered_map &t) +{ + typedef typename std::unordered_map::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << itr->first; + stream << itr->second; + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::unordered_map &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + + for (quint64 i = 0; i < uiSize; ++i) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(std::make_pair(key, value)); + } + + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::unordered_multimap &t) +{ + typedef typename std::unordered_multimap::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << itr->first; + stream << itr->second; + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::unordered_multimap &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + + for (quint64 i = 0; i < uiSize; ++i) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(std::make_pair(key, value)); + } + + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_UNORDERED_MAP_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_set.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_set.h new file mode 100644 index 0000000..cf796cc --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_unordered_set.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_UNORDERED_SET_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_unordered_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::unordered_set and std::unordered_multiset (C++11 compilation option _QX_CPP_11_CONTAINER must be defined) + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::unordered_set &t) +{ + typedef typename std::unordered_set::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::unordered_set &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.insert(tmp); + } + return stream; +} + +template +QDataStream &operator<<(QDataStream &stream, const std::unordered_multiset &t) +{ + typedef typename std::unordered_multiset::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::unordered_multiset &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.insert(tmp); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_UNORDERED_SET_H_ diff --git a/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_vector.h b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_vector.h new file mode 100644 index 0000000..3cd2977 --- /dev/null +++ b/include/QxSerialize/QDataStream/QxSerializeQDataStream_std_vector.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_STD_VECTOR_H_ +#define _QX_SERIALIZE_QDATASTREAM_STD_VECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream_std_vector.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QDataStream serialization method (save/load) for type std::vector + */ + +#include + +#include + +template +QDataStream &operator<<(QDataStream &stream, const std::vector &t) +{ + typedef typename std::vector::const_iterator type_itr; + quint64 uiSize = static_cast(t.size()); + stream << uiSize; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + stream << (*itr); + } + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, std::vector &t) +{ + quint64 uiSize = 0; + stream >> uiSize; + t.clear(); + t.reserve(static_cast::size_type>(uiSize)); + for (quint64 i = 0; i < uiSize; ++i) + { + T tmp; + stream >> tmp; + t.push_back(tmp); + } + return stream; +} + +#endif // _QX_SERIALIZE_QDATASTREAM_STD_VECTOR_H_ diff --git a/include/QxSerialize/QJson/QxSerializeQJson_IxParameter.h b/include/QxSerialize/QJson/QxSerializeQJson_IxParameter.h new file mode 100644 index 0000000..182629a --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_IxParameter.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERIALIZE_QJSON_IX_PARAMETER_H_ +#define _QX_SERIALIZE_QJSON_IX_PARAMETER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_IxParameter.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::service::IxParameter + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::service::IxParameter &t, const QString &format) + { + Q_UNUSED(t); + Q_UNUSED(format); + return QJsonValue(); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::service::IxParameter &t, const QString &format) + { + Q_UNUSED(j); + Q_UNUSED(t); + Q_UNUSED(format); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_IX_PARAMETER_H_ +#endif // _QX_ENABLE_QT_NETWORK +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_IxPersistable.h b/include/QxSerialize/QJson/QxSerializeQJson_IxPersistable.h new file mode 100644 index 0000000..21a0eb2 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_IxPersistable.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_IX_PERSISTABLE_H_ +#define _QX_SERIALIZE_QJSON_IX_PERSISTABLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_IxPersistable.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::IxPersistable + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::IxPersistable &t, const QString &format) + { + QJsonParseError err; + QString json = t.toJson(format); + QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), (&err)); + if (err.error != QJsonParseError::NoError) + { + return QJsonValue(); + } + return (doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object())); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::IxPersistable &t, const QString &format) + { + QJsonDocument doc = (j.isArray() ? QJsonDocument(j.toArray()) : QJsonDocument(j.toObject())); + QString json = QString::fromUtf8(doc.toJson()); + return t.fromJson(json, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_IX_PERSISTABLE_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_IxService.h b/include/QxSerialize/QJson/QxSerializeQJson_IxService.h new file mode 100644 index 0000000..ab94b46 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_IxService.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERIALIZE_QJSON_IX_SERVICE_H_ +#define _QX_SERIALIZE_QJSON_IX_SERVICE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_IxService.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::service::IxService + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::service::IxService &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::service::IxService &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_IX_SERVICE_H_ +#endif // _QX_ENABLE_QT_NETWORK +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.h b/include/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.h new file mode 100644 index 0000000..b497378 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_IX_SQL_ELEMENT_H_ +#define _QX_SERIALIZE_QJSON_IX_SQL_ELEMENT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_IxSqlElement.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::dao::detail::IxSqlElement + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::dao::detail::IxSqlElement &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::dao::detail::IxSqlElement &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_IX_SQL_ELEMENT_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QBrush.h b/include/QxSerialize/QJson/QxSerializeQJson_QBrush.h new file mode 100644 index 0000000..1720b67 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QBrush.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QBRUSH_H_ +#define _QX_SERIALIZE_QJSON_QBRUSH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QBrush.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QBrush + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QBrush &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QBrush &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QBrush &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QBrush &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QBRUSH_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QColor.h b/include/QxSerialize/QJson/QxSerializeQJson_QColor.h new file mode 100644 index 0000000..b1955c3 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QColor.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QCOLOR_H_ +#define _QX_SERIALIZE_QJSON_QCOLOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QColor.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QColor + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QColor &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QColor &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QColor &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QColor &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QCOLOR_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QFlags.h b/include/QxSerialize/QJson/QxSerializeQJson_QFlags.h new file mode 100644 index 0000000..6f23e07 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QFlags.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QFLAGS_H_ +#define _QX_SERIALIZE_QJSON_QFLAGS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QFlags.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QFlags + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QFlags &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QFlags &t, const QString &format) + { + Q_UNUSED(format); + t = QFlags(QFlag(qRound(j.toDouble()))); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QFLAGS_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QFont.h b/include/QxSerialize/QJson/QxSerializeQJson_QFont.h new file mode 100644 index 0000000..97fbe24 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QFont.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QFONT_H_ +#define _QX_SERIALIZE_QJSON_QFONT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QFont.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QFont + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QFont &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QFont &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QFont &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QFont &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QFONT_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QHash.h b/include/QxSerialize/QJson/QxSerializeQJson_QHash.h new file mode 100644 index 0000000..9285e6c --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QHash.h @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QHASH_H_ +#define _QX_SERIALIZE_QJSON_QHASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QHash.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QHash + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QHash &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + QHashIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + QJsonObject obj; + val = qx::cvt::to_json(itr.key(), format); + obj.insert("key", val); + val = qx::cvt::to_json(itr.value(), format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QHash &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(arr.count()); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QHash &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QHashIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + val = qx::cvt::to_json(itr.value(), format); + obj.insert(itr.key(), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QHash &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(obj.count()); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QHash &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QHashIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + +#ifndef QT_NO_STL + QString key = QString::fromStdString(itr.key()); +#else // QT_NO_STL + std::string s = itr.key(); + QString key = QString::fromLatin1(s.data(), int(s.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(itr.value(), format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QHash &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(obj.count()); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(s, value); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QHash &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QHashIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + val = qx::cvt::to_json(itr.value(), format); + obj.insert(QString::fromStdWString(itr.key()), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QHash &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(obj.count()); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key.toStdWString(), value); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QHASH_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QImage.h b/include/QxSerialize/QJson/QxSerializeQJson_QImage.h new file mode 100644 index 0000000..7fb2ad8 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QImage.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QIMAGE_H_ +#define _QX_SERIALIZE_QJSON_QIMAGE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QImage.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QImage + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QImage &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QImage &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QImage &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QImage &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QIMAGE_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QLinkedList.h b/include/QxSerialize/QJson/QxSerializeQJson_QLinkedList.h new file mode 100644 index 0000000..5ca8e12 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QLinkedList.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +#ifndef _QX_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QLINKEDLIST_H_ +#define _QX_SERIALIZE_QJSON_QLINKEDLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QLinkedList.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QLinkedList + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QLinkedList &t, const QString &format) + { + QJsonArray arr; + QLinkedListIterator itr(t); + while (itr.hasNext()) + { + arr.append(qx::cvt::to_json(itr.next(), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QLinkedList &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.append(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QLINKEDLIST_H_ +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QList.h b/include/QxSerialize/QJson/QxSerializeQJson_QList.h new file mode 100644 index 0000000..a3540c8 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QList.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QLIST_H_ +#define _QX_SERIALIZE_QJSON_QLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QList.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QList + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QList &t, const QString &format) + { + QJsonArray arr; + for (int i = 0; i < t.count(); i++) + { + arr.append(qx::cvt::to_json(t.at(i), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QList &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + t.reserve(arr.count()); +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.append(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QLIST_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QMap.h b/include/QxSerialize/QJson/QxSerializeQJson_QMap.h new file mode 100644 index 0000000..95a05ca --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QMap.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QMAP_H_ +#define _QX_SERIALIZE_QJSON_QMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QMap.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QMap + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMap &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + QMapIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + QJsonObject obj; + val = qx::cvt::to_json(itr.key(), format); + obj.insert("key", val); + val = qx::cvt::to_json(itr.value(), format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMap &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMap &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QMapIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + val = qx::cvt::to_json(itr.value(), format); + obj.insert(itr.key(), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMap &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMap &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QMapIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + +#ifndef QT_NO_STL + QString key = QString::fromStdString(itr.key()); +#else // QT_NO_STL + std::string s = itr.key(); + QString key = QString::fromLatin1(s.data(), int(s.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(itr.value(), format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMap &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(s, value); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMap &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + QMapIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + val = qx::cvt::to_json(itr.value(), format); + obj.insert(QString::fromStdWString(itr.key()), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMap &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key.toStdWString(), value); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QMAP_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QMatrix.h b/include/QxSerialize/QJson/QxSerializeQJson_QMatrix.h new file mode 100644 index 0000000..91aea97 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QMatrix.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QMATRIX_H_ +#define _QX_SERIALIZE_QJSON_QMATRIX_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QMatrix.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QMatrix + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QMatrix &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QMatrix &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QMatrix &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QMatrix &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QMATRIX_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QMultiHash.h b/include/QxSerialize/QJson/QxSerializeQJson_QMultiHash.h new file mode 100644 index 0000000..e3bc4f7 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QMultiHash.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QMULTIHASH_H_ +#define _QX_SERIALIZE_QJSON_QMULTIHASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QMultiHash.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QMultiHash + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMultiHash &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + QHashIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + QJsonObject obj; + val = qx::cvt::to_json(itr.key(), format); + obj.insert("key", val); + val = qx::cvt::to_json(itr.value(), format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMultiHash &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(arr.count()); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QMULTIHASH_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QMultiMap.h b/include/QxSerialize/QJson/QxSerializeQJson_QMultiMap.h new file mode 100644 index 0000000..ea28343 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QMultiMap.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QMULTIMAP_H_ +#define _QX_SERIALIZE_QJSON_QMULTIMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QMultiMap.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QMultiMap + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QMultiMap &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + QMapIterator itr(t); + + while (itr.hasNext()) + { + itr.next(); + QJsonObject obj; + val = qx::cvt::to_json(itr.key(), format); + obj.insert("key", val); + val = qx::cvt::to_json(itr.value(), format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QMultiMap &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QMULTIMAP_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QObject.h b/include/QxSerialize/QJson/QxSerializeQJson_QObject.h new file mode 100644 index 0000000..02de41e --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QObject.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QOBJECT_H_ +#define _QX_SERIALIZE_QJSON_QOBJECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QObject.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QObject (serialize dynamic properties) + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QObject &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QObject &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QObject &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QObject &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QOBJECT_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QPair.h b/include/QxSerialize/QJson/QxSerializeQJson_QPair.h new file mode 100644 index 0000000..b0dde00 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QPair.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QPAIR_H_ +#define _QX_SERIALIZE_QJSON_QPAIR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QPair.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QPair + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QPair &t, const QString &format) + { + QJsonArray arr; + arr.append(qx::cvt::to_json(t.first, format)); + arr.append(qx::cvt::to_json(t.second, format)); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QPair &t, const QString &format) + { + t = QPair(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + if (arr.count() != 2) + { + return qx_bool(true); + } + T1 tmp1; + qx::cvt::from_json(arr.at(0), tmp1, format); + T2 tmp2; + qx::cvt::from_json(arr.at(1), tmp2, format); + t = qMakePair(tmp1, tmp2); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QPAIR_H_ +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QPicture.h b/include/QxSerialize/QJson/QxSerializeQJson_QPicture.h new file mode 100644 index 0000000..5e9c8b0 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QPicture.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QPICTURE_H_ +#define _QX_SERIALIZE_QJSON_QPICTURE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QPicture.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QPicture + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QPicture &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPicture &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QPicture &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QPicture &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QPICTURE_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QPixmap.h b/include/QxSerialize/QJson/QxSerializeQJson_QPixmap.h new file mode 100644 index 0000000..de0e0b9 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QPixmap.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QPIXMAP_H_ +#define _QX_SERIALIZE_QJSON_QPIXMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QPixmap.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QPixmap + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QPixmap &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPixmap &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QPixmap &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QPixmap &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QPIXMAP_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QPoint.h b/include/QxSerialize/QJson/QxSerializeQJson_QPoint.h new file mode 100644 index 0000000..f1a1a59 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QPoint.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QPOINT_H_ +#define _QX_SERIALIZE_QJSON_QPOINT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QPoint.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QPoint + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QPoint &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPoint &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QPoint &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QPoint &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QPOINT_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QRect.h b/include/QxSerialize/QJson/QxSerializeQJson_QRect.h new file mode 100644 index 0000000..6a55cf7 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QRect.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QRECT_H_ +#define _QX_SERIALIZE_QJSON_QRECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QRect.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QRect + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QRect &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRect &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QRect &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QRect &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QRECT_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QRegExp.h b/include/QxSerialize/QJson/QxSerializeQJson_QRegExp.h new file mode 100644 index 0000000..ecc6c0d --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QRegExp.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QREGEXP_H_ +#define _QX_SERIALIZE_QJSON_QREGEXP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QRegExp.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QRegExp + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QRegExp &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRegExp &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QRegExp &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QRegExp &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QREGEXP_H_ +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QRegion.h b/include/QxSerialize/QJson/QxSerializeQJson_QRegion.h new file mode 100644 index 0000000..8a1625b --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QRegion.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QJSON_QREGION_H_ +#define _QX_SERIALIZE_QJSON_QREGION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QRegion.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QRegion + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QRegion &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRegion &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QRegion &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QRegion &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QREGION_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QScopedPointer.h b/include/QxSerialize/QJson/QxSerializeQJson_QScopedPointer.h new file mode 100644 index 0000000..4ac9b86 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QScopedPointer.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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_NO_JSON +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#ifndef _QX_SERIALIZE_QJSON_QSCOPEDPOINTER_H_ +#define _QX_SERIALIZE_QJSON_QSCOPEDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QScopedPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QScopedPointer + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QScopedPointer &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QScopedPointer &t, const QString &format) + { + if (j.isNull()) + { + t.reset(); + return qx_bool(true); + } + t.reset(new T()); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QSCOPEDPOINTER_H_ +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QSharedPointer.h b/include/QxSerialize/QJson/QxSerializeQJson_QSharedPointer.h new file mode 100644 index 0000000..3fe9427 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QSharedPointer.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QSHAREDPOINTER_H_ +#define _QX_SERIALIZE_QJSON_QSHAREDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QSharedPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QSharedPointer + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QSharedPointer &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QSharedPointer &t, const QString &format) + { + if (j.isNull()) + { + t.clear(); + return qx_bool(true); + } + t = QSharedPointer(new T()); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QSHAREDPOINTER_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QSize.h b/include/QxSerialize/QJson/QxSerializeQJson_QSize.h new file mode 100644 index 0000000..719bf99 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QSize.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QSIZE_H_ +#define _QX_SERIALIZE_QJSON_QSIZE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QSize.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QSize + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QSize &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QSize &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QSize &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QSize &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QSIZE_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QSqlError.h b/include/QxSerialize/QJson/QxSerializeQJson_QSqlError.h new file mode 100644 index 0000000..3633247 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QSqlError.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QSQLERROR_H_ +#define _QX_SERIALIZE_QJSON_QSQLERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QSqlError.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QSqlError + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QSqlError &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QSqlError &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QSqlError &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QSqlError &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QSQLERROR_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QStringList.h b/include/QxSerialize/QJson/QxSerializeQJson_QStringList.h new file mode 100644 index 0000000..d3852a2 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QStringList.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QSTRINGLIST_H_ +#define _QX_SERIALIZE_QJSON_QSTRINGLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QStringList.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QStringList + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const QStringList &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QStringList &t, const QString &format) QX_USED; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QStringList &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QStringList &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QSTRINGLIST_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QUrl.h b/include/QxSerialize/QJson/QxSerializeQJson_QUrl.h new file mode 100644 index 0000000..6696642 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QUrl.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QURL_H_ +#define _QX_SERIALIZE_QJSON_QURL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QUrl.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QUrl + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QUrl &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toString()); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QUrl &t, const QString &format) + { + Q_UNUSED(format); + t = QUrl(j.toString()); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QURL_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QVariantHash.h b/include/QxSerialize/QJson/QxSerializeQJson_QVariantHash.h new file mode 100644 index 0000000..f17c11f --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QVariantHash.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_NO_JSON +#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) +#ifndef _QX_SERIALIZE_QJSON_QVARIANTHASH_H_ +#define _QX_SERIALIZE_QJSON_QVARIANTHASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QVariantHash.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QVariantHash + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QVariantHash &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(QJsonObject::fromVariantHash(t)); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QVariantHash &t, const QString &format) + { + Q_UNUSED(format); + t = j.toObject().toVariantHash(); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QVARIANTHASH_H_ +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QVariantMap.h b/include/QxSerialize/QJson/QxSerializeQJson_QVariantMap.h new file mode 100644 index 0000000..932c262 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QVariantMap.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QVARIANTMAP_H_ +#define _QX_SERIALIZE_QJSON_QVARIANTMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QVariantMap.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QVariantMap + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QVariantMap &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(QJsonObject::fromVariantMap(t)); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QVariantMap &t, const QString &format) + { + Q_UNUSED(format); + t = j.toObject().toVariantMap(); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QVARIANTMAP_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QVector.h b/include/QxSerialize/QJson/QxSerializeQJson_QVector.h new file mode 100644 index 0000000..e24accb --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QVector.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QVECTOR_H_ +#define _QX_SERIALIZE_QJSON_QVECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QVector.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QVector + */ + +#include +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QVector &t, const QString &format) + { + QJsonArray arr; + for (int i = 0; i < t.count(); i++) + { + arr.append(qx::cvt::to_json(t.at(i), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QVector &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(arr.count()); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.append(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QVECTOR_H_ +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QWeakPointer.h b/include/QxSerialize/QJson/QxSerializeQJson_QWeakPointer.h new file mode 100644 index 0000000..0606485 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QWeakPointer.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QWEAKPOINTER_H_ +#define _QX_SERIALIZE_QJSON_QWEAKPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QWeakPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type QWeakPointer + */ + +#include +#include +#include +#include + +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const QWeakPointer &t, const QString &format) + { + QSharedPointer ptr = t.toStrongRef(); + return qx::cvt::to_json(ptr, format); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, QWeakPointer &t, const QString &format) + { + QSharedPointer ptr; + qx::cvt::from_json(j, ptr, format); + t = QWeakPointer(ptr); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QWEAKPOINTER_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxCollection.h b/include/QxSerialize/QJson/QxSerializeQJson_QxCollection.h new file mode 100644 index 0000000..ecbd814 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxCollection.h @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_COLLECTION_H_ +#define _QX_SERIALIZE_QJSON_QX_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxCollection.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::QxCollection + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const qx::QxCollection &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + + for (long l = 0; l < t.count(); l++) + { + QJsonObject obj; + val = qx::cvt::to_json(t.getKeyByIndex(l), format); + obj.insert("key", val); + val = qx::cvt::to_json(t.getByIndex(l), format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxCollection &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(static_cast(arr.count())); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const qx::QxCollection &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + + for (long l = 0; l < t.count(); l++) + { + val = qx::cvt::to_json(t.getByIndex(l), format); + obj.insert(t.getKeyByIndex(l), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxCollection &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key, value); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const qx::QxCollection &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + + for (long l = 0; l < t.count(); l++) + { +#ifndef QT_NO_STL + QString key = QString::fromStdString(t.getKeyByIndex(l)); +#else // QT_NO_STL + std::string s = t.getKeyByIndex(l); + QString key = QString::fromLatin1(s.data(), int(s.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(t.getByIndex(l), format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxCollection &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(s, value); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const qx::QxCollection &t, const QString &format) + { + QJsonObject obj; + QJsonValue val; + + for (long l = 0; l < t.count(); l++) + { + val = qx::cvt::to_json(t.getByIndex(l), format); + obj.insert(QString::fromStdWString(t.getKeyByIndex(l)), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxCollection &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(key.toStdWString(), value); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_COLLECTION_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxDaoPointer.h b/include/QxSerialize/QJson/QxSerializeQJson_QxDaoPointer.h new file mode 100644 index 0000000..dc7cf11 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxDaoPointer.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_DAO_POINTER_H_ +#define _QX_SERIALIZE_QJSON_QX_DAO_POINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxDaoPointer.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::dao::ptr + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const qx::dao::ptr &t, const QString &format) + { + QJsonArray arr; + arr.append(qx::cvt::to_json(t.data(), format)); + arr.append(qx::cvt::to_json(t.dataOriginal(), format)); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, qx::dao::ptr &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + if (arr.count() != 2) + { + return qx_bool(true); + } + T *ptr = NULL; + T *original = NULL; + qx::cvt::from_json(arr.at(0), ptr, format); + qx::cvt::from_json(arr.at(1), original, format); + t = qx::dao::ptr(ptr, original); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_DAO_POINTER_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.h b/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.h new file mode 100644 index 0000000..8474bc6 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_H_ +#define _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxInvalidValue.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::QxInvalidValue + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxInvalidValue &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxInvalidValue &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.h b/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.h new file mode 100644 index 0000000..e316831 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_X_H_ +#define _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxInvalidValueX.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::QxInvalidValueX + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxInvalidValueX &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxInvalidValueX &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_INVALID_VALUE_X_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.h b/include/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.h new file mode 100644 index 0000000..c25a2a8 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_SQL_QUERY_H_ +#define _QX_SERIALIZE_QJSON_QX_SQL_QUERY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxSqlQuery.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::QxSqlQuery + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxSqlQuery &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxSqlQuery &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_SQL_QUERY_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_QxTransaction.h b/include/QxSerialize/QJson/QxSerializeQJson_QxTransaction.h new file mode 100644 index 0000000..1747897 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_QxTransaction.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERIALIZE_QJSON_QX_TRANSACTION_H_ +#define _QX_SERIALIZE_QJSON_QX_TRANSACTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_QxTransaction.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type qx::service::QxTransaction + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::service::QxTransaction &t, const QString &format) + { + return QxConvert_ToJson_Helper(t, format); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::service::QxTransaction &t, const QString &format) + { + return QxConvert_FromJson_Helper(j, t, format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_QX_TRANSACTION_H_ +#endif // _QX_ENABLE_QT_NETWORK +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_all_include.h b/include/QxSerialize/QJson/QxSerializeQJson_all_include.h new file mode 100644 index 0000000..01b1c7f --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_all_include.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_ALL_INCLUDE_H_ +#define _QX_SERIALIZE_QJSON_ALL_INCLUDE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_all_include.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Include all Qt QJson serialization method (save/load) provided by QxOrm library + */ + +#ifdef _QX_ENABLE_BOOST +#include +#include +#include +#include +#include +#endif // _QX_ENABLE_BOOST + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _QX_SERIALIZE_QJSON_ALL_INCLUDE_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_boost_scoped_ptr.h b/include/QxSerialize/QJson/QxSerializeQJson_boost_scoped_ptr.h new file mode 100644 index 0000000..a2bb833 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_boost_scoped_ptr.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QJSON_BOOST_SCOPED_PTR_H_ +#define _QX_SERIALIZE_QJSON_BOOST_SCOPED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_boost_scoped_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type boost::scoped_ptr + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::scoped_ptr &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::scoped_ptr &t, const QString &format) + { + if (j.isNull()) + { + t.reset(); + return qx_bool(true); + } + t.reset(new T()); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_BOOST_SCOPED_PTR_H_ +#endif // _QX_ENABLE_BOOST +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_boost_shared_ptr.h b/include/QxSerialize/QJson/QxSerializeQJson_boost_shared_ptr.h new file mode 100644 index 0000000..4898101 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_boost_shared_ptr.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QJSON_BOOST_SHARED_PTR_H_ +#define _QX_SERIALIZE_QJSON_BOOST_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_boost_shared_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type boost::shared_ptr + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::shared_ptr &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::shared_ptr &t, const QString &format) + { + if (j.isNull()) + { + t.reset(); + return qx_bool(true); + } + t.reset(new T()); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_BOOST_SHARED_PTR_H_ +#endif // _QX_ENABLE_BOOST +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_boost_tuple.h b/include/QxSerialize/QJson/QxSerializeQJson_boost_tuple.h new file mode 100644 index 0000000..c281fe4 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_boost_tuple.h @@ -0,0 +1,455 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QJSON_BOOST_TUPLE_H_ +#define _QX_SERIALIZE_QJSON_BOOST_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_boost_tuple.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type boost::tuple + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<5>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<6>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<7>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<7>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<8>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(boost::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<7>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<8>(t), format); + arr.append(val); + val = qx::cvt::to_json(boost::get<9>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + qx::cvt::from_json(arr.at(5), boost::get<5>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + qx::cvt::from_json(arr.at(5), boost::get<5>(t), format); + qx::cvt::from_json(arr.at(6), boost::get<6>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + qx::cvt::from_json(arr.at(5), boost::get<5>(t), format); + qx::cvt::from_json(arr.at(6), boost::get<6>(t), format); + qx::cvt::from_json(arr.at(7), boost::get<7>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + qx::cvt::from_json(arr.at(5), boost::get<5>(t), format); + qx::cvt::from_json(arr.at(6), boost::get<6>(t), format); + qx::cvt::from_json(arr.at(7), boost::get<7>(t), format); + qx::cvt::from_json(arr.at(8), boost::get<8>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), boost::get<0>(t), format); + qx::cvt::from_json(arr.at(1), boost::get<1>(t), format); + qx::cvt::from_json(arr.at(2), boost::get<2>(t), format); + qx::cvt::from_json(arr.at(3), boost::get<3>(t), format); + qx::cvt::from_json(arr.at(4), boost::get<4>(t), format); + qx::cvt::from_json(arr.at(5), boost::get<5>(t), format); + qx::cvt::from_json(arr.at(6), boost::get<6>(t), format); + qx::cvt::from_json(arr.at(7), boost::get<7>(t), format); + qx::cvt::from_json(arr.at(8), boost::get<8>(t), format); + qx::cvt::from_json(arr.at(9), boost::get<9>(t), format); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_BOOST_TUPLE_H_ +#endif // _QX_ENABLE_BOOST +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_map.h b/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_map.h new file mode 100644 index 0000000..8178b85 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_map.h @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QJSON_BOOST_UNORDERED_MAP_H_ +#define _QX_SERIALIZE_QJSON_BOOST_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_boost_unordered_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type boost::unordered_map and boost::unordered_multimap + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_map &t, const QString &format) + { + typedef typename boost::unordered_map::const_iterator type_itr; + QJsonArray arr; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + QJsonObject obj; + val = qx::cvt::to_json(itr->first, format); + obj.insert("key", val); + val = qx::cvt::to_json(itr->second, format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(static_cast::size_type>(arr.count())); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_multimap &t, const QString &format) + { + typedef typename boost::unordered_multimap::const_iterator type_itr; + QJsonArray arr; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + QJsonObject obj; + val = qx::cvt::to_json(itr->first, format); + obj.insert("key", val); + val = qx::cvt::to_json(itr->second, format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_multimap &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(static_cast::size_type>(arr.count())); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_map &t, const QString &format) + { + typedef typename boost::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(itr->first, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_map &t, const QString &format) + { + typedef typename boost::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { +#ifndef QT_NO_STL + QString key = QString::fromStdString(itr->first); +#else // QT_NO_STL + QString key = QString::fromLatin1(itr->first.data(), int(itr->first.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(itr->second, format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(std::make_pair(s, value)); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_map &t, const QString &format) + { + typedef typename boost::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(QString::fromStdWString(itr->first), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key.toStdWString(), value)); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_BOOST_UNORDERED_MAP_H_ +#endif // _QX_ENABLE_BOOST +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_set.h b/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_set.h new file mode 100644 index 0000000..58272d8 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_boost_unordered_set.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_SERIALIZE_QJSON_BOOST_UNORDERED_SET_H_ +#define _QX_SERIALIZE_QJSON_BOOST_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_boost_unordered_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type boost::unordered_set and boost::unordered_multiset + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_set &t, const QString &format) + { + QJsonArray arr; + typedef typename boost::unordered_set::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_set &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(static_cast::size_type>(arr.count())); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.insert(tmp); + } + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::unordered_multiset &t, const QString &format) + { + QJsonArray arr; + typedef typename boost::unordered_multiset::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::unordered_multiset &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(static_cast::size_type>(arr.count())); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.insert(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_BOOST_UNORDERED_SET_H_ +#endif // _QX_ENABLE_BOOST +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.h b/include/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.h new file mode 100644 index 0000000..466fb91 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_QX_REGISTERED_CLASS_H_ +#define _QX_SERIALIZE_QJSON_QX_REGISTERED_CLASS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_qx_registered_class.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a generic Qt QJson serialization method (save/load) for classes registered into QxOrm context (void qx::register_class() function), it is possible to specialize qx::cvt::detail::QxSerializeJsonRegistered template to implement your own serialization method for a specific class + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + struct QX_DLL_EXPORT QxSerializeJsonRegistered_Helper + { + + static QJsonValue save(IxClass *pClass, const void *pOwner, const QString &format); + static qx_bool load(const QJsonValue &j, IxClass *pClass, void *pOwner, const QString &format); + }; + + template + struct QxSerializeJsonRegistered + { + + enum + { + is_valid = qx::trait::is_qx_registered::value + }; + + static QJsonValue save(const T &t, const QString &format) + { + static_assert(is_valid, "is_valid"); + return qx::cvt::detail::QxSerializeJsonRegistered_Helper::save(qx::QxClass::getSingleton(), (&t), format); + } + + static qx_bool load(const QJsonValue &j, T &t, const QString &format) + { + static_assert(is_valid, "is_valid"); + return qx::cvt::detail::QxSerializeJsonRegistered_Helper::load(j, qx::QxClass::getSingleton(), (&t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#define QX_JSON_SERIALIZE_ONLY_ID "QX_JSON_SERIALIZE_ONLY_ID" + +#endif // _QX_SERIALIZE_QJSON_QX_REGISTERED_CLASS_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_list.h b/include/QxSerialize/QJson/QxSerializeQJson_std_list.h new file mode 100644 index 0000000..9bbd32a --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_list.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_LIST_H_ +#define _QX_SERIALIZE_QJSON_STD_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_list.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::list + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::list &t, const QString &format) + { + QJsonArray arr; + typedef typename std::list::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::list &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.push_back(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_LIST_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_map.h b/include/QxSerialize/QJson/QxSerializeQJson_std_map.h new file mode 100644 index 0000000..79e424c --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_map.h @@ -0,0 +1,274 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_MAP_H_ +#define _QX_SERIALIZE_QJSON_STD_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::map + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::map &t, const QString &format) + { + typedef typename std::map::const_iterator type_itr; + QJsonArray arr; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + QJsonObject obj; + val = qx::cvt::to_json(itr->first, format); + obj.insert("key", val); + val = qx::cvt::to_json(itr->second, format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::map &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::map &t, const QString &format) + { + typedef typename std::map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(itr->first, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::map &t, const QString &format) + { + typedef typename std::map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { +#ifndef QT_NO_STL + QString key = QString::fromStdString(itr->first); +#else // QT_NO_STL + std::string s = itr->first; + QString key = QString::fromLatin1(s.data(), int(s.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(itr->second, format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(std::make_pair(s, value)); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::map &t, const QString &format) + { + typedef typename std::map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(QString::fromStdWString(itr->first), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key.toStdWString(), value)); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_MAP_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_pair.h b/include/QxSerialize/QJson/QxSerializeQJson_std_pair.h new file mode 100644 index 0000000..f9590eb --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_pair.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_PAIR_H_ +#define _QX_SERIALIZE_QJSON_STD_PAIR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_pair.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::pair + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::pair &t, const QString &format) + { + QJsonArray arr; + arr.append(qx::cvt::to_json(t.first, format)); + arr.append(qx::cvt::to_json(t.second, format)); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::pair &t, const QString &format) + { + t = std::pair(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + if (arr.count() != 2) + { + return qx_bool(true); + } + T1 tmp1; + qx::cvt::from_json(arr.at(0), tmp1, format); + T2 tmp2; + qx::cvt::from_json(arr.at(1), tmp2, format); + t = std::make_pair(tmp1, tmp2); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_PAIR_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_set.h b/include/QxSerialize/QJson/QxSerializeQJson_std_set.h new file mode 100644 index 0000000..9594fe5 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_set.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_SET_H_ +#define _QX_SERIALIZE_QJSON_STD_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::set + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::set &t, const QString &format) + { + QJsonArray arr; + typedef typename std::set::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::set &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.insert(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_SET_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_shared_ptr.h b/include/QxSerialize/QJson/QxSerializeQJson_std_shared_ptr.h new file mode 100644 index 0000000..7531780 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_shared_ptr.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_SHARED_PTR_H_ +#define _QX_SERIALIZE_QJSON_STD_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_shared_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::shared_ptr (C++11 compilation option _QX_CPP_11_SMART_PTR must be defined) + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::shared_ptr &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::shared_ptr &t, const QString &format) + { + if (j.isNull()) + { + t.reset(); + return qx_bool(true); + } + t = std::make_shared(); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_SHARED_PTR_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_tuple.h b/include/QxSerialize/QJson/QxSerializeQJson_std_tuple.h new file mode 100644 index 0000000..2b47b08 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_tuple.h @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_TUPLE_H_ +#define _QX_SERIALIZE_QJSON_STD_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_tuple.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::tuple (C++11 compilation option _QX_CPP_11_TUPLE must be defined) + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<5>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<6>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<7>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<7>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<8>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::tuple &t, const QString &format) + { + QJsonArray arr; + QJsonValue val; + val = qx::cvt::to_json(std::get<0>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<1>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<2>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<3>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<4>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<5>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<6>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<7>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<8>(t), format); + arr.append(val); + val = qx::cvt::to_json(std::get<9>(t), format); + arr.append(val); + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + qx::cvt::from_json(arr.at(5), std::get<5>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + qx::cvt::from_json(arr.at(5), std::get<5>(t), format); + qx::cvt::from_json(arr.at(6), std::get<6>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + qx::cvt::from_json(arr.at(5), std::get<5>(t), format); + qx::cvt::from_json(arr.at(6), std::get<6>(t), format); + qx::cvt::from_json(arr.at(7), std::get<7>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + qx::cvt::from_json(arr.at(5), std::get<5>(t), format); + qx::cvt::from_json(arr.at(6), std::get<6>(t), format); + qx::cvt::from_json(arr.at(7), std::get<7>(t), format); + qx::cvt::from_json(arr.at(8), std::get<8>(t), format); + return qx_bool(true); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::tuple &t, const QString &format) + { + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + qx::cvt::from_json(arr.at(0), std::get<0>(t), format); + qx::cvt::from_json(arr.at(1), std::get<1>(t), format); + qx::cvt::from_json(arr.at(2), std::get<2>(t), format); + qx::cvt::from_json(arr.at(3), std::get<3>(t), format); + qx::cvt::from_json(arr.at(4), std::get<4>(t), format); + qx::cvt::from_json(arr.at(5), std::get<5>(t), format); + qx::cvt::from_json(arr.at(6), std::get<6>(t), format); + qx::cvt::from_json(arr.at(7), std::get<7>(t), format); + qx::cvt::from_json(arr.at(8), std::get<8>(t), format); + qx::cvt::from_json(arr.at(9), std::get<9>(t), format); + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_TUPLE_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_unique_ptr.h b/include/QxSerialize/QJson/QxSerializeQJson_std_unique_ptr.h new file mode 100644 index 0000000..611106b --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_unique_ptr.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_UNIQUE_PTR_H_ +#define _QX_SERIALIZE_QJSON_STD_UNIQUE_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_unique_ptr.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::unique_ptr (C++11 compilation option _QX_CPP_11_SMART_PTR must be defined) + */ + +#include +#include +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unique_ptr &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + } + return QJsonValue(); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unique_ptr &t, const QString &format) + { + if (j.isNull()) + { + t.reset(); + return qx_bool(true); + } + t.reset(new T()); + return qx::cvt::from_json(j, (*t), format); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_UNIQUE_PTR_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_map.h b/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_map.h new file mode 100644 index 0000000..6a3b2db --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_map.h @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_UNORDERED_MAP_H_ +#define _QX_SERIALIZE_QJSON_STD_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_unordered_map.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::unordered_map and std::unordered_multimap (C++11 compilation option _QX_CPP_11_CONTAINER must be defined) + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_map &t, const QString &format) + { + typedef typename std::unordered_map::const_iterator type_itr; + QJsonArray arr; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + QJsonObject obj; + val = qx::cvt::to_json(itr->first, format); + obj.insert("key", val); + val = qx::cvt::to_json(itr->second, format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(static_cast::size_type>(arr.count())); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_multimap &t, const QString &format) + { + typedef typename std::unordered_multimap::const_iterator type_itr; + QJsonArray arr; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + QJsonObject obj; + val = qx::cvt::to_json(itr->first, format); + obj.insert("key", val); + val = qx::cvt::to_json(itr->second, format); + obj.insert("value", val); + arr.append(obj); + } + + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_multimap &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + QJsonValue val; + QJsonObject obj; + t.reserve(static_cast::size_type>(arr.count())); + + for (int i = 0; i < arr.count(); i++) + { + val = arr.at(i); + if (!val.isObject()) + { + continue; + } + obj = val.toObject(); + Key key; + Value value; + qx::cvt::from_json(obj.value("key"), key, format); + qx::cvt::from_json(obj.value("value"), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_map &t, const QString &format) + { + typedef typename std::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(itr->first, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key, value)); + } + + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_map &t, const QString &format) + { + typedef typename std::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { +#ifndef QT_NO_STL + QString key = QString::fromStdString(itr->first); +#else // QT_NO_STL + QString key = QString::fromLatin1(itr->first.data(), int(itr->first.size())); +#endif // QT_NO_STL + + val = qx::cvt::to_json(itr->second, format); + obj.insert(key, val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + +#ifndef QT_NO_STL + std::string s = key.toStdString(); +#else // QT_NO_STL + std::string s = key.toLatin1().constData(); +#endif // QT_NO_STL + + t.insert(std::make_pair(s, value)); + } + + return qx_bool(true); + } + }; + +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_map &t, const QString &format) + { + typedef typename std::unordered_map::const_iterator type_itr; + QJsonObject obj; + QJsonValue val; + + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + val = qx::cvt::to_json(itr->second, format); + obj.insert(QString::fromStdWString(itr->first), val); + } + + return QJsonValue(obj); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_map &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QJsonValue val; + t.reserve(static_cast::size_type>(obj.count())); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + Value value; + qx::cvt::from_json(itr.value(), value, format); + t.insert(std::make_pair(key.toStdWString(), value)); + } + + return qx_bool(true); + } + }; + +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_UNORDERED_MAP_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_set.h b/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_set.h new file mode 100644 index 0000000..9fab6c9 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_unordered_set.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_UNORDERED_SET_H_ +#define _QX_SERIALIZE_QJSON_STD_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_unordered_set.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::unordered_set and std::unordered_multiset (C++11 compilation option _QX_CPP_11_CONTAINER must be defined) + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_set &t, const QString &format) + { + QJsonArray arr; + typedef typename std::unordered_set::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_set &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(static_cast::size_type>(arr.count())); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.insert(tmp); + } + return qx_bool(true); + } + }; + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::unordered_multiset &t, const QString &format) + { + QJsonArray arr; + typedef typename std::unordered_multiset::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::unordered_multiset &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(static_cast::size_type>(arr.count())); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.insert(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_UNORDERED_SET_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/QJson/QxSerializeQJson_std_vector.h b/include/QxSerialize/QJson/QxSerializeQJson_std_vector.h new file mode 100644 index 0000000..1ddb456 --- /dev/null +++ b/include/QxSerialize/QJson/QxSerializeQJson_std_vector.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_STD_VECTOR_H_ +#define _QX_SERIALIZE_QJSON_STD_VECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson_std_vector.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a Qt QJson serialization method (save/load) for type std::vector + */ + +#include +#include +#include + +#include + +#include +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const std::vector &t, const QString &format) + { + QJsonArray arr; + typedef typename std::vector::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + arr.append(qx::cvt::to_json((*itr), format)); + } + return QJsonValue(arr); + } + }; + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, std::vector &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.reserve(static_cast::size_type>(arr.count())); + for (int i = 0; i < arr.count(); i++) + { + T tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.push_back(tmp); + } + return qx_bool(true); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_STD_VECTOR_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/Qt/QxSerialize_QBrush.h b/include/QxSerialize/Qt/QxSerialize_QBrush.h new file mode 100644 index 0000000..64711da --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QBrush.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QBRUSH_H_ +#define _QX_SERIALIZE_QBRUSH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +QX_CLASS_VERSION(QBrush, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QBrush) + +#endif // _QX_SERIALIZE_QBRUSH_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QByteArray.h b/include/QxSerialize/Qt/QxSerialize_QByteArray.h new file mode 100644 index 0000000..1abfb0a --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QByteArray.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QBYTEARRAY_H_ +#define _QX_SERIALIZE_QBYTEARRAY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QByteArray, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QByteArray) + +#endif // _QX_SERIALIZE_QBYTEARRAY_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QColor.h b/include/QxSerialize/Qt/QxSerialize_QColor.h new file mode 100644 index 0000000..559ea5e --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QColor.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QCOLOR_H_ +#define _QX_SERIALIZE_QCOLOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QColor, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QColor) + +#endif // _QX_SERIALIZE_QCOLOR_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QDate.h b/include/QxSerialize/Qt/QxSerialize_QDate.h new file mode 100644 index 0000000..73bf118 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QDate.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QDATE_H_ +#define _QX_SERIALIZE_QDATE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +#define QX_SERIALIZE_QDATE_FORMAT "yyyyMMdd" + +QX_CLASS_VERSION(QDate, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QDate) + +#endif // _QX_SERIALIZE_QDATE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QDateTime.h b/include/QxSerialize/Qt/QxSerialize_QDateTime.h new file mode 100644 index 0000000..7900752 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QDateTime.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QDATETIME_H_ +#define _QX_SERIALIZE_QDATETIME_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +#define QX_SERIALIZE_QDATETIME_FORMAT "yyyyMMddhhmmsszzz" + +QX_CLASS_VERSION(QDateTime, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QDateTime) + +#endif // _QX_SERIALIZE_QDATETIME_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QFlags.h b/include/QxSerialize/Qt/QxSerialize_QFlags.h new file mode 100644 index 0000000..7d3f9f5 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QFlags.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QFLAGS_H_ +#define _QX_SERIALIZE_QFLAGS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QFlags &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iValue = static_cast(t); + ar << boost::serialization::make_nvp("value", iValue); + } + + template + inline void load(Archive &ar, QFlags &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iValue = 0; + ar >> boost::serialization::make_nvp("value", iValue); + t = QFlags(QFlag(iValue)); + } + + template + inline void serialize(Archive &ar, QFlags &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QFLAGS_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QFont.h b/include/QxSerialize/Qt/QxSerialize_QFont.h new file mode 100644 index 0000000..522642f --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QFont.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QFONT_H_ +#define _QX_SERIALIZE_QFONT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QFont, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QFont) + +#endif // _QX_SERIALIZE_QFONT_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QHash.h b/include/QxSerialize/Qt/QxSerialize_QHash.h new file mode 100644 index 0000000..f8a33fd --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QHash.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QHASH_H_ +#define _QX_SERIALIZE_QHASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QHash &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + QHashIterator itr(t); + while (itr.hasNext()) + { + itr.next(); + std::pair pair_key_value = std::make_pair(itr.key(), itr.value()); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, QHash &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + t.reserve(lCount); + std::pair pair_key_value; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value.first, pair_key_value.second); + } + } + + template + inline void serialize(Archive &ar, QHash &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QHASH_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QImage.h b/include/QxSerialize/Qt/QxSerialize_QImage.h new file mode 100644 index 0000000..ffe4670 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QImage.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QIMAGE_H_ +#define _QX_SERIALIZE_QIMAGE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QImage, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QImage) +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(QImage) + +#endif // _QX_SERIALIZE_QIMAGE_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QLinkedList.h b/include/QxSerialize/Qt/QxSerialize_QLinkedList.h new file mode 100644 index 0000000..30103ba --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QLinkedList.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QLINKEDLIST_H_ +#define _QX_SERIALIZE_QLINKEDLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QLinkedList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + QLinkedListIterator itr(t); + while (itr.hasNext()) + ar << boost::serialization::make_nvp("item", itr.next()); + } + + template + inline void load(Archive &ar, QLinkedList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + T item; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", item); + t.append(item); + } + } + + template + inline void serialize(Archive &ar, QLinkedList &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QLINKEDLIST_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) diff --git a/include/QxSerialize/Qt/QxSerialize_QList.h b/include/QxSerialize/Qt/QxSerialize_QList.h new file mode 100644 index 0000000..a1a16d8 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QList.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QLIST_H_ +#define _QX_SERIALIZE_QLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + for (long l = 0; l < lCount; l++) + ar << boost::serialization::make_nvp("item", t.at(l)); + } + + template + inline void load(Archive &ar, QList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + T item; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", item); + t.append(item); + } + } + + template + inline void serialize(Archive &ar, QList &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QLIST_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QMap.h b/include/QxSerialize/Qt/QxSerialize_QMap.h new file mode 100644 index 0000000..929adb3 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QMap.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QMAP_H_ +#define _QX_SERIALIZE_QMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QMap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + QMapIterator itr(t); + while (itr.hasNext()) + { + itr.next(); + std::pair pair_key_value = std::make_pair(itr.key(), itr.value()); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, QMap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + std::pair pair_key_value; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value.first, pair_key_value.second); + } + } + + template + inline void serialize(Archive &ar, QMap &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QMAP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QMatrix.h b/include/QxSerialize/Qt/QxSerialize_QMatrix.h new file mode 100644 index 0000000..2ac5f36 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QMatrix.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QMATRIX_H_ +#define _QX_SERIALIZE_QMATRIX_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QMatrix, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QMatrix) + +#endif // _QX_SERIALIZE_QMATRIX_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/Qt/QxSerialize_QMultiHash.h b/include/QxSerialize/Qt/QxSerialize_QMultiHash.h new file mode 100644 index 0000000..edd00f0 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QMultiHash.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QMULTIHASH_H_ +#define _QX_SERIALIZE_QMULTIHASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QMultiHash &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + QHashIterator itr(t); + while (itr.hasNext()) + { + itr.next(); + std::pair pair_key_value = std::make_pair(itr.key(), itr.value()); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, QMultiHash &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + t.reserve(lCount); + std::pair pair_key_value; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value.first, pair_key_value.second); + } + } + + template + inline void serialize(Archive &ar, QMultiHash &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QMULTIHASH_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QMultiMap.h b/include/QxSerialize/Qt/QxSerialize_QMultiMap.h new file mode 100644 index 0000000..fd6b03f --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QMultiMap.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QMULTIMAP_H_ +#define _QX_SERIALIZE_QMULTIMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QMultiMap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + QMapIterator itr(t); + while (itr.hasNext()) + { + itr.next(); + std::pair pair_key_value = std::make_pair(itr.key(), itr.value()); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, QMultiMap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + std::pair pair_key_value; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value.first, pair_key_value.second); + } + } + + template + inline void serialize(Archive &ar, QMultiMap &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QMULTIMAP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QObject.h b/include/QxSerialize/Qt/QxSerialize_QObject.h new file mode 100644 index 0000000..e40f2fe --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QObject.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QOBJECT_H_ +#define _QX_SERIALIZE_QOBJECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QObject, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QObject) +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(QObject) +QX_REGISTER_BOOST_SERIALIZE_HELPER(QObject) + +#endif // _QX_SERIALIZE_QOBJECT_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QPair.h b/include/QxSerialize/Qt/QxSerialize_QPair.h new file mode 100644 index 0000000..bee092d --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QPair.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QPAIR_H_ +#define _QX_SERIALIZE_QPAIR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void serialize(Archive &ar, QPair &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("first", t.first); + ar &boost::serialization::make_nvp("second", t.second); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QPAIR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QPicture.h b/include/QxSerialize/Qt/QxSerialize_QPicture.h new file mode 100644 index 0000000..2b71382 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QPicture.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QPICTURE_H_ +#define _QX_SERIALIZE_QPICTURE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QPicture, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QPicture) +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(QPicture) + +#endif // _QX_SERIALIZE_QPICTURE_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QPixmap.h b/include/QxSerialize/Qt/QxSerialize_QPixmap.h new file mode 100644 index 0000000..0f6e463 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QPixmap.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QPIXMAP_H_ +#define _QX_SERIALIZE_QPIXMAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QPixmap, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QPixmap) +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(QPixmap) + +#endif // _QX_SERIALIZE_QPIXMAP_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QPoint.h b/include/QxSerialize/Qt/QxSerialize_QPoint.h new file mode 100644 index 0000000..66516fd --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QPoint.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QPOINT_H_ +#define _QX_SERIALIZE_QPOINT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QPoint, 0) + +QX_SERIALIZE_FAST_COMPIL_SERIALIZE_HPP(QX_DLL_EXPORT, QPoint) + +#endif // _QX_SERIALIZE_QPOINT_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QRect.h b/include/QxSerialize/Qt/QxSerialize_QRect.h new file mode 100644 index 0000000..f871658 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QRect.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QRECT_H_ +#define _QX_SERIALIZE_QRECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QRect, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QRect) + +#endif // _QX_SERIALIZE_QRECT_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QRegExp.h b/include/QxSerialize/Qt/QxSerialize_QRegExp.h new file mode 100644 index 0000000..f856508 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QRegExp.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QREGEXP_H_ +#define _QX_SERIALIZE_QREGEXP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QRegExp, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QRegExp) + +#endif // _QX_SERIALIZE_QREGEXP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/Qt/QxSerialize_QRegion.h b/include/QxSerialize/Qt/QxSerialize_QRegion.h new file mode 100644 index 0000000..3f4113c --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QRegion.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifdef _QX_ENABLE_QT_GUI +#ifndef _QX_SERIALIZE_QREGION_H_ +#define _QX_SERIALIZE_QREGION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +QX_CLASS_VERSION(QRegion, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QRegion) + +#endif // _QX_SERIALIZE_QREGION_H_ +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QScopedPointer.h b/include/QxSerialize/Qt/QxSerialize_QScopedPointer.h new file mode 100644 index 0000000..c619b4a --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QScopedPointer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#ifndef _QX_SERIALIZE_QSCOPEDPOINTER_H_ +#define _QX_SERIALIZE_QSCOPEDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QScopedPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + const T *ptr = t.data(); + ar << boost::serialization::make_nvp("qt_scoped_ptr", ptr); + } + + template + inline void load(Archive &ar, QScopedPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + T *ptr = NULL; + ar >> boost::serialization::make_nvp("qt_scoped_ptr", ptr); + t.reset(ptr); + } + + template + inline void serialize(Archive &ar, QScopedPointer &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QSCOPEDPOINTER_H_ +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QSharedPointer.h b/include/QxSerialize/Qt/QxSerialize_QSharedPointer.h new file mode 100644 index 0000000..8d532c4 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QSharedPointer.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QSHAREDPOINTER_H_ +#define _QX_SERIALIZE_QSHAREDPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QSharedPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + const T *ptr = t.data(); + ar << boost::serialization::make_nvp("qt_shared_ptr", ptr); + } + + template + inline void load(Archive &ar, QSharedPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + static QHash> listOfWeakPointers; + T *ptr = NULL; + ar >> boost::serialization::make_nvp("qt_shared_ptr", ptr); + if (!ptr) + { + t = QSharedPointer(); + return; + } + + void *pVoid = static_cast(ptr); + QSharedPointer pShared = (listOfWeakPointers.contains(pVoid) ? listOfWeakPointers.value(pVoid).toStrongRef() : QSharedPointer()); + if (pShared) + { + t = pShared; + return; + } + t = QSharedPointer(ptr); + QWeakPointer pWeak = t; + listOfWeakPointers.insert(pVoid, pWeak); + + static int iLoadCount = 0; + iLoadCount++; + if (iLoadCount <= 1000) + { + return; + } + QMutableHashIterator> itr(listOfWeakPointers); + while (itr.hasNext()) + { + itr.next(); + if (itr.value().isNull()) + { + itr.remove(); + } + } + iLoadCount = 0; + } + + template + inline void serialize(Archive &ar, QSharedPointer &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QSHAREDPOINTER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QSize.h b/include/QxSerialize/Qt/QxSerialize_QSize.h new file mode 100644 index 0000000..e8ff763 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QSize.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QSIZE_H_ +#define _QX_SERIALIZE_QSIZE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QSize, 0) + +QX_SERIALIZE_FAST_COMPIL_SERIALIZE_HPP(QX_DLL_EXPORT, QSize) + +#endif // _QX_SERIALIZE_QSIZE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QSqlError.h b/include/QxSerialize/Qt/QxSerialize_QSqlError.h new file mode 100644 index 0000000..2b72417 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QSqlError.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QSQLERROR_H_ +#define _QX_SERIALIZE_QSQLERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QSqlError, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QSqlError) + +#endif // _QX_SERIALIZE_QSQLERROR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QString.h b/include/QxSerialize/Qt/QxSerialize_QString.h new file mode 100644 index 0000000..1005300 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QString.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QSTRING_H_ +#define _QX_SERIALIZE_QSTRING_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QString, 0) +BOOST_CLASS_TRACKING(QString, boost::serialization::track_never) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QString) + +#endif // _QX_SERIALIZE_QSTRING_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QStringList.h b/include/QxSerialize/Qt/QxSerialize_QStringList.h new file mode 100644 index 0000000..316214b --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QStringList.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QSTRINGLIST_H_ +#define _QX_SERIALIZE_QSTRINGLIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QStringList, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QStringList) + +#endif // _QX_SERIALIZE_QSTRINGLIST_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QTime.h b/include/QxSerialize/Qt/QxSerialize_QTime.h new file mode 100644 index 0000000..d676172 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QTime.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QTIME_H_ +#define _QX_SERIALIZE_QTIME_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +#define QX_SERIALIZE_QTIME_FORMAT "hhmmsszzz" + +QX_CLASS_VERSION(QTime, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QTime) + +#endif // _QX_SERIALIZE_QTIME_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QUrl.h b/include/QxSerialize/Qt/QxSerialize_QUrl.h new file mode 100644 index 0000000..c005b29 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QUrl.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QURL_H_ +#define _QX_SERIALIZE_QURL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include + +#include + +QX_CLASS_VERSION(QUrl, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QUrl) + +#endif // _QX_SERIALIZE_QURL_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QUuid.h b/include/QxSerialize/Qt/QxSerialize_QUuid.h new file mode 100644 index 0000000..d76a0c7 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QUuid.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QUUID_H_ +#define _QX_SERIALIZE_QUUID_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +#include + +QX_CLASS_VERSION(QUuid, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QUuid) + +#endif // _QX_SERIALIZE_QUUID_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QVariant.h b/include/QxSerialize/Qt/QxSerialize_QVariant.h new file mode 100644 index 0000000..c72d9bd --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QVariant.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QVARIANT_H_ +#define _QX_SERIALIZE_QVARIANT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +QX_CLASS_VERSION(QVariant, 0) + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(QX_DLL_EXPORT, QVariant) + +#endif // _QX_SERIALIZE_QVARIANT_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qt/QxSerialize_QVector.h b/include/QxSerialize/Qt/QxSerialize_QVector.h new file mode 100644 index 0000000..02ea22f --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QVector.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QVECTOR_H_ +#define _QX_SERIALIZE_QVECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QVector &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + for (long l = 0; l < lCount; l++) + ar << boost::serialization::make_nvp("item", t.at(l)); + } + + template + inline void load(Archive &ar, QVector &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + t.reserve(lCount); + T item; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", item); + t.append(item); + } + } + + template + inline void serialize(Archive &ar, QVector &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QVECTOR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/include/QxSerialize/Qt/QxSerialize_QWeakPointer.h b/include/QxSerialize/Qt/QxSerialize_QWeakPointer.h new file mode 100644 index 0000000..28f4a15 --- /dev/null +++ b/include/QxSerialize/Qt/QxSerialize_QWeakPointer.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QWEAKPOINTER_H_ +#define _QX_SERIALIZE_QWEAKPOINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const QWeakPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QSharedPointer ptr = t.toStrongRef(); + ar << boost::serialization::make_nvp("qt_weak_ptr", ptr); + } + + template + inline void load(Archive &ar, QWeakPointer &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QSharedPointer ptr; + ar >> boost::serialization::make_nvp("qt_weak_ptr", ptr); + t = QWeakPointer(ptr); + } + + template + inline void serialize(Archive &ar, QWeakPointer &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QWEAKPOINTER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qx/QxSerialize_QxCollection.h b/include/QxSerialize/Qx/QxSerialize_QxCollection.h new file mode 100644 index 0000000..4801fb4 --- /dev/null +++ b/include/QxSerialize/Qx/QxSerialize_QxCollection.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QX_COLLECTION_H_ +#define _QX_SERIALIZE_QX_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const qx::QxCollection &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + for (long l = 0; l < lCount; l++) + { + std::pair pair_key_value = std::make_pair(t.getKeyByIndex(l), t.getByIndex(l)); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, qx::QxCollection &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + t.reserve(lCount); + std::pair pair_key_value; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value.first, pair_key_value.second); + } + } + + template + inline void serialize(Archive &ar, qx::QxCollection &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QX_COLLECTION_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qx/QxSerialize_QxDaoPointer.h b/include/QxSerialize/Qx/QxSerialize_QxDaoPointer.h new file mode 100644 index 0000000..1a9ed31 --- /dev/null +++ b/include/QxSerialize/Qx/QxSerialize_QxDaoPointer.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_QX_DAO_POINTER_H_ +#define _QX_SERIALIZE_QX_DAO_POINTER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const qx::dao::ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + const T *ptr = t.data(); + const T *original = t.dataOriginal(); + ar << boost::serialization::make_nvp("qx_dao_ptr", ptr); + ar << boost::serialization::make_nvp("qx_dao_ptr_original", original); + } + + template + inline void load(Archive &ar, qx::dao::ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + T *ptr = NULL; + T *original = NULL; + ar >> boost::serialization::make_nvp("qx_dao_ptr", ptr); + ar >> boost::serialization::make_nvp("qx_dao_ptr_original", original); + t = qx::dao::ptr(ptr, original); + } + + template + inline void serialize(Archive &ar, qx::dao::ptr &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_QX_DAO_POINTER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qx/QxSerialize_QxXmlReader.h b/include/QxSerialize/Qx/QxSerialize_QxXmlReader.h new file mode 100644 index 0000000..6a41202 --- /dev/null +++ b/include/QxSerialize/Qx/QxSerialize_QxXmlReader.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/Qx/QxSerialize_QxXmlWriter.h b/include/QxSerialize/Qx/QxSerialize_QxXmlWriter.h new file mode 100644 index 0000000..6a41202 --- /dev/null +++ b/include/QxSerialize/Qx/QxSerialize_QxXmlWriter.h @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxArchive.h b/include/QxSerialize/QxArchive.h new file mode 100644 index 0000000..d955241 --- /dev/null +++ b/include/QxSerialize/QxArchive.h @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_ARCHIVE_H_ +#define _QX_ARCHIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxArchive.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide some tools to serialize a class registered into QxOrm context into/from binary/XML archive (file, string, etc.) + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#define QX_STR_SERIALIZATION_ERROR "Serialization error : '%ERR%'" +#define QX_STR_DESERIALIZATION_ERROR "Deserialization error : '%ERR%'" + +namespace qx +{ + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_ToFile : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_ToFile + { + public: + static qx_bool toFile(const T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_FromFile : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_FromFile + { + public: + static qx_bool fromFile(T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_ToFileCompressed : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_ToFileCompressed + { + public: + static qx_bool toFileCompressed(const T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header, int iCompressionLevel = -1); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_FromFileCompressed : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_FromFileCompressed + { + public: + static qx_bool fromFileCompressed(T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_ToString : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_ToString + { + public: + static QString toString(const T &obj, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_FromString : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_FromString + { + public: + static qx_bool fromString(T &obj, const QString &sString, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_ToByteArray : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_ToByteArray + { + public: + typedef typename qx::trait::archive_wide_traits::type_string type_string; + static QByteArray toByteArray(const T &obj, type_string *owner = NULL, unsigned int flags = boost::archive::no_header); + }; + + /*! + * \ingroup QxSerialize + * \brief qx::QxArchive_FromByteArray : provide some tools to serialize a class registered into QxOrm context into/from binary/text/XML archives (file, string, etc.) + */ + template + class QxArchive_FromByteArray + { + public: + static qx_bool fromByteArray(T &obj, const QByteArray &data, unsigned int flags = boost::archive::no_header); + }; + +} // namespace qx + +#include "../../inl/QxSerialize/QxArchive.inl" + +namespace qx +{ + namespace serialization + { + + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, QX_DEFAULT_ARCHIVE_INPUT, QX_DEFAULT_ARCHIVE_OUTPUT) + +#if _QX_SERIALIZE_POLYMORPHIC + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from polymorphic_binary archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC compilation options in QxOrm.pri configuration file + */ + namespace polymorphic_binary + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::polymorphic_binary_iarchive, boost::archive::polymorphic_binary_oarchive) + } // namespace polymorphic_binary + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from polymorphic_text archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC compilation options in QxOrm.pri configuration file + */ + namespace polymorphic_text + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::polymorphic_text_iarchive, boost::archive::polymorphic_text_oarchive) + } // namespace polymorphic_text + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from polymorphic_xml archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC compilation options in QxOrm.pri configuration file + */ + namespace polymorphic_xml + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::polymorphic_xml_iarchive, boost::archive::polymorphic_xml_oarchive) + } // namespace polymorphic_xml + +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from binary archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_BINARY compilation options in QxOrm.pri configuration file + */ + namespace binary + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::binary_iarchive, boost::archive::binary_oarchive) + } // namespace binary + +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from text archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_TEXT compilation options in QxOrm.pri configuration file + */ + namespace text + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::text_iarchive, boost::archive::text_oarchive) + } // namespace text + +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from XML archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_XML compilation options in QxOrm.pri configuration file + */ + namespace xml + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::xml_iarchive, boost::archive::xml_oarchive) + } // namespace xml + +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from portable_binary archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_PORTABLE_BINARY compilation options in QxOrm.pri configuration file + */ + namespace portable_binary + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, eos::portable_iarchive, eos::portable_oarchive) + } // namespace portable_binary + +#endif // _QX_SERIALIZE_PORTABLE_BINARY + + namespace wide + { + +#if _QX_SERIALIZE_WIDE_BINARY + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from wide binary archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_WIDE_BINARY compilation options in QxOrm.pri configuration file + */ + namespace binary + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::binary_wiarchive, boost::archive::binary_woarchive) + } // namespace binary + +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from wide text archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_WIDE_TEXT compilation options in QxOrm.pri configuration file + */ + namespace text + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::text_wiarchive, boost::archive::text_woarchive) + } // namespace text + +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context into/from wide XML archive (file, string, etc.) : enable this feature defining _QX_ENABLE_BOOST_SERIALIZATION and _QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML compilation options in QxOrm.pri configuration file + */ + namespace xml + { + QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, boost::archive::xml_wiarchive, boost::archive::xml_woarchive) + } // namespace xml + +#endif // _QX_SERIALIZE_WIDE_XML + + } // namespace wide + } // namespace serialization +} // namespace qx + +#endif // _QX_ARCHIVE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.h b/include/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.h new file mode 100644 index 0000000..721e78d --- /dev/null +++ b/include/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _IX_BOOST_SERIALIZE_REGISTER_HELPER_H_ +#define _IX_BOOST_SERIALIZE_REGISTER_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#define QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(ArchiveIn, ArchiveOut) \ + virtual void helper(ArchiveIn &ar) const = 0; \ + virtual void helper(ArchiveOut &ar) const = 0; + +namespace qx +{ + + class QX_DLL_EXPORT IxBoostSerializeRegisterHelper + { + + private: + QString m_sKey; // Register key used by 'QxBoostSerializeRegisterHelperX' + + protected: + IxBoostSerializeRegisterHelper(const QString &sKey); + virtual ~IxBoostSerializeRegisterHelper() = 0; + + public: + virtual void helper() const = 0; + +#if _QX_SERIALIZE_POLYMORPHIC + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_IX_BOOST_SERIALIZE_REGISTER_HELPER_PURE_VIRTUAL_ARCHIVE(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + + private: + IxBoostSerializeRegisterHelper(const IxBoostSerializeRegisterHelper &other) { Q_UNUSED(other); } + IxBoostSerializeRegisterHelper &operator=(const IxBoostSerializeRegisterHelper &other) + { + Q_UNUSED(other); + return (*this); + } + }; + +} // namespace qx + +#endif // _IX_BOOST_SERIALIZE_REGISTER_HELPER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxBoostSerializeHelper/QxBoostInitGuid.h b/include/QxSerialize/QxBoostSerializeHelper/QxBoostInitGuid.h new file mode 100644 index 0000000..e09bc09 --- /dev/null +++ b/include/QxSerialize/QxBoostSerializeHelper/QxBoostInitGuid.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_BOOST_INIT_GUID_H_ +#define _QX_BOOST_INIT_GUID_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include + +#include + +namespace qx +{ + + template + class QxBoostInitGuid + { + + public: + static inline void init() + { + boost::serialization::singleton>::get_mutable_instance().guid(qx::trait::get_class_name::get()); + } + + private: + inline void guid(const char *key, std::false_type) + { + Q_UNUSED(key); /* boost::archive::detail::instantiate_ptr_serialization((T *)0, 0, boost::archive::detail::adl_tag()); */ + } + + inline void guid(const char *key, std::true_type) + { + Q_UNUSED(key); + } + + inline void guid(const char *key) + { + qAssert(NULL != key); + boost::serialization::singleton::type>::get_mutable_instance().key_register(key); + guid(key, boost::serialization::is_abstract()); + } + }; + +} // namespace qx + +#endif // _QX_BOOST_INIT_GUID_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeHelper.h b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeHelper.h new file mode 100644 index 0000000..ffa7786 --- /dev/null +++ b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeHelper.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_BOOST_SERIALIZE_HELPER_H_ +#define _QX_BOOST_SERIALIZE_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#include + +namespace qx +{ + + template + class QxBoostSerializeHelper + { + + private: + typedef T type_derived; + typedef typename qx::trait::get_base_class::type type_base; + + public: + template + static inline void register_type_helper(Archive &ar, const T *t) + { + Q_UNUSED(t); + ar.template register_type(); + } + + static inline void void_cast_register_helper(const T *t) + { + Q_UNUSED(t); + QxBoostVoidCastRegisterHelper::value, 0>::helper(); + } + + static inline void init_guid(const T *t) + { + Q_UNUSED(t); + QxBoostInitGuid::init(); + } + + private: + template + struct QxBoostVoidCastRegisterHelper + { + static inline void helper() { boost::serialization::void_cast_register(static_cast(NULL), static_cast(NULL)); } + }; + + template + struct QxBoostVoidCastRegisterHelper + { + static inline void helper() { /* Nothing */ ; } + }; + }; + +} // namespace qx + +#endif // _QX_BOOST_SERIALIZE_HELPER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelper.h b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelper.h new file mode 100644 index 0000000..d4a145b --- /dev/null +++ b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelper.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_BOOST_SERIALIZE_REGISTER_HELPER_H_ +#define _QX_BOOST_SERIALIZE_REGISTER_HELPER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +#define QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(ArchiveIn, ArchiveOut) \ + virtual void helper(ArchiveIn &ar) const { private_helper(ar); } \ + virtual void helper(ArchiveOut &ar) const { private_helper(ar); } + +namespace qx +{ + + template + class QxBoostSerializeRegisterHelper : public IxBoostSerializeRegisterHelper + { + + public: + QxBoostSerializeRegisterHelper(const QString &sKey) : IxBoostSerializeRegisterHelper(sKey) { ; } + virtual ~QxBoostSerializeRegisterHelper() { ; } + + virtual void helper() const { private_helper(); } + +#if _QX_SERIALIZE_POLYMORPHIC + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + QX_BOOST_SERIALIZE_REGISTER_HELPER_IMPLEMENT_VIRTUAL_ARCHIVE(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + + private: + template + inline void private_helper(Archive &ar) const + { + qx::QxBoostSerializeHelper::register_type_helper(ar, static_cast(NULL)); + qx::QxBoostSerializeHelper::void_cast_register_helper(static_cast(NULL)); + qx::QxBoostSerializeHelper::init_guid(static_cast(NULL)); + } + + inline void private_helper() const + { + qx::QxBoostSerializeHelper::void_cast_register_helper(static_cast(NULL)); + qx::QxBoostSerializeHelper::init_guid(static_cast(NULL)); + } + }; + +} // namespace qx + +#if _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME(className, classNameFormatted) \ + extern qx::QxBoostSerializeRegisterHelper G_QX_REGISTER_BOOST_SERIALIZE_HELPER_##classNameFormatted; +#define QX_REGISTER_BOOST_SERIALIZE_HELPER(className) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME(className, className) +#else +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME(className, classNameFormatted) /* Nothing */ +#define QX_REGISTER_BOOST_SERIALIZE_HELPER(className) /* Nothing */ +#endif // _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + +#if _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + qx::QxBoostSerializeRegisterHelper G_QX_REGISTER_BOOST_SERIALIZE_HELPER_##classNameFormatted(QString(#className)); +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_CPP(className) \ + QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME_CPP(className, className) +#else +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) /* Nothing */ +#define QX_REGISTER_BOOST_SERIALIZE_HELPER_CPP(className) /* Nothing */ +#endif // _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + +#endif // _QX_BOOST_SERIALIZE_REGISTER_HELPER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.h b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.h new file mode 100644 index 0000000..2f73d7e --- /dev/null +++ b/include/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_BOOST_SERIALIZE_REGISTER_HELPER_X_H_ +#define _QX_BOOST_SERIALIZE_REGISTER_HELPER_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#include + +#include + +#include +#include + +namespace qx +{ + + class QX_DLL_EXPORT QxBoostSerializeRegisterHelperX : public QxSingleton + { + + friend class QxSingleton; + friend class IxBoostSerializeRegisterHelper; + + private: + QxCollection m_colHelperX; // Collection of all 'IxBoostSerializeRegisterHelper' pointer + QMutex m_oMutexHelperX; // Mutex -> 'QxBoostSerializeRegisterHelperX' is thread-safe + + QxBoostSerializeRegisterHelperX() : QxSingleton("qx::QxBoostSerializeRegisterHelperX") { ; } + virtual ~QxBoostSerializeRegisterHelperX() { ; } + + public: + void add(const QString &sKey, IxBoostSerializeRegisterHelper *p); + void remove(const QString &sKey); + + template + static inline void helper(Archive &ar) +#if _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + { + QxBoostSerializeRegisterHelperX::getSingleton()->private_helper(ar); + } +#else + { + Q_UNUSED(ar); + } +#endif // _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + + static inline void helper() +#if _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + { + QxBoostSerializeRegisterHelperX::getSingleton()->private_helper(); + } +#else + { + ; + } +#endif // _QX_USE_BOOST_SERIALIZE_REGISTER_HELPER + + private: + template + inline void private_helper(Archive &ar) const + { + static bool bDone = false; + if (bDone) + { + return; + } + QMutexLocker locker(const_cast(&m_oMutexHelperX)); + if (bDone) + { + return; + } + _foreach(IxBoostSerializeRegisterHelper * p, m_colHelperX) { p->helper(ar); } + bDone = true; + } + + inline void private_helper() const + { + static bool bDone = false; + if (bDone) + { + return; + } + QMutexLocker locker(const_cast(&m_oMutexHelperX)); + if (bDone) + { + return; + } + _foreach(IxBoostSerializeRegisterHelper * p, m_colHelperX) { p->helper(); } + bDone = true; + } + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxBoostSerializeRegisterHelperX) + +#endif // _QX_BOOST_SERIALIZE_REGISTER_HELPER_X_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxClone.h b/include/QxSerialize/QxClone.h new file mode 100644 index 0000000..87d1dbe --- /dev/null +++ b/include/QxSerialize/QxClone.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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_CLONE_H_ +#define _QX_CLONE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxClone.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Clone all classes registered into QxOrm context using QxOrm library serialization engine + */ + +#include +#include +#include +#include + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include +#include +#include + +#else // _QX_ENABLE_BOOST_SERIALIZATION + +#include +#include + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#define QX_STR_CLONE_SERIALIZATION_ERROR "[QxOrm] qx::clone() serialization error : '%s'" +#define QX_STR_CLONE_DESERIALIZATION_ERROR "[QxOrm] qx::clone() deserialization error : '%s'" + +namespace qx +{ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + + /*! + * \ingroup QxSerialize + * \brief qx::clone_to_nude_ptr(const T & obj) : return a nude pointer (be careful with memory leak) of a new instance of type T cloned from obj + */ + template + T *clone_to_nude_ptr(const T &obj) + { + QX_CLONE_STRING_STREAM ioss(std::ios_base::binary | std::ios_base::in | std::ios_base::out); + QX_CLONE_BINARY_OUTPUT_ARCHIVE oar(ioss, boost::archive::no_header); + QxBoostSerializeRegisterHelperX::helper(oar); + bool bSerializeOk = false; + + try + { + oar << obj; + bSerializeOk = ioss.good(); + } + catch (const boost::archive::archive_exception &e) + { + qDebug(QX_STR_CLONE_SERIALIZATION_ERROR, e.what()); + } + catch (const std::exception &e) + { + qDebug(QX_STR_CLONE_SERIALIZATION_ERROR, e.what()); + } + catch (...) + { + qDebug(QX_STR_CLONE_SERIALIZATION_ERROR, "unknown error"); + } + if (!bSerializeOk) + { + qAssert(false); + return NULL; + } + + T *pClone = new T(); + QX_CLONE_BINARY_INPUT_ARCHIVE iar(ioss, boost::archive::no_header); + QxBoostSerializeRegisterHelperX::helper(iar); + bool bDeserializeOk = false; + + try + { + iar >> (*pClone); + bDeserializeOk = ioss.good(); + } + catch (const boost::archive::archive_exception &e) + { + qDebug(QX_STR_CLONE_DESERIALIZATION_ERROR, e.what()); + } + catch (const std::exception &e) + { + qDebug(QX_STR_CLONE_DESERIALIZATION_ERROR, e.what()); + } + catch (...) + { + qDebug(QX_STR_CLONE_DESERIALIZATION_ERROR, "unknown error"); + } + qAssert(bDeserializeOk); + + return (bDeserializeOk ? pClone : NULL); + } + +#else // _QX_ENABLE_BOOST_SERIALIZATION + + /*! + * \ingroup QxSerialize + * \brief qx::clone_to_nude_ptr(const T & obj) : return a nude pointer (be careful with memory leak) of a new instance of type T cloned from obj (this is a limited clone version which uses Qt QDataStream engine compared to boost::serialization engine) + */ + template + T *clone_to_nude_ptr(const T &obj) + { + QByteArray baClone = qx::serialization::qt::to_byte_array(obj); + if (baClone.isEmpty()) + { + qAssertMsg(false, "[QxOrm] qx::clone_to_nude_ptr", "an error occurred during QDataStream serialization process"); + return NULL; + } + T *pClone = new T(); + qx_bool bOk = qx::serialization::qt::from_byte_array((*pClone), baClone); + return (bOk ? pClone : NULL); + } + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + /*! + * \ingroup QxSerialize + * \brief qx::clone(const T & obj) : return a boost smart-pointer (std::shared_ptr) of a new instance of type T cloned from obj + */ + template + std::shared_ptr clone(const T &obj) + { + T *ptr = qx::clone_to_nude_ptr(obj); + return std::shared_ptr(ptr); + } + +#ifdef _QX_ENABLE_BOOST + + /*! + * \ingroup QxSerialize + * \brief qx::clone_to_boost_shared_ptr(const T & obj) : return a boost smart-pointer (boost::shared_ptr) of a new instance of type T cloned from obj + */ + template + boost::shared_ptr clone_to_boost_shared_ptr(const T &obj) + { + T *ptr = qx::clone_to_nude_ptr(obj); + return boost::shared_ptr(ptr); + } + +#endif // _QX_ENABLE_BOOST + + /*! + * \ingroup QxSerialize + * \brief qx::clone_to_qt_shared_ptr(const T & obj) : return a Qt smart-pointer (QSharedPointer) of a new instance of type T cloned from obj + */ + template + QSharedPointer clone_to_qt_shared_ptr(const T &obj) + { + T *ptr = qx::clone_to_nude_ptr(obj); + return QSharedPointer(ptr); + } + + /*! + * \ingroup QxSerialize + * \brief qx::clone_to_std_shared_ptr(const T & obj) : return a C++11 std smart-pointer (std::shared_ptr) of a new instance of type T cloned from obj + */ + template + std::shared_ptr clone_to_std_shared_ptr(const T &obj) + { + T *ptr = qx::clone_to_nude_ptr(obj); + return std::shared_ptr(ptr); + } + +} // namespace qx + +#endif // _QX_CLONE_H_ diff --git a/include/QxSerialize/QxDump.h b/include/QxSerialize/QxDump.h new file mode 100644 index 0000000..54c5b17 --- /dev/null +++ b/include/QxSerialize/QxDump.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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_DUMP_H_ +#define _QX_DUMP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxDump.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Dump all classes registered into QxOrm context using XML and JSON serialization engine + */ + +#include + +#include +#include +#include + +#include + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace qx +{ + + /*! + * \ingroup QxSerialize + * \brief qx::dump(const T & t, bool bJsonFormat) : dump class of type T registered into QxOrm context using XML and JSON serialization engine + */ + template + void dump(const T &t, bool bJsonFormat = false) + { + QString sDump; + + if (bJsonFormat) + { +#ifndef _QX_NO_JSON + sDump = qx::serialization::json::to_string(t); +#else // _QX_NO_JSON + sDump = "Unable to dump element in JSON format : you must work with Qt5 and not define _QX_NO_JSON compilation option in 'QxOrm.pri' configuration file"; +#endif // _QX_NO_JSON + } + else + { +#if _QX_SERIALIZE_POLYMORPHIC + sDump = qx::serialization::polymorphic_xml::to_string(t); +#elif _QX_SERIALIZE_XML + sDump = qx::serialization::xml::to_string(t); +#elif _QX_SERIALIZE_WIDE_XML + sDump = qx::serialization::wide::xml::to_string(t); +#else // _QX_SERIALIZE_POLYMORPHIC + sDump = "Unable to dump element : you must define '_QX_ENABLE_BOOST_SERIALIZATION' and '_QX_ENABLE_BOOST_SERIALIZATION_XML' (or '_QX_ENABLE_BOOST_SERIALIZATION_WIDE_XML') compilation options in 'QxOrm.pri' configuration file"; +#endif // _QX_SERIALIZE_POLYMORPHIC + } + + QString sName = qx::QxClassName::get(); + qDebug("[QxOrm] start dump '%s'", qPrintable(sName)); + qDebug("%s", qPrintable(sDump)); + qDebug("[QxOrm] end dump '%s'", qPrintable(sName)); + } + +} // namespace qx + +#else // _QX_ENABLE_BOOST_SERIALIZATION + +namespace qx +{ + + template + void dump(const T &t, bool bJsonFormat = true) + { +#ifdef _QX_NO_JSON + qDebug("[QxOrm] qx::dump() : %s", "not implemented when _QX_ENABLE_BOOST_SERIALIZATION compilation option is not defined (XML format) and _QX_NO_JSON compilation option is defined (JSON format)"); + Q_UNUSED(t); + Q_UNUSED(bJsonFormat); +#else // _QX_NO_JSON + if (!bJsonFormat) + { + return; + } + QString sDump = qx::serialization::json::to_string(t); + QString sName = qx::QxClassName::get(); + qDebug("[QxOrm] start dump '%s'", qPrintable(sName)); + qDebug("%s", qPrintable(sDump)); + qDebug("[QxOrm] end dump '%s'", qPrintable(sName)); +#endif // _QX_NO_JSON + } + +} // namespace qx + +#endif // _QX_ENABLE_BOOST_SERIALIZATION +#endif // _QX_DUMP_H_ diff --git a/include/QxSerialize/QxSerialize.h b/include/QxSerialize/QxSerialize.h new file mode 100644 index 0000000..a41e3cc --- /dev/null +++ b/include/QxSerialize/QxSerialize.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_H_ +#define _QX_SERIALIZE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerialize.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Include all files necessary to serialize most used classes defined into stl, boost and Qt libraries + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4189) +#endif // _MSC_VER + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* +#include +#include +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_SERIALIZE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxSerializeCheckInstance.h b/include/QxSerialize/QxSerializeCheckInstance.h new file mode 100644 index 0000000..55285e5 --- /dev/null +++ b/include/QxSerialize/QxSerializeCheckInstance.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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_SERIALIZE_CHECK_INSTANCE_H_ +#define _QX_SERIALIZE_CHECK_INSTANCE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeCheckInstance.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Check instance during serialization process to avoid infinite loop with circular references (using RAII) + */ + +#include +#include +#include + +namespace qx +{ + + class QxSqlRelationLinked; + class IxClass; + +} // namespace qx + +namespace qx +{ + namespace serialization + { + namespace helper + { + + /*! + * \ingroup QxSerialize + * \brief qx::serialization::helper::QxSerializeCheckInstance : check instance during serialization process to avoid infinite loop with circular references (using RAII) + */ + class QX_DLL_EXPORT QxSerializeCheckInstance + { + + public: + typedef QPair, QString> type_hierarchy; + + protected: + static QSet>> m_lstInstanceByThread; //!< List of all instances currently used by a serialization process + static QHash m_hashLevelByThread; //!< Manage how deep level is serialization process + static QHash m_hashHierarchyByThread; //!< Store current hierarchy used by serialization process + static QMutex m_mutex; //!< Mutex => qx::serialization::helper::QxSerializeCheckInstance is thread-safe + + qptrdiff m_pInstance; //!< Instance associated to this helper class + Qt::HANDLE m_lThreadId; //!< Thread id associated to this helper class + qx::IxClass *m_pClass; //!< Class associated to this helper class + + public: + QxSerializeCheckInstance(const void *pInstance, qx::IxClass *pClass); + virtual ~QxSerializeCheckInstance(); + + static bool contains(const void *pInstance, qx::IxClass *pClass); + static bool isRoot(); + + static type_hierarchy getHierarchy(); + static void setHierarchy(const type_hierarchy &hierarchy); + }; + + } // namespace helper + } // namespace serialization +} // namespace qx + +#endif // _QX_SERIALIZE_CHECK_INSTANCE_H_ diff --git a/include/QxSerialize/QxSerializeFastCompil.h b/include/QxSerialize/QxSerializeFastCompil.h new file mode 100644 index 0000000..1249151 --- /dev/null +++ b/include/QxSerialize/QxSerializeFastCompil.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_FAST_COMPIL_H_ +#define _QX_SERIALIZE_FAST_COMPIL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include +#include +#include +#include +#include + +#if _QX_BUILDING_QX_ORM +#define QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(T) /* Nothing */ +#define QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(T) QX_BOOST_EXPORT_SERIALIZATION_CPP(T) +#else // _QX_BUILDING_QX_ORM +#define QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_HPP(T) QX_BOOST_EXPORT_SERIALIZATION_HPP(T) +#define QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(T) /* Nothing */ +#endif // _QX_BUILDING_QX_ORM + +#define QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, Archive, className) \ + dllImportExport void save(Archive &ar, const className &t, const unsigned int file_version); + +#define QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, Archive, className) \ + dllImportExport void load(Archive &ar, className &t, const unsigned int file_version); + +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, Archive, className) \ + dllImportExport void serialize(Archive &ar, className &t, const unsigned int file_version); + +#define QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(Archive, className) \ + void save(Archive &ar, const className &t, const unsigned int file_version) \ + { \ + qx_save(ar, t, file_version); \ + } + +#define QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(Archive, className) \ + void load(Archive &ar, className &t, const unsigned int file_version) \ + { \ + qx_load(ar, t, file_version); \ + } + +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(Archive, className) \ + void serialize(Archive &ar, className &t, const unsigned int file_version) \ + { \ + qx_serialize(ar, t, file_version); \ + } + +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::polymorphic_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::polymorphic_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::polymorphic_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::polymorphic_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::polymorphic_iarchive, className) +#else // _QX_SERIALIZE_POLYMORPHIC +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::binary_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::binary_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::binary_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::binary_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::binary_iarchive, className) +#else // _QX_SERIALIZE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::text_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::text_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::text_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::text_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::text_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::text_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::text_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::text_iarchive, className) +#else // _QX_SERIALIZE_TEXT +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::xml_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::xml_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::xml_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::xml_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::xml_iarchive, className) +#else // _QX_SERIALIZE_XML +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, eos::portable_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, eos::portable_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, eos::portable_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, eos::portable_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(eos::portable_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(eos::portable_iarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(eos::portable_oarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(eos::portable_iarchive, className) +#else // _QX_SERIALIZE_PORTABLE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::binary_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::binary_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::binary_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::binary_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::binary_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_BINARY +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::text_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::text_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::text_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::text_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::text_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::text_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::text_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::text_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_TEXT +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_HPP(dllImportExport, boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_HPP(dllImportExport, boost::archive::xml_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_HPP(dllImportExport, boost::archive::xml_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_CPP(boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_LOAD_CPP(boost::archive::xml_wiarchive, className) +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::xml_woarchive, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_IMPL_CPP(boost::archive::xml_wiarchive, className) +#else // _QX_SERIALIZE_WIDE_XML +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_HPP(dllImportExport, className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_CPP(className) /* Nothing */ +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_CPP(className) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_XML + +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_HPP(dllImportExport, className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_HPP(dllImportExport, className) \ + \ + template \ + inline void serialize(Archive &ar, className &t, const unsigned int file_version) \ + { \ + boost::serialization::split_free(ar, t, file_version); \ + } \ + } \ + } // namespace boost::serialization + +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_HPP(dllImportExport, className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_HPP(dllImportExport, className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_HPP(dllImportExport, className) \ + } \ + } // namespace boost::serialization + +#define QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_WIDE_XML_CPP(className) \ + } \ + } // namespace boost::serialization + +#define QX_SERIALIZE_FAST_COMPIL_SERIALIZE_CPP(className) \ + namespace boost \ + { \ + namespace serialization \ + { \ + \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_POLYMORPHIC_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_XML_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_PORTABLE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_BINARY_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_TEXT_CPP(className) \ + QX_SERIALIZE_FAST_COMPIL_SERIALIZE_WIDE_XML_CPP(className) \ + } \ + } // namespace boost::serialization + +#endif // _QX_SERIALIZE_FAST_COMPIL_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxSerializeInvoker.h b/include/QxSerialize/QxSerializeInvoker.h new file mode 100644 index 0000000..8d89ba4 --- /dev/null +++ b/include/QxSerialize/QxSerializeInvoker.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_INVOKER_H_ +#define _QX_SERIALIZE_INVOKER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4094) +#endif // _MSC_VER + +#include +#include +#include + +#include +#include + +#include + +namespace qx +{ + namespace serialization + { + namespace detail + { + + template + struct base_class + { + template + static inline void save(Archive &ar, const T &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + const char *sTag = QxClass::getSingleton()->getNamePtr(); + ar << boost::serialization::make_nvp(sTag, boost::serialization::base_object(t)); + } + template + static inline void load(Archive &ar, T &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + const char *sTag = QxClass::getSingleton()->getNamePtr(); + ar >> boost::serialization::make_nvp(sTag, boost::serialization::base_object(t)); + } + }; + + template <> + struct base_class + { + template + static inline void save(Archive &ar, const T &t, const unsigned int file_version) + { + Q_UNUSED(ar); + Q_UNUSED(t); + Q_UNUSED(file_version); + } + template + static inline void load(Archive &ar, T &t, const unsigned int file_version) + { + Q_UNUSED(ar); + Q_UNUSED(t); + Q_UNUSED(file_version); + } + }; + + template + void save(Archive &ar, const T &t, const unsigned int file_version) + { + typedef typename qx::trait::get_base_class::type qx_type_base_class_tmp; + qx::serialization::detail::base_class::save(ar, t, file_version); + QxClass::getSingleton()->dataMemberX()->toArchive(&t, ar, file_version); + } + + template + void load(Archive &ar, T &t, const unsigned int file_version) + { + typedef typename qx::trait::get_base_class::type qx_type_base_class_tmp; + qx::serialization::detail::base_class::load(ar, t, file_version); + QxClass::getSingleton()->dataMemberX()->fromArchive(&t, ar, file_version); + } + + template + struct saver + { + static inline void invoke(Archive &ar, const T &t, const unsigned int file_version) + { + qx::serialization::detail::save(ar, t, file_version); + } + }; + + template + struct loader + { + static inline void invoke(Archive &ar, T &t, const unsigned int file_version) + { + qx::serialization::detail::load(ar, t, file_version); + } + }; + + } // namespace detail + } // namespace serialization +} // namespace qx + +#include "../../inl/QxSerialize/QxSerializeInvoker.inl" + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_SERIALIZE_INVOKER_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxSerializeMacro.h b/include/QxSerialize/QxSerializeMacro.h new file mode 100644 index 0000000..98904ca --- /dev/null +++ b/include/QxSerialize/QxSerializeMacro.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_MACRO_H_ +#define _QX_SERIALIZE_MACRO_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#define QX_ARCHIVE_NAMESPACE_FCT_IMPL(T, INPUT, OUTPUT) \ + \ + template \ + inline qx_bool to_file(const T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_ToFile::toFile(obj, sFileName, flags); }; \ + \ + template \ + inline qx_bool from_file(T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_FromFile::fromFile(obj, sFileName, flags); }; \ + \ + template \ + inline qx_bool to_file_compressed(const T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header, int iCompressionLevel = -1) { return qx::QxArchive_ToFileCompressed::toFileCompressed(obj, sFileName, flags, iCompressionLevel); }; \ + \ + template \ + inline qx_bool from_file_compressed(T &obj, const QString &sFileName, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_FromFileCompressed::fromFileCompressed(obj, sFileName, flags); }; \ + \ + template \ + inline QString to_string(const T &obj, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_ToString::toString(obj, flags); }; \ + \ + template \ + inline qx_bool from_string(T &obj, const QString &sString, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_FromString::fromString(obj, sString, flags); }; \ + \ + template \ + inline QByteArray to_byte_array(const T &obj, typename qx::trait::archive_wide_traits::type_string *owner = NULL, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_ToByteArray::toByteArray(obj, owner, flags); }; \ + \ + template \ + inline qx_bool from_byte_array(T &obj, const QByteArray &data, unsigned int flags = boost::archive::no_header) { return qx::QxArchive_FromByteArray::fromByteArray(obj, data, flags); }; + +#endif // _QX_SERIALIZE_MACRO_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/QxSerializeQDataStream.h b/include/QxSerialize/QxSerializeQDataStream.h new file mode 100644 index 0000000..35c3383 --- /dev/null +++ b/include/QxSerialize/QxSerializeQDataStream.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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_SERIALIZE_QDATASTREAM_H_ +#define _QX_SERIALIZE_QDATASTREAM_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQDataStream.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Used when _QX_ENABLE_BOOST_SERIALIZATION compilation option is not defined to provide serialization engine with Qt QDataStream class + */ + +#include + +#include +#include + +#include + +namespace qx +{ + namespace serialization + { + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context using Qt QDataStream serialization engine + */ + namespace qt + { + + template + inline QByteArray to_byte_array(const T &obj, void *owner = NULL, unsigned int flags = 1 /* boost::archive::no_header */) + { + Q_UNUSED(flags); + Q_UNUSED(owner); + QByteArray ba; + QString err; + QDataStream stream((&ba), QIODevice::WriteOnly); + stream << (quint32)(9438); + try + { + stream << obj; + } + catch (const std::exception &e) + { + err = QString("serialization error '%ERR%'").replace("%ERR%", e.what()); + } + catch (...) + { + err = QString("serialization error '%ERR%'").replace("%ERR%", "unknown error"); + } + if (!err.isEmpty()) + { + qDebug("[QxOrm] qx::serialization::qt::to_byte_array() : %s", qPrintable(err)); + ba.clear(); + } + return ba; + } + + template + inline qx_bool from_byte_array(T &obj, const QByteArray &data, unsigned int flags = 1 /* boost::archive::no_header */) + { + Q_UNUSED(flags); + qx_bool result = false; + if (data.isEmpty()) + { + return qx_bool(false, "input binary data is empty"); + } + QDataStream stream(data); + quint32 magic = 0; + stream >> magic; + if (magic != 9438) + { + return qx_bool(false, "input binary data is not valid"); + } + try + { + stream >> obj; + result = true; + } + catch (const std::exception &e) + { + result.setDesc(QString("deserialization error '%ERR%'").replace("%ERR%", e.what())); + } + catch (...) + { + result.setDesc(QString("deserialization error '%ERR%'").replace("%ERR%", "unknown error")); + } + if (!result.getDesc().isEmpty()) + { + QString msg = result.getDesc(); + qDebug("[QxOrm] qx::serialization::qt::from_byte_array() : %s", qPrintable(msg)); + } + return result; + } + + template + inline QString to_string(const T &obj, unsigned int flags = 1 /* boost::archive::no_header */) + { + return qx::serialization::qt::to_byte_array(obj, NULL, flags).toBase64(); + } + + template + inline qx_bool from_string(T &obj, const QString &sString, unsigned int flags = 1 /* boost::archive::no_header */) + { + QByteArray data = QByteArray::fromBase64(sString.toLatin1()); + return qx::serialization::qt::from_byte_array(obj, data, flags); + } + + template + inline qx_bool to_file(const T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */) + { + QByteArray data = qx::serialization::qt::to_byte_array(obj, NULL, flags); + QFile file(sFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + file.write(data); + file.close(); + return qx_bool(true); + } + + template + inline qx_bool from_file(T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */) + { + QFile file(sFileName); + if (!file.open(QIODevice::ReadOnly)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + QByteArray data = file.readAll(); + file.close(); + return qx::serialization::qt::from_byte_array(obj, data, flags); + } + + template + inline qx_bool to_file_compressed(const T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */, int iCompressionLevel = -1) + { + QByteArray data = qx::serialization::qt::to_byte_array(obj, NULL, flags); + QByteArray compressed = qCompress(data, iCompressionLevel); + QFile file(sFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + file.write(compressed); + file.close(); + return qx_bool(true); + } + + template + inline qx_bool from_file_compressed(T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */) + { + QFile file(sFileName); + if (!file.open(QIODevice::ReadOnly)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + QByteArray data = file.readAll(); + file.close(); + QByteArray uncompressed = qUncompress(data); + return qx::serialization::qt::from_byte_array(obj, uncompressed, flags); + } + + } // namespace qt + } // namespace serialization +} // namespace qx + +#endif // _QX_SERIALIZE_QDATASTREAM_H_ diff --git a/include/QxSerialize/QxSerializeQJson.h b/include/QxSerialize/QxSerializeQJson.h new file mode 100644 index 0000000..3db4783 --- /dev/null +++ b/include/QxSerialize/QxSerializeQJson.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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_NO_JSON +#ifndef _QX_SERIALIZE_QJSON_H_ +#define _QX_SERIALIZE_QJSON_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSerializeQJson.h + * \author XDL Team + * \ingroup QxSerialize + * \brief Provide a serialization engine with Qt QJson classes (this feature requires Qt5) + */ + +#include +#include +#include +#include +#include + +#include + +#include + +namespace qx +{ + namespace serialization + { + + /*! + * \ingroup QxSerialize + * \brief serialize a class registered into QxOrm context using Qt QJson serialization engine (this feature requires Qt5) + */ + namespace json + { + + template + inline QByteArray to_byte_array(const T &obj, void *owner = NULL, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + Q_UNUSED(flags); + Q_UNUSED(owner); + QJsonValue val = qx::cvt::to_json(obj, format); + QJsonDocument doc = (val.isArray() ? QJsonDocument(val.toArray()) : QJsonDocument(val.toObject())); + return doc.toJson(); + } + + template + inline qx_bool from_byte_array(T &obj, const QByteArray &data, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + Q_UNUSED(flags); + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(data, (&err)); + if (err.error != QJsonParseError::NoError) + { + return qx_bool(false, static_cast(err.error), err.errorString()); + } + QJsonValue val = (doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object())); + return qx::cvt::from_json(val, obj, format); + } + + template + inline QString to_string(const T &obj, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + return QString::fromUtf8(qx::serialization::json::to_byte_array(obj, NULL, flags, format)); + } + + template + inline qx_bool from_string(T &obj, const QString &sString, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + return qx::serialization::json::from_byte_array(obj, sString.toUtf8(), flags, format); + } + + template + inline qx_bool to_file(const T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + QByteArray data = qx::serialization::json::to_byte_array(obj, NULL, flags, format); + QFile file(sFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + file.write(data); + file.close(); + return qx_bool(true); + } + + template + inline qx_bool from_file(T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + QFile file(sFileName); + if (!file.open(QIODevice::ReadOnly)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + QByteArray data = file.readAll(); + file.close(); + return qx::serialization::json::from_byte_array(obj, data, flags, format); + } + + template + inline qx_bool to_file_compressed(const T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */, int iCompressionLevel = -1, const QString &format = QString()) + { + QByteArray data = qx::serialization::json::to_byte_array(obj, NULL, flags, format); + QByteArray compressed = qCompress(data, iCompressionLevel); + QFile file(sFileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + file.write(compressed); + file.close(); + return qx_bool(true); + } + + template + inline qx_bool from_file_compressed(T &obj, const QString &sFileName, unsigned int flags = 1 /* boost::archive::no_header */, const QString &format = QString()) + { + QFile file(sFileName); + if (!file.open(QIODevice::ReadOnly)) + { + return qx_bool(false, "cannot open file : " + sFileName); + } + QByteArray data = file.readAll(); + file.close(); + QByteArray uncompressed = qUncompress(data); + return qx::serialization::json::from_byte_array(obj, uncompressed, flags, format); + } + + } // namespace json + } // namespace serialization +} // namespace qx + +#endif // _QX_SERIALIZE_QJSON_H_ +#endif // _QX_NO_JSON diff --git a/include/QxSerialize/boost/QxExportDllBoostArchive.h b/include/QxSerialize/boost/QxExportDllBoostArchive.h new file mode 100644 index 0000000..59d120a --- /dev/null +++ b/include/QxSerialize/boost/QxExportDllBoostArchive.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_EXPORT_DLL_BOOST_ARCHIVE_H_ +#define _QX_EXPORT_DLL_BOOST_ARCHIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#if _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#if (!_QX_BUILDING_QX_ORM) + +#include + +#if (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::archive_serializer_map, Archive) +#else // (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION > 103800) + +#if (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_HPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_serializer_map, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_serializer_map, ArchiveOut) +#else // (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_HPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_pointer_iserializer, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_pointer_oserializer, ArchiveOut) +#endif // (BOOST_VERSION > 103800) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::save_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::save_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::save_non_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::save_non_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::save_enum_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::save_enum_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::save_array_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::save_array_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::load_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::load_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::load_non_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::load_non_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::load_enum_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::load_enum_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::archive::detail::load_array_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::load_array_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_HPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_IARCHIVE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::interface_iarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::interface_iarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_OARCHIVE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::interface_oarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::interface_oarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_IARCHIVE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::common_iarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::common_iarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_OARCHIVE_HPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::common_oarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::archive::detail::common_oarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_IARCHIVE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_OARCHIVE_HPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_IARCHIVE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_OARCHIVE_HPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_HPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_HPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_HPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_HPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_HPP(ArchiveIn, ArchiveOut) + +#if _QX_SERIALIZE_POLYMORPHIC +QX_BOOST_EXPORT_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +QX_BOOST_EXPORT_ARCHIVE_HPP(boost::archive::polymorphic_binary_iarchive, boost::archive::polymorphic_binary_oarchive) +QX_BOOST_EXPORT_ARCHIVE_HPP(boost::archive::polymorphic_text_iarchive, boost::archive::polymorphic_text_oarchive) +QX_BOOST_EXPORT_ARCHIVE_HPP(boost::archive::polymorphic_xml_iarchive, boost::archive::polymorphic_xml_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_HPP(eos::portable_iarchive, eos::portable_oarchive) +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +QX_BOOST_EXPORT_ARCHIVE_ALL_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#if _QX_USE_SERIALIZE_POLYMORPHIC_PATCH +namespace boost +{ + namespace archive + { + template <> + inline void xml_iarchive_impl::load(std::basic_string, std::allocator> &s) + { + Q_UNUSED(s); + qAssert(false); + } + template <> + inline void xml_oarchive_impl::save(std::basic_string, std::allocator> const &s) + { + Q_UNUSED(s); + qAssert(false); + } + } +} // namespace boost::archive +#endif // _QX_USE_SERIALIZE_POLYMORPHIC_PATCH + +#endif // (! _QX_BUILDING_QX_ORM) +#endif // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#endif // _QX_EXPORT_DLL_BOOST_ARCHIVE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxExportDllMacroCpp.h b/include/QxSerialize/boost/QxExportDllMacroCpp.h new file mode 100644 index 0000000..8eacd98 --- /dev/null +++ b/include/QxSerialize/boost/QxExportDllMacroCpp.h @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_EXPORT_DLL_MACRO_CPP_H_ +#define _QX_EXPORT_DLL_MACRO_CPP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#if _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#if (BOOST_VERSION < 106600) +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::pointer_iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::pointer_oserializer, ArchiveOut, T) +#else // (BOOST_VERSION < 106600) +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, T) +#endif // (BOOST_VERSION < 106600) + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, QX_BOOST_132_SHARED_PTR_HELPER(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::pointer_iserializer, ArchiveIn, QX_BOOST_132_SHARED_PTR_HELPER(T)) +#else // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, QX_BOOST_132_SHARED_PTR_HELPER(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::pointer_oserializer, ArchiveOut, QX_BOOST_132_SHARED_PTR_HELPER(T)) +#else // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_ISERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::iserializer, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_OSERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::archive::detail::oserializer, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::oserializer, ArchiveOut, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_EXTENDED_TYPE_ID_CPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::serialization::extended_type_info_typeid, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::serialization::extended_type_info_typeid, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_VOID_CAST_PRIMITIVE_CPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(class, boost::serialization::void_cast_detail::void_caster_primitive, T, QX_GET_BASE_CLASS_2(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::serialization::void_cast_detail::void_caster_primitive, T, QX_GET_BASE_CLASS_2(T)) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_TYPE_INFO_IMPL_CPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::serialization::type_info_implementation, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::serialization::type_info_implementation, T) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::save_pointer_type, ArchiveOut, T *) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::save_pointer_type, ArchiveOut, T *) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_NON_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::save_non_pointer_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::save_non_pointer_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_NON_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ENUM_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::save_enum_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::save_enum_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ENUM_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ARRAY_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::save_array_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::save_array_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ARRAY_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::load_pointer_type, ArchiveIn, T *) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::load_pointer_type, ArchiveIn, T *) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_NON_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::load_non_pointer_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::load_non_pointer_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_NON_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ENUM_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::load_enum_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::load_enum_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ENUM_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ARRAY_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_CPP(struct, boost::archive::detail::load_array_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_CPP(class, boost::serialization::singleton, boost::archive::detail::load_array_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ARRAY_TYPE_CPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_ISERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_OSERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_CPP(ArchiveIn, ArchiveOut, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_EXTENDED_TYPE_ID_CPP(T) \ + /* \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_VOID_CAST_PRIMITIVE_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_TYPE_INFO_IMPL_CPP(T) \ + */ + +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive, T) +#else // _QX_SERIALIZE_POLYMORPHIC +#define QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive, T) +#else // _QX_SERIALIZE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_BINARY_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_TEXT_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::text_iarchive, boost::archive::text_oarchive, T) +#else // _QX_SERIALIZE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_TEXT_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_XML_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive, T) +#else // _QX_SERIALIZE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_XML_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(eos::portable_iarchive, eos::portable_oarchive, T) +#else // _QX_SERIALIZE_PORTABLE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive, T) +#else // _QX_SERIALIZE_WIDE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::text_wiarchive, boost::archive::text_woarchive, T) +#else // _QX_SERIALIZE_WIDE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_CPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive, T) +#else // _QX_SERIALIZE_WIDE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_CPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_XML + +#define QX_BOOST_EXPORT_SERIALIZATION_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_TEXT_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_XML_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_CPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_CPP(T) + +#else // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#define QX_BOOST_EXPORT_SERIALIZATION_CPP(T) /* Nothing */ + +#endif // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#endif // _QX_EXPORT_DLL_MACRO_CPP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxExportDllMacroHpp.h b/include/QxSerialize/boost/QxExportDllMacroHpp.h new file mode 100644 index 0000000..ed302a3 --- /dev/null +++ b/include/QxSerialize/boost/QxExportDllMacroHpp.h @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_EXPORT_DLL_MACRO_HPP_H_ +#define _QX_EXPORT_DLL_MACRO_HPP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include + +#include + +#if _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_132_SHARED_PTR_HELPER(T) \ + boost_132::detail::sp_counted_base_impl +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_132_SHARED_PTR_HELPER(T) \ + boost_132::detail::sp_counted_base_impl +#endif // (BOOST_VERSION >= 104100) +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#if (BOOST_VERSION < 106600) +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::pointer_iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::pointer_oserializer, ArchiveOut, T) +#else // (BOOST_VERSION < 106600) +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, T) +#endif // (BOOST_VERSION < 106600) + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_iserializer, ArchiveIn, QX_BOOST_132_SHARED_PTR_HELPER(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::pointer_iserializer, ArchiveIn, QX_BOOST_132_SHARED_PTR_HELPER(T)) +#else // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::pointer_oserializer, ArchiveOut, QX_BOOST_132_SHARED_PTR_HELPER(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::pointer_oserializer, ArchiveOut, QX_BOOST_132_SHARED_PTR_HELPER(T)) +#else // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_ISERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::iserializer, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::iserializer, ArchiveIn, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_OSERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::archive::detail::oserializer, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::oserializer, ArchiveOut, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_EXTENDED_TYPE_ID_HPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::serialization::extended_type_info_typeid, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::serialization::extended_type_info_typeid, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_VOID_CAST_PRIMITIVE_HPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(class, boost::serialization::void_cast_detail::void_caster_primitive, T, QX_GET_BASE_CLASS_2(T)) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::serialization::void_cast_detail::void_caster_primitive, T, QX_GET_BASE_CLASS_2(T)) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_TYPE_INFO_IMPL_HPP(T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(struct, boost::serialization::type_info_implementation, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_HPP(class, boost::serialization::singleton, boost::serialization::type_info_implementation, T) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::save_pointer_type, ArchiveOut, T *) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::save_pointer_type, ArchiveOut, T *) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_NON_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::save_non_pointer_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::save_non_pointer_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_NON_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ENUM_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::save_enum_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::save_enum_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ENUM_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ARRAY_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::save_array_type, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::save_array_type, ArchiveOut, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_SAVE_ARRAY_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::load_pointer_type, ArchiveIn, T *) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::load_pointer_type, ArchiveIn, T *) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_NON_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::load_non_pointer_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::load_non_pointer_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_NON_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ENUM_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::load_enum_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::load_enum_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ENUM_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#if (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ARRAY_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_P2_HPP(struct, boost::archive::detail::load_array_type, ArchiveIn, T) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_P2_HPP(class, boost::serialization::singleton, boost::archive::detail::load_array_type, ArchiveIn, T) +#else // (BOOST_VERSION < 104100) +#define QX_BOOST_EXPORT_SERIALIZATION_LOAD_ARRAY_TYPE_HPP(ArchiveIn, ArchiveOut, T) /* Nothing */ +#endif // (BOOST_VERSION < 104100) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_ISERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_OSERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_ISERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_POINTER_OSERIALIZER_BOOST_132_HELPER_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_SAVE_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) \ + QX_BOOST_EXPORT_SERIALIZATION_LOAD_POINTER_TYPE_HPP(ArchiveIn, ArchiveOut, T) + +#define QX_BOOST_EXPORT_SERIALIZATION_IMPL_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_EXTENDED_TYPE_ID_HPP(T) \ + /* \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_VOID_CAST_PRIMITIVE_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_TYPE_INFO_IMPL_HPP(T) \ + */ + +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive, T) +#else // _QX_SERIALIZE_POLYMORPHIC +#define QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive, T) +#else // _QX_SERIALIZE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_BINARY_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_TEXT_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive, T) +#else // _QX_SERIALIZE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_TEXT_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_XML_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive, T) +#else // _QX_SERIALIZE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_XML_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(eos::portable_iarchive, eos::portable_oarchive, T) +#else // _QX_SERIALIZE_PORTABLE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive, T) +#else // _QX_SERIALIZE_WIDE_BINARY +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive, T) +#else // _QX_SERIALIZE_WIDE_TEXT +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_WITH_ARCHIVE_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive, T) +#else // _QX_SERIALIZE_WIDE_XML +#define QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_HPP(T) /* Nothing */ +#endif // _QX_SERIALIZE_WIDE_XML + +#define QX_BOOST_EXPORT_SERIALIZATION_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_IMPL_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_POLYMORPHIC_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_TEXT_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_XML_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_PORTABLE_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_BINARY_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_TEXT_HPP(T) \ + QX_BOOST_EXPORT_SERIALIZATION_WIDE_XML_HPP(T) + +#else // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#define QX_BOOST_EXPORT_SERIALIZATION_HPP(T) /* Nothing */ + +#endif // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#endif // _QX_EXPORT_DLL_MACRO_HPP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxImportDllBoostArchive.h b/include/QxSerialize/boost/QxImportDllBoostArchive.h new file mode 100644 index 0000000..cb4bc97 --- /dev/null +++ b/include/QxSerialize/boost/QxImportDllBoostArchive.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_IMPORT_DLL_BOOST_ARCHIVE_H_ +#define _QX_IMPORT_DLL_BOOST_ARCHIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#if _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#if (BOOST_VERSION > 103800) +#define QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_serializer_map, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_serializer_map, ArchiveOut) +#else // (BOOST_VERSION > 103800) +#define QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_pointer_iserializer, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_HPP(class, boost::archive::detail::archive_pointer_oserializer, ArchiveOut) +#endif // (BOOST_VERSION > 103800) + +#if _QX_SERIALIZE_POLYMORPHIC +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_WIDE_BINARY +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +QX_BOOST_IMPORT_ARCHIVE_SERIALIZER_MAP_HPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#endif // _QX_IMPORT_DLL_BOOST_ARCHIVE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxSerializeInclude.h b/include/QxSerialize/boost/QxSerializeInclude.h new file mode 100644 index 0000000..4dede56 --- /dev/null +++ b/include/QxSerialize/boost/QxSerializeInclude.h @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_INCLUDE_H_ +#define _QX_SERIALIZE_INCLUDE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4189) +#pragma warning(disable : 4996) +#endif // _MSC_VER + +#if _QX_SERIALIZE_POLYMORPHIC +#include +#include +#include +#include +#include +#include +#include +#include +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +#include +#include +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +#include +#include +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +#include +#include +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_WIDE_BINARY +#include +#include +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +#include +#include +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +#include +#include +#endif // _QX_SERIALIZE_WIDE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +#include +#include +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ +#define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ +#if (BOOST_VERSION > 103800) +#include +#else // (BOOST_VERSION > 103800) +#include +#include +#endif // (BOOST_VERSION > 103800) +#include +#include +#include +#include +#if _QX_SERIALIZE_TEXT +#include +#include +#include +#include +#endif // _QX_SERIALIZE_TEXT +#if (BOOST_VERSION > 103800) +#else // (BOOST_VERSION > 103800) +#if _QX_INCLUDE_BOOST_SERIALIZE_ARCHIVE_IMPL_IPP +#if _QX_SERIALIZE_TEXT +#include +#include +#endif // _QX_SERIALIZE_TEXT +#if _QX_SERIALIZE_XML +#include +#include +#endif // _QX_SERIALIZE_XML +#if _QX_SERIALIZE_WIDE_TEXT +#include +#include +#endif // _QX_SERIALIZE_WIDE_TEXT +#if _QX_SERIALIZE_WIDE_XML +#include +#include +#endif // _QX_SERIALIZE_WIDE_XML +#endif // _QX_INCLUDE_BOOST_SERIALIZE_ARCHIVE_IMPL_IPP +#endif // (BOOST_VERSION > 103800) +#endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#ifndef QX_DEFAULT_ARCHIVE_INPUT // && QX_DEFAULT_ARCHIVE_OUTPUT +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::polymorphic_binary_iarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::polymorphic_binary_oarchive +#elif _QX_SERIALIZE_BINARY +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::binary_iarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::binary_oarchive +#elif _QX_SERIALIZE_TEXT +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::text_iarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::text_oarchive +#elif _QX_SERIALIZE_XML +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::xml_iarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::xml_oarchive +#elif _QX_SERIALIZE_PORTABLE_BINARY +#define QX_DEFAULT_ARCHIVE_INPUT eos::portable_iarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT eos::portable_oarchive +#elif _QX_SERIALIZE_WIDE_BINARY +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::binary_wiarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::binary_woarchive +#elif _QX_SERIALIZE_WIDE_TEXT +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::text_wiarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::text_woarchive +#elif _QX_SERIALIZE_WIDE_XML +#define QX_DEFAULT_ARCHIVE_INPUT boost::archive::xml_wiarchive +#define QX_DEFAULT_ARCHIVE_OUTPUT boost::archive::xml_woarchive +#endif // _QX_SERIALIZE_BINARY +#endif // QX_DEFAULT_ARCHIVE_INPUT + +#ifndef QX_CLONE_STRING_STREAM // && QX_CLONE_BINARY_OUTPUT_ARCHIVE && QX_CLONE_BINARY_INPUT_ARCHIVE +#if _QX_SERIALIZE_POLYMORPHIC +#define QX_CLONE_STRING_STREAM std::stringstream +#define QX_CLONE_BINARY_OUTPUT_ARCHIVE boost::archive::polymorphic_binary_oarchive +#define QX_CLONE_BINARY_INPUT_ARCHIVE boost::archive::polymorphic_binary_iarchive +#elif _QX_SERIALIZE_WIDE_BINARY +#define QX_CLONE_STRING_STREAM std::wstringstream +#define QX_CLONE_BINARY_OUTPUT_ARCHIVE boost::archive::binary_woarchive +#define QX_CLONE_BINARY_INPUT_ARCHIVE boost::archive::binary_wiarchive +#elif _QX_SERIALIZE_BINARY +#define QX_CLONE_STRING_STREAM std::stringstream +#define QX_CLONE_BINARY_OUTPUT_ARCHIVE boost::archive::binary_oarchive +#define QX_CLONE_BINARY_INPUT_ARCHIVE boost::archive::binary_iarchive +#elif _QX_SERIALIZE_PORTABLE_BINARY +#define QX_CLONE_STRING_STREAM std::stringstream +#define QX_CLONE_BINARY_OUTPUT_ARCHIVE eos::portable_oarchive +#define QX_CLONE_BINARY_INPUT_ARCHIVE eos::portable_iarchive +#endif // _QX_SERIALIZE_WIDE_BINARY +#else +#define QX_CLONE_NEED_BINARY_TO_INCREASE_PERFORMANCE "qx::clone() need binary archive for best performance" +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) +#pragma message(QX_CLONE_NEED_BINARY_TO_INCREASE_PERFORMANCE) +#elif defined(__GNUC__) || defined(__HP_aCC) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +#warning QX_CLONE_NEED_BINARY_TO_INCREASE_PERFORMANCE +#endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__DMC__) +#endif // QX_CLONE_STRING_STREAM + +#endif // _QX_SERIALIZE_INCLUDE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxSerialize_shared_ptr.h b/include/QxSerialize/boost/QxSerialize_shared_ptr.h new file mode 100644 index 0000000..77c2cbf --- /dev/null +++ b/include/QxSerialize/boost/QxSerialize_shared_ptr.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_BOOST_SHARED_PTR_H_ +#define _QX_SERIALIZE_BOOST_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif // _MSC_VER + +#if _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#include +#else // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 +#ifdef BOOST_SERIALIZATION_SHARED_PTR_132_HPP +#undef BOOST_SERIALIZATION_SHARED_PTR_132_HPP +#endif // BOOST_SERIALIZATION_SHARED_PTR_132_HPP +#endif // _QX_SUPPORT_BOOST_SERIALIZE_SHARED_PTR_132 + +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_SERIALIZE_BOOST_SHARED_PTR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxSerialize_tuple.h b/include/QxSerialize/boost/QxSerialize_tuple.h new file mode 100644 index 0000000..751f344 --- /dev/null +++ b/include/QxSerialize/boost/QxSerialize_tuple.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_BOOST_TUPLE_H_ +#define _QX_SERIALIZE_BOOST_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", boost::get<5>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", boost::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", boost::get<6>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", boost::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", boost::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", boost::get<7>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", boost::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", boost::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", boost::get<7>(t)); + ar &boost::serialization::make_nvp("tuple_9", boost::get<8>(t)); + } + + template + inline void serialize(Archive &ar, boost::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", boost::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", boost::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", boost::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", boost::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", boost::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", boost::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", boost::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", boost::get<7>(t)); + ar &boost::serialization::make_nvp("tuple_9", boost::get<8>(t)); + ar &boost::serialization::make_nvp("tuple_10", boost::get<9>(t)); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_BOOST_TUPLE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxSerialize_unordered_map.h b/include/QxSerialize/boost/QxSerialize_unordered_map.h new file mode 100644 index 0000000..e8f0fc1 --- /dev/null +++ b/include/QxSerialize/boost/QxSerialize_unordered_map.h @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZATION_BOOST_UNORDERED_MAP_H_ +#define _QX_SERIALIZATION_BOOST_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace serialization + { + +#if (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_map &t, const unsigned int /* file_version */) + { + long lSize = static_cast(t.size()); + ar << boost::serialization::make_nvp("size", lSize); + + typedef typename boost::unordered_map::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + std::pair pair_key_value = std::make_pair(itr->first, itr->second); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, boost::unordered_map &t, const unsigned int /* file_version */) + { + long lSize = 0; + ar >> boost::serialization::make_nvp("size", lSize); + + t.clear(); + t.reserve(lSize); + std::pair pair_key_value; + + for (long l = 0; l < lSize; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value); + } + } + +#else // (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_map &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, boost::unordered_map &t, const unsigned int /* file_version */) + { + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_map>, + boost::serialization::stl::no_reserve_imp>>(ar, t); + } + +#endif // (BOOST_VERSION > 105700) + + template + inline void serialize(Archive &ar, boost::unordered_map &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + +#if (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_multimap &t, const unsigned int /* file_version */) + { + long lSize = static_cast(t.size()); + ar << boost::serialization::make_nvp("size", lSize); + + typedef typename boost::unordered_multimap::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + std::pair pair_key_value = std::make_pair(itr->first, itr->second); + ar << boost::serialization::make_nvp("item", pair_key_value); + } + } + + template + inline void load(Archive &ar, boost::unordered_multimap &t, const unsigned int /* file_version */) + { + long lSize = 0; + ar >> boost::serialization::make_nvp("size", lSize); + + t.clear(); + t.reserve(lSize); + std::pair pair_key_value; + + for (long l = 0; l < lSize; l++) + { + ar >> boost::serialization::make_nvp("item", pair_key_value); + t.insert(pair_key_value); + } + } + +#else // (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_multimap &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, boost::unordered_multimap &t, const unsigned int /* file_version */) + { +#if (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_map>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#else // (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_multimap>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#endif // (BOOST_VERSION >= 104200) + } + +#endif // (BOOST_VERSION > 105700) + + template + inline void serialize(Archive &ar, boost::unordered_multimap &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_SERIALIZATION_BOOST_UNORDERED_MAP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/QxSerialize_unordered_set.h b/include/QxSerialize/boost/QxSerialize_unordered_set.h new file mode 100644 index 0000000..de0ac87 --- /dev/null +++ b/include/QxSerialize/boost/QxSerialize_unordered_set.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZATION_BOOST_UNORDERED_SET_H_ +#define _QX_SERIALIZATION_BOOST_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace serialization + { + +#if (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_set &t, const unsigned int /* file_version */) + { + long lSize = static_cast(t.size()); + ar << boost::serialization::make_nvp("size", lSize); + + typedef typename boost::unordered_set::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + ar << boost::serialization::make_nvp("item", (*itr)); + } + } + + template + inline void load(Archive &ar, boost::unordered_set &t, const unsigned int /* file_version */) + { + long lSize = 0; + ar >> boost::serialization::make_nvp("size", lSize); + + t.clear(); + t.reserve(lSize); + + for (long l = 0; l < lSize; l++) + { + Key item; + ar >> boost::serialization::make_nvp("item", item); + t.insert(item); + } + } + +#else // (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_set &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, boost::unordered_set &t, const unsigned int /* file_version */) + { + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_set>, + boost::serialization::stl::no_reserve_imp>>(ar, t); + } + +#endif // (BOOST_VERSION > 105700) + + template + inline void serialize(Archive &ar, boost::unordered_set &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + +#if (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_multiset &t, const unsigned int /* file_version */) + { + long lSize = static_cast(t.size()); + ar << boost::serialization::make_nvp("size", lSize); + + typedef typename boost::unordered_multiset::const_iterator type_itr; + for (type_itr itr = t.begin(); itr != t.end(); ++itr) + { + ar << boost::serialization::make_nvp("item", (*itr)); + } + } + + template + inline void load(Archive &ar, boost::unordered_multiset &t, const unsigned int /* file_version */) + { + long lSize = 0; + ar >> boost::serialization::make_nvp("size", lSize); + + t.clear(); + t.reserve(lSize); + + for (long l = 0; l < lSize; l++) + { + Key item; + ar >> boost::serialization::make_nvp("item", item); + t.insert(item); + } + } + +#else // (BOOST_VERSION > 105700) + + template + inline void save(Archive &ar, const boost::unordered_multiset &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, boost::unordered_multiset &t, const unsigned int /* file_version */) + { +#if (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_set>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#else // (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_multiset>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#endif // (BOOST_VERSION >= 104200) + } + +#endif // (BOOST_VERSION > 105700) + + template + inline void serialize(Archive &ar, boost::unordered_multiset &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_SERIALIZATION_BOOST_UNORDERED_SET_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/class_export/qx_boost_class_export.h b/include/QxSerialize/boost/class_export/qx_boost_class_export.h new file mode 100644 index 0000000..50a3af8 --- /dev/null +++ b/include/QxSerialize/boost/class_export/qx_boost_class_export.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_BOOST_SERIALIZATION_EXPORT_HPP_ +#define _QX_BOOST_SERIALIZATION_EXPORT_HPP_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#if _QX_USE_MODIFY_BOOST_SERIALIZATION_EXPORT_HPP + +#include +#include // NULL + +#include +#include + +#ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO +#include +#endif // BOOST_SERIALIZATION_DEFAULT_TYPE_INFO + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace archive + { + namespace detail + { + + class basic_pointer_iserializer; + class basic_pointer_oserializer; + + template + class pointer_iserializer; + template + class pointer_oserializer; + + template + struct export_impl + { + static const basic_pointer_iserializer & + enable_load(mpl::true_) + { + return boost::serialization::singleton< + pointer_iserializer>::get_const_instance(); + } + + static const basic_pointer_oserializer & + enable_save(mpl::true_) + { + return boost::serialization::singleton< + pointer_oserializer>::get_const_instance(); + } + inline static void enable_load(mpl::false_) {} + inline static void enable_save(mpl::false_) {} + }; + + // On many platforms, naming a specialization of this template is + // enough to cause its argument to be instantiated. + template + struct instantiate_function + { + }; + + template + struct ptr_serialization_support + { +#if defined(BOOST_MSVC) + virtual BOOST_DLLEXPORT void instantiate() QX_USED; +#elif defined(__BORLANDC__) + static BOOST_DLLEXPORT void instantiate() QX_USED; + enum + { + x = sizeof(instantiate(), 3) + }; +#else + static BOOST_DLLEXPORT void instantiate() QX_USED; + typedef instantiate_function< + &ptr_serialization_support::instantiate> + x; +#endif + }; + + template + BOOST_DLLEXPORT void + ptr_serialization_support::instantiate() + { + export_impl::enable_save( +#if !defined(__BORLANDC__) + BOOST_DEDUCED_TYPENAME +#endif + Archive::is_saving()); + + export_impl::enable_load( +#if !defined(__BORLANDC__) + BOOST_DEDUCED_TYPENAME +#endif + Archive::is_loading()); + } + + template + struct guid_initializer + { + const guid_initializer &export_guid(char const * /* key */, mpl::false_) + { + // generates the statically-initialized objects whose constructors + // register the information allowing serialization of T objects + // through pointers to their base classes. + instantiate_ptr_serialization((T *)0, 0, adl_tag()); + return *this; + } + const guid_initializer &export_guid(char const * /*key*/, mpl::true_) + { + return *this; + } + const guid_initializer &export_guid(char const *key) + { + BOOST_STATIC_WARNING(boost::is_polymorphic::value); + assert(NULL != key); + boost::serialization::singleton< + BOOST_DEDUCED_TYPENAME + boost::serialization::type_info_implementation::type>::get_mutable_instance() + .key_register(key); + // note: exporting an abstract base class will have no effect + // and cannot be used to instantitiate serialization code + // (one might be using this in a DLL to instantiate code) + // BOOST_STATIC_WARNING(! boost::serialization::is_abstract::value); + return export_guid(key, boost::serialization::is_abstract()); + } + }; + + } // namespace detail + } // namespace archive +} // namespace boost + +#define BOOST_CLASS_EXPORT_GUID(T, K) \ + namespace \ + { \ + ::boost::archive::detail::guid_initializer const & \ + boost_serialization_guid_initializer_##T = ::boost::serialization::singleton< \ + ::boost::archive::detail::guid_initializer>::get_mutable_instance() \ + .export_guid(K); \ + } + +// check for unnecessary export. T isn't polymorphic so there is no +// need to export it. +#define BOOST_CLASS_EXPORT_CHECK(T) \ + BOOST_STATIC_WARNING( \ + boost::is_polymorphic::value); \ + /**/ + +// the default exportable class identifier is the class name +// the default list of archives types for which code id generated +// are the originally included with this serialization system +#define BOOST_CLASS_EXPORT(T) \ + BOOST_CLASS_EXPORT_GUID( \ + T, \ + BOOST_PP_STRINGIZE(T) ) \ + /**/ + +#endif // _QX_USE_MODIFY_BOOST_SERIALIZATION_EXPORT_HPP +#endif // _QX_BOOST_SERIALIZATION_EXPORT_HPP_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/portable_binary/portable_archive_exception.hpp b/include/QxSerialize/boost/portable_binary/portable_archive_exception.hpp new file mode 100644 index 0000000..bb0d352 --- /dev/null +++ b/include/QxSerialize/boost/portable_binary/portable_archive_exception.hpp @@ -0,0 +1,104 @@ +/*****************************************************************************/ +/** + * \file portable_archive_exception.hpp + * \brief Provides error handling and constants. + * \author christian.pfligersdorffer@gmx.at + * + * Portable archive exceptions derive from the boost archive exceptions + * and add failure causes specific to the portable binary usecase. + * + * Additionally this header serves as common include for important + * constants or typedefs. + */ +/****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_PORTABLE_BINARY +#ifndef _QX_PORTABLE_ARCHIVE_EXCEPTION_H_ +#define _QX_PORTABLE_ARCHIVE_EXCEPTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif // _MSC_VER + +#include +#include +#include + +namespace eos { + + // this value is written to the top of the stream + const signed char magic_byte = 'e' | 'o' | 's'; + + // flag for fp serialization + const unsigned no_infnan = 64; + + // integral type for the archive version + #if BOOST_VERSION < 104400 + typedef boost::archive::version_type archive_version_type; + #else + typedef boost::archive::library_version_type archive_version_type; + #endif + + // version of the linked boost archive library + const archive_version_type archive_version( + #if BOOST_VERSION < 103700 + boost::archive::ARCHIVE_VERSION() + #else + boost::archive::BOOST_ARCHIVE_VERSION() + #endif + ); + + /** + * \brief Exception being thrown when serialization cannot proceed. + * + * There are several situations in which the portable archives may fail and + * hence throw an exception: + * -# deserialization of an integer value that exceeds the range of the type + * -# (de)serialization of inf/nan through an archive with no_infnan flag set + * -# deserialization of a denormalized value without the floating point type + * supporting denormalized numbers + * + * Note that this exception will also be thrown if you mixed up your stream + * position and accidentially interpret some value for size data (in this case + * the reported size will be totally amiss most of the time). + */ + class portable_archive_exception : public boost::archive::archive_exception + { + std::string msg; + + public: + //! type size is not large enough for deserialized number + portable_archive_exception(signed char invalid_size) + : boost::archive::archive_exception(other_exception) + , msg("requested integer size exceeds type size: ") + { + msg += boost::lexical_cast(invalid_size); + } + + //! negative number in unsigned type + portable_archive_exception() + : boost::archive::archive_exception(other_exception) + , msg("cannot read a negative number into an unsigned type") + { + } + + //! serialization of inf, nan and denormals + template + portable_archive_exception(const T& abnormal) + : boost::archive::archive_exception(other_exception) + , msg("serialization of illegal floating point value: ") + { + msg += boost::lexical_cast(abnormal); + } + + //! override the base class function with our message + const char* what() const throw() { return msg.c_str(); } + ~portable_archive_exception() throw() {} + }; + +} // namespace eos + +#endif // _QX_PORTABLE_ARCHIVE_EXCEPTION_H_ +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/portable_binary/portable_iarchive.hpp b/include/QxSerialize/boost/portable_binary/portable_iarchive.hpp new file mode 100644 index 0000000..fce4296 --- /dev/null +++ b/include/QxSerialize/boost/portable_binary/portable_iarchive.hpp @@ -0,0 +1,505 @@ +/*****************************************************************************/ +/** + * \file portable_iarchive.hpp + * \brief Provides an archive to read from portable binary files. + * \author christian.pfligersdorffer@gmx.at + * \version 5.1 + * + * This pair of archives brings the advantages of binary streams to the cross + * platform boost::serialization user. While being almost as fast as the native + * binary archive it allows its files to be exchanged between cpu architectures + * using different byte order (endianness). Speaking of speed: in serializing + * numbers the (portable) binary approach is approximately ten times faster than + * the ascii implementation (that is inherently portable)! + * + * Based on the portable archive example by Robert Ramey this implementation + * uses Beman Dawes endian library and fp_utilities from Johan Rade, both being + * in boost since 1.36. Prior to that you need to add them both (header only) + * to your boost directory before you're able to use the archives provided. + * Our archives have been tested successfully for boost versions 1.33 to 1.49! + * + * \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32 + * and x86-64 platforms featuring different byte order. So there is a good + * chance it will instantly work for your specific setup. If you encounter + * problems or have suggestions please contact the author. + * + * \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to + * ecotax for pointing to the issue with shared_ptr_helper. + * + * \note Version 5.0 is now compatible with boost up to version 1.49 and enables + * serialization of std::wstring by converting it to/from utf8 (thanks to + * Arash Abghari for this suggestion). With that all unit tests from the + * serialization library pass again with the notable exception of user + * defined primitive types. Those are not supported and as a result any + * user defined type to be used with the portable archives are required + * to be at least object_serializable. + * + * \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds + * serialization of special floating point values inf and NaN as proposed + * by Francois Mauger. + * + * \note Version 4.1 makes the archives work together with boost 1.40 and 1.41. + * Thanks to Francois Mauger for his suggestions. + * + * \note Version 4 removes one level of the inheritance hierarchy and directly + * builds upon binary primitive and basic binary archive, thereby fixing + * the last open issue regarding array serialization. Thanks to Robert + * Ramey for the hint. + * + * \note A few fixes introduced in version 3.1 let the archives pass all of the + * serialization tests. Thanks to Sergey Morozov for running the tests. + * Wouter Bijlsma pointed out where to find the fp_utilities and endian + * libraries headers inside the boost distribution. I would never have + * found them so thank him it works out of the box since boost 1.36. + * + * \note With Version 3.0 the archives have been made portable across different + * boost versions. For that purpose a header is added to the data that + * supplies the underlying serialization library version. Backwards + * compatibility is maintained by assuming library version boost 1.33 if + * the iarchive is created using the no_header flag. Whether a header is + * present or not can be guessed by peeking into the stream: the header's + * first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-) + * + * \note Version 2.1 removes several compiler warnings and enhances floating + * point diagnostics to inform the user if some preconditions are violated + * on his platform. We do not strive for the universally portable solution + * in binary floating point serialization as desired by some boost users. + * Instead we support only the most widely used IEEE 754 format and try to + * detect when requirements are not met and hence our approach must fail. + * Contributions we made by Johan Rade and kos Mary. + * + * \note Version 2.0 fixes a serious bug that effectively transformed most + * of negative integral values into positive values! For example the two + * numbers -12 and 234 were stored in the same 8-bit pattern and later + * always restored to 234. This was fixed in this version in a way that + * does not change the interpretation of existing archives that did work + * because there were no negative numbers. The other way round archives + * created by version 2.0 and containing negative numbers will raise an + * integer type size exception when reading it with version 1.0. Thanks + * to Markus Frohnmaier for testing the archives and finding the bug. + * + * \copyright The boost software license applies. + */ +/*****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_PORTABLE_BINARY +#ifndef _QX_PORTABLE_BINARY_IARCHIVE_H_ +#define _QX_PORTABLE_BINARY_IARCHIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif // _MSC_VER + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#pragma warning(disable:4661) +#endif // _MSC_VER + +#include + +// basic headers +#include +#include +#include +#include + +#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 +#include +#endif + +// endian and fpclassify +#if BOOST_VERSION < 103600 +#include +#include +#elif BOOST_VERSION < 104800 +#include +#include +#else +#include +#include +#endif + +// namespace alias +#if BOOST_VERSION < 103800 +namespace fp = boost::math; +#else +namespace fp = boost::spirit::math; +#endif + +// namespace alias endian +#if BOOST_VERSION < 104800 +namespace endian = boost::detail; +#else +namespace endian = boost::spirit::detail; +#endif + +#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING +// used for wstring to utf8 conversion +#include +#include +#endif + +// generic type traits for numeric types +#include +#include +#include +#include + +#include "portable_archive_exception.hpp" + +// hint from Johan Rade: on VMS there is still support for +// the VAX floating point format and this macro detects it +#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT +#error "VAX floating point format is not supported!" +#endif + +namespace eos { + + // forward declaration + class portable_iarchive; + + typedef boost::archive::basic_binary_iprimitive< + portable_iarchive + #if BOOST_VERSION < 103400 + , std::istream + #else + , std::istream::char_type + , std::istream::traits_type + #endif + > portable_iprimitive; + + /** + * \brief Portable binary input archive using little endian format. + * + * This archive addresses integer size, endianness and floating point types so + * that data can be transferred across different systems. There may still be + * constraints as to what systems are compatible and the user will have to take + * care that e.g. a very large int being saved on a 64 bit machine will result + * in a portable_archive_exception if loaded into an int on a 32 bit system. + * A possible workaround to this would be to use fixed types like + * boost::uint64_t in your serialization structures. + * + * \note The class is based on the portable binary example by Robert Ramey and + * uses Beman Dawes endian library plus fp_utilities by Johan Rade. + */ + class portable_iarchive : public portable_iprimitive + + // the example derives from common_oarchive but that lacks the + // load_override functions so we chose to stay one level higher + , public boost::archive::basic_binary_iarchive + + #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 + // mix-in helper class for serializing shared_ptr + , public boost::archive::detail::shared_ptr_helper + #endif + { + // only needed for Robert's hack in basic_binary_iarchive::init + friend class boost::archive::basic_binary_iarchive; + + // workaround for gcc: use a dummy struct + // as additional argument type for overloading + template struct dummy { dummy(int) {}}; + + // loads directly from stream + inline signed char load_signed_char() + { + signed char c; + portable_iprimitive::load(c); + return c; + } + + // archive initialization + void init(unsigned flags) + { + using namespace boost::archive; + archive_version_type input_library_version(3); + + // it is vital to have version information! + // if we don't have any we assume boost 1.33 + if (flags & no_header) + set_library_version(input_library_version); + + // extract and check the magic eos byte + else if (load_signed_char() != magic_byte) + throw archive_exception(archive_exception::invalid_signature); + + else + { + // extract version information + operator>>(input_library_version); + + // throw if file version is newer than we are + if (input_library_version > archive_version) + throw archive_exception(archive_exception::unsupported_version); + + // else set the library version accordingly + else set_library_version(input_library_version); + } + } + + public: + /** + * \brief Constructor on a stream using ios::binary mode! + * + * We cannot call basic_binary_iprimitive::init which tries to detect + * if the binary archive stems from a different platform by examining + * type sizes. + * + * We could have called basic_binary_iarchive::init which would create + * the boost::serialization standard archive header containing also the + * library version. Due to efficiency we stick with our own. + */ + portable_iarchive(std::istream& is, unsigned flags = 0) + #if BOOST_VERSION < 103400 + : portable_iprimitive(is, flags & boost::archive::no_codecvt) + #else + : portable_iprimitive(*is.rdbuf(), flags & boost::archive::no_codecvt) + #endif + , boost::archive::basic_binary_iarchive(flags) + { + init(flags); + } + + #if BOOST_VERSION >= 103400 + portable_iarchive(std::streambuf& sb, unsigned flags = 0) + : portable_iprimitive(sb, flags & boost::archive::no_codecvt) + , boost::archive::basic_binary_iarchive(flags) + { + init(flags); + } + #endif + + //! Load narrow strings. + void load(std::string& s) + { + portable_iprimitive::load(s); + } + + #ifndef BOOST_NO_STD_WSTRING + /** + * \brief Load wide strings. + * + * This is rather tricky to get right for true portability as there + * are so many different character encodings around. However, wide + * strings that are encoded in one of the Unicode schemes only need + * to be _transcoded_ which is a lot easier actually. + * + * We generate the output string to be encoded in the system's native + * format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't + * know about Mac here so I can't really say about that. + */ + void load(std::wstring& s) + { + std::string utf8; + load(utf8); + s = boost::from_utf8(utf8); + } + #endif + + /** + * \brief Loading bool type. + * + * Byte pattern is same as with integer types, so this function + * is somewhat redundant but treating bool as integer generates + * a lot of compiler warnings. + * + * \note If you cannot compile your application and it says something + * about load(bool) cannot convert your type A& into bool& then you + * should check your BOOST_CLASS_IMPLEMENTATION setting for A, as + * portable_archive is not able to handle custom primitive types in + * a general manner. + */ + void load(bool& b) + { + switch (signed char c = load_signed_char()) + { + case 0: b = false; break; + case 1: b = load_signed_char(); break; + default: throw portable_archive_exception(c); + } + } + + /** + * \brief Load integer types. + * + * First we load the size information ie. the number of bytes that + * hold the actual data. Then we retrieve the data and transform it + * to the original value by using load_little_endian. + */ + template + typename boost::enable_if >::type + load(T & t, dummy<2> = 0) + { + // get the number of bytes in the stream + if (signed char size = load_signed_char()) + { + // check for negative value in unsigned type + if (size < 0 && boost::is_unsigned::value) + throw portable_archive_exception(); + + // check that our type T is large enough + else if ((unsigned) abs(size) > sizeof(T)) + throw portable_archive_exception(size); + + // reconstruct the value + T temp = size < 0 ? -1 : 0; + load_binary(&temp, abs(size)); + + // load the value from little endian - it is then converted + // to the target type T and fits it because size <= sizeof(T) + t = endian::load_little_endian(&temp); + } + + else t = 0; // zero optimization + } + + /** + * \brief Load floating point types. + * + * We simply rely on fp_traits to set the bit pattern from the (unsigned) + * integral type that was stored in the stream. Francois Mauger provided + * standardized behaviour for special values like inf and NaN, that need to + * be serialized in his application. + * + * \note by Johan Rade (author of the floating point utilities library): + * Be warned that the math::detail::fp_traits::type::get_bits() function + * is *not* guaranteed to give you all bits of the floating point number. It + * will give you all bits if and only if there is an integer type that has + * the same size as the floating point you are copying from. It will not + * give you all bits for double if there is no uint64_t. It will not give + * you all bits for long double if sizeof(long double) > 8 or there is no + * uint64_t. + * + * The member fp_traits::type::coverage will tell you whether all bits + * are copied. This is a typedef for either math::detail::all_bits or + * math::detail::not_all_bits. + * + * If the function does not copy all bits, then it will copy the most + * significant bits. So if you serialize and deserialize the way you + * describe, and fp_traits::type::coverage is math::detail::not_all_bits, + * then your floating point numbers will be truncated. This will introduce + * small rounding off errors. + */ + template + typename boost::enable_if >::type + load(T & t, dummy<3> = 0) + { + typedef typename fp::detail::fp_traits::type traits; + + // if you end here there are three possibilities: + // 1. you're serializing a long double which is not portable + // 2. you're serializing a double but have no 64 bit integer + // 3. your machine is using an unknown floating point format + // after reading the note above you still might decide to + // deactivate this static assert and try if it works out. + typename traits::bits bits; + BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_iec559); + + load(bits); + traits::set_bits(t, bits); + + // if the no_infnan flag is set we must throw here + if (get_flags() & no_infnan && !fp::isfinite(t)) + throw portable_archive_exception(t); + + // if you end here your floating point type does not support + // denormalized numbers. this might be the case even though + // your type conforms to IEC 559 (and thus to IEEE 754) + if (std::numeric_limits::has_denorm == std::denorm_absent + && fp::fpclassify(t) == (int) FP_SUBNORMAL) // GCC4 + throw portable_archive_exception(t); + } + + // in boost 1.44 version_type was splitted into library_version_type and + // item_version_type, plus a whole bunch of additional strong typedefs. + template + typename boost::disable_if >::type + load(T& t, dummy<4> = 0) + { + // we provide a generic load routine for all types that feature + // conversion operators into an unsigned integer value like those + // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like + // library_version_type, collection_size_type, item_version_type, + // class_id_type, object_id_type, version_type and tracking_type + load((typename boost::uint_t::least&)(t)); + } + }; + +} // namespace eos + +// this is required by export which registers all of your +// classes with all the inbuilt archives plus our archive. +#if BOOST_VERSION < 103500 +#define BOOST_ARCHIVE_CUSTOM_IARCHIVE_TYPES eos::portable_iarchive +#else +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_iarchive) +#endif + +// if you include this header multiple times and your compiler is picky +// about multiple template instantiations (eg. gcc is) then you need to +// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one +// or you move the instantiation section into an implementation file +#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ +#define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ + +#include +#include +#include +#include + +#if _QX_SERIALIZE_TEXT +#include +#include +#include +#include +#endif // _QX_SERIALIZE_TEXT + +#if (BOOST_VERSION < 104000) +#include +#include +#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED +#include +#define BOOST_ARCHIVE_SERIALIZER_INCLUDED +#endif // (BOOST_VERSION < 104000) + +#endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ + +namespace boost { namespace archive { + + // explicitly instantiate for this type of binary stream + template class basic_binary_iarchive; + + template class basic_binary_iprimitive< + eos::portable_iarchive + #if BOOST_VERSION < 103400 + , std::istream + #else + , std::istream::char_type + , std::istream::traits_type + #endif + >; + +#if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) +#if (BOOST_VERSION < 104000) + template class detail::archive_pointer_iserializer; +#else // (BOOST_VERSION < 104000) + template class detail::archive_serializer_map; +#endif // (BOOST_VERSION < 104000) +#endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) + +} } // namespace boost::archive + +#endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_PORTABLE_BINARY_IARCHIVE_H_ +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/boost/portable_binary/portable_oarchive.hpp b/include/QxSerialize/boost/portable_binary/portable_oarchive.hpp new file mode 100644 index 0000000..2dad52a --- /dev/null +++ b/include/QxSerialize/boost/portable_binary/portable_oarchive.hpp @@ -0,0 +1,488 @@ +/*****************************************************************************/ +/** + * \file portable_oarchive.hpp + * \brief Provides an archive to create portable binary files. + * \author christian.pfligersdorffer@gmx.at + * \version 5.1 + * + * This pair of archives brings the advantages of binary streams to the cross + * platform boost::serialization user. While being almost as fast as the native + * binary archive it allows its files to be exchanged between cpu architectures + * using different byte order (endianness). Speaking of speed: in serializing + * numbers the (portable) binary approach is approximately ten times faster than + * the ascii implementation (that is inherently portable)! + * + * Based on the portable archive example by Robert Ramey this implementation + * uses Beman Dawes endian library and fp_utilities from Johan Rade, both being + * in boost since 1.36. Prior to that you need to add them both (header only) + * to your boost directory before you're able to use the archives provided. + * Our archives have been tested successfully for boost versions 1.33 to 1.49! + * + * \note Correct behaviour has so far been confirmed using PowerPC-32, x86-32 + * and x86-64 platforms featuring different byte order. So there is a good + * chance it will instantly work for your specific setup. If you encounter + * problems or have suggestions please contact the author. + * + * \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to + * ecotax for pointing to the issue with shared_ptr_helper. + * + * \note Version 5.0 is now compatible with boost up to version 1.49 and enables + * serialization of std::wstring by converting it to/from utf8 (thanks to + * Arash Abghari for this suggestion). With that all unit tests from the + * serialization library pass again with the notable exception of user + * defined primitive types. Those are not supported and as a result any + * user defined type to be used with the portable archives are required + * to be at least object_serializable. + * + * \note Oliver Putz pointed out that -0.0 was not serialized correctly, so + * version 4.3 provides a fix for that. Thanks Ollie! + * + * \note Version 4.2 maintains compatibility with the latest boost 1.45 and adds + * serialization of special floating point values inf and NaN as proposed + * by Francois Mauger. + * + * \note Version 4.1 makes the archives work together with boost 1.40 and 1.41. + * Thanks to Francois Mauger for his suggestions. + * + * \note Version 4 removes one level of the inheritance hierarchy and directly + * builds upon binary primitive and basic binary archive, thereby fixing + * the last open issue regarding array serialization. Thanks to Robert + * Ramey for the hint. + * + * \note A few fixes introduced in version 3.1 let the archives pass all of the + * serialization tests. Thanks to Sergey Morozov for running the tests. + * Wouter Bijlsma pointed out where to find the fp_utilities and endian + * libraries headers inside the boost distribution. I would never have + * found them so thank him it works out of the box since boost 1.36. + * + * \note With Version 3.0 the archives have been made portable across different + * boost versions. For that purpose a header is added to the data that + * supplies the underlying serialization library version. Backwards + * compatibility is maintained by assuming library version boost 1.33 if + * the iarchive is created using the no_header flag. Whether a header is + * present or not can be guessed by peeking into the stream: the header's + * first byte is the magic number 127 coinciding with 'e'|'o'|'s' :-) + * + * \note Version 2.1 removes several compiler warnings and enhances floating + * point diagnostics to inform the user if some preconditions are violated + * on his platform. We do not strive for the universally portable solution + * in binary floating point serialization as desired by some boost users. + * Instead we support only the most widely used IEEE 754 format and try to + * detect when requirements are not met and hence our approach must fail. + * Contributions we made by Johan Rade and kos Mary. + * + * \note Version 2.0 fixes a serious bug that effectively transformed most + * of negative integral values into positive values! For example the two + * numbers -12 and 234 were stored in the same 8-bit pattern and later + * always restored to 234. This was fixed in this version in a way that + * does not change the interpretation of existing archives that did work + * because there were no negative numbers. The other way round archives + * created by version 2.0 and containing negative numbers will raise an + * integer type size exception when reading it with version 1.0. Thanks + * to Markus Frohnmaier for testing the archives and finding the bug. + * + * \copyright The boost software license applies. + */ +/*****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#if _QX_SERIALIZE_PORTABLE_BINARY +#ifndef _QX_PORTABLE_BINARY_OARCHIVE_H_ +#define _QX_PORTABLE_BINARY_OARCHIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif // _MSC_VER + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4996) +#pragma warning(disable:4661) +#endif // _MSC_VER + +#include + +// basic headers +#include +#include +#include +#include + +#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 +#include +#endif + +// endian and fpclassify +#if BOOST_VERSION < 103600 +#include +#include +#elif BOOST_VERSION < 104800 +#include +#include +#else +#include +#include +#endif + +// namespace alias fp_classify +#if BOOST_VERSION < 103800 +namespace fp = boost::math; +#else +namespace fp = boost::spirit::math; +#endif + +// namespace alias endian +#if BOOST_VERSION < 104800 +namespace endian = boost::detail; +#else +namespace endian = boost::spirit::detail; +#endif + +#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING +// used for wstring to utf8 conversion +#include +#include +#endif + +// generic type traits for numeric types +#include +#include +#include +#include + +#include "portable_archive_exception.hpp" + +// hint from Johan Rade: on VMS there is still support for +// the VAX floating point format and this macro detects it +#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT +#error "VAX floating point format is not supported!" +#endif + +namespace eos { + + // forward declaration + class portable_oarchive; + + typedef boost::archive::basic_binary_oprimitive< + portable_oarchive + #if BOOST_VERSION < 103400 + , std::ostream + #else + , std::ostream::char_type + , std::ostream::traits_type + #endif + > portable_oprimitive; + + /** + * \brief Portable binary output archive using little endian format. + * + * This archive addresses integer size, endianness and floating point types so + * that data can be transferred across different systems. The archive consists + * primarily of three different save implementations for integral types, + * floating point types and string types. Those functions are templates and use + * enable_if to be correctly selected for overloading. + * + * \note The class is based on the portable binary example by Robert Ramey and + * uses Beman Dawes endian library plus fp_utilities by Johan Rade. + */ + class portable_oarchive : public portable_oprimitive + + // the example derives from common_oarchive but that lacks the + // save_override functions so we chose to stay one level higher + , public boost::archive::basic_binary_oarchive + + #if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600 + // mix-in helper class for serializing shared_ptr + , public boost::archive::detail::shared_ptr_helper + #endif + { + // workaround for gcc: use a dummy struct + // as additional argument type for overloading + template struct dummy { dummy(int) {}}; + + // stores a signed char directly to stream + inline void save_signed_char(const signed char& c) + { + portable_oprimitive::save(c); + } + + // archive initialization + void init(unsigned flags) + { + // it is vital to have version information if the archive is + // to be parsed with a newer version of boost::serialization + // therefor we create a header, no header means boost 1.33 + if (flags & boost::archive::no_header) + BOOST_ASSERT(archive_version == 3); + else + { + // write our minimalistic header (magic byte plus version) + // the boost archives write a string instead - by calling + // boost::archive::basic_binary_oarchive::init() + save_signed_char(magic_byte); + + // write current version +// save(archive_version); + operator<<(archive_version); + } + } + + public: + /** + * \brief Constructor on a stream using ios::binary mode! + * + * We cannot call basic_binary_oprimitive::init which stores type + * sizes to the archive in order to detect transfers to non-compatible + * platforms. + * + * We could have called basic_binary_oarchive::init which would create + * the boost::serialization standard archive header containing also the + * library version. Due to efficiency we stick with our own. + */ + portable_oarchive(std::ostream& os, unsigned flags = 0) + #if BOOST_VERSION < 103400 + : portable_oprimitive(os, flags & boost::archive::no_codecvt) + #else + : portable_oprimitive(*os.rdbuf(), flags & boost::archive::no_codecvt) + #endif + , boost::archive::basic_binary_oarchive(flags) + { + init(flags); + } + + #if BOOST_VERSION >= 103400 + portable_oarchive(std::streambuf& sb, unsigned flags = 0) + : portable_oprimitive(sb, flags & boost::archive::no_codecvt) + , boost::archive::basic_binary_oarchive(flags) + { + init(flags); + } + #endif + + //! Save narrow strings. + void save(const std::string& s) + { + portable_oprimitive::save(s); + } + + #ifndef BOOST_NO_STD_WSTRING + /** + * \brief Save wide strings. + * + * This is rather tricky to get right for true portability as there + * are so many different character encodings around. However, wide + * strings that are encoded in one of the Unicode schemes only need + * to be _transcoded_ which is a lot easier actually. + * + * We expect the input string to be encoded in the system's native + * format, ie. UTF-16 on Windows and UTF-32 on Linux machines. Don't + * know about Mac here so I can't really say about that. + */ + void save(const std::wstring& s) + { + save(boost::to_utf8(s)); + } + #endif + + /** + * \brief Saving bool type. + * + * Saving bool directly, not by const reference + * because of tracking_type's operator (bool). + * + * \note If you cannot compile your application and it says something + * about save(bool) cannot convert your type const A& into bool then + * you should check your BOOST_CLASS_IMPLEMENTATION setting for A, as + * portable_archive is not able to handle custom primitive types in + * a general manner. + */ + void save(const bool& b) + { + save_signed_char(b); + if (b) save_signed_char('T'); + } + + /** + * \brief Save integer types. + * + * First we save the size information ie. the number of bytes that hold the + * actual data. We subsequently transform the data using store_little_endian + * and store non-zero bytes to the stream. + */ + template + typename boost::enable_if >::type + save(const T & t, dummy<2> = 0) + { + if (T temp = t) + { + // examine the number of bytes + // needed to represent the number + signed char size = 0; + do { temp >>= CHAR_BIT; ++size; } + while (temp != 0 && temp != (T) -1); + + // encode the sign bit into the size + save_signed_char(t > 0 ? size : -size); + BOOST_ASSERT(t > 0 || boost::is_signed::value); + + // we choose to use little endian because this way we just + // save the first size bytes to the stream and skip the rest + endian::store_little_endian(&temp, t); + + save_binary(&temp, size); + } + // zero optimization + else save_signed_char(0); + } + + /** + * \brief Save floating point types. + * + * We simply rely on fp_traits to extract the bit pattern into an (unsigned) + * integral type and store that into the stream. Francois Mauger provided + * standardized behaviour for special values like inf and NaN, that need to + * be serialized in his application. + * + * \note by Johan Rade (author of the floating point utilities library): + * Be warned that the math::detail::fp_traits::type::get_bits() function + * is *not* guaranteed to give you all bits of the floating point number. It + * will give you all bits if and only if there is an integer type that has + * the same size as the floating point you are copying from. It will not + * give you all bits for double if there is no uint64_t. It will not give + * you all bits for long double if sizeof(long double) > 8 or there is no + * uint64_t. + * + * The member fp_traits::type::coverage will tell you whether all bits + * are copied. This is a typedef for either math::detail::all_bits or + * math::detail::not_all_bits. + * + * If the function does not copy all bits, then it will copy the most + * significant bits. So if you serialize and deserialize the way you + * describe, and fp_traits::type::coverage is math::detail::not_all_bits, + * then your floating point numbers will be truncated. This will introduce + * small rounding off errors. + */ + template + typename boost::enable_if >::type + save(const T & t, dummy<3> = 0) + { + typedef typename fp::detail::fp_traits::type traits; + + // if the no_infnan flag is set we must throw here + if (get_flags() & no_infnan && !fp::isfinite(t)) + throw portable_archive_exception(t); + + // if you end here there are three possibilities: + // 1. you're serializing a long double which is not portable + // 2. you're serializing a double but have no 64 bit integer + // 3. your machine is using an unknown floating point format + // after reading the note above you still might decide to + // deactivate this static assert and try if it works out. + typename traits::bits bits; + BOOST_STATIC_ASSERT(sizeof(bits) == sizeof(T)); + BOOST_STATIC_ASSERT(std::numeric_limits::is_iec559); + + // examine value closely + switch (fp::fpclassify(t)) + { + //case FP_ZERO: bits = 0; break; + case FP_NAN: bits = traits::exponent | traits::mantissa; break; + case FP_INFINITE: bits = traits::exponent | (t<0) * traits::sign; break; + case FP_SUBNORMAL: assert(std::numeric_limits::has_denorm); // pass + case FP_ZERO: // note that floats can be 0.0 + case FP_NORMAL: traits::get_bits(t, bits); break; + default: throw portable_archive_exception(t); + } + + save(bits); + } + + // in boost 1.44 version_type was splitted into library_version_type and + // item_version_type, plus a whole bunch of additional strong typedefs. + template + typename boost::disable_if >::type + save(const T& t, dummy<4> = 0) + { + // we provide a generic save routine for all types that feature + // conversion operators into an unsigned integer value like those + // created through BOOST_STRONG_TYPEDEF(X, some unsigned int) like + // library_version_type, collection_size_type, item_version_type, + // class_id_type, object_id_type, version_type and tracking_type + save((typename boost::uint_t::least)(t)); + } + }; + +} // namespace eos + +// required by export +#if BOOST_VERSION < 103500 +#define BOOST_ARCHIVE_CUSTOM_OARCHIVE_TYPES eos::portable_oarchive +#else +BOOST_SERIALIZATION_REGISTER_ARCHIVE(eos::portable_oarchive) +#endif + +// if you include this header multiple times and your compiler is picky +// about multiple template instantiations (eg. gcc is) then you need to +// define NO_EXPLICIT_TEMPLATE_INSTANTIATION before every include but one +// or you move the instantiation section into an implementation file +#ifndef NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#ifndef _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ +#define _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ + +#include +#include +#include +#include + +#if _QX_SERIALIZE_TEXT +#include +#include +#include +#include +#endif // _QX_SERIALIZE_TEXT + +#if (BOOST_VERSION < 104000) +#include +#include +#elif !defined BOOST_ARCHIVE_SERIALIZER_INCLUDED +#include +#define BOOST_ARCHIVE_SERIALIZER_INCLUDED +#endif // (BOOST_VERSION < 104000) + +#endif // _QX_BOOST_ARCHIVE_SERIALIZER_IMPL_DEFINED_ + +namespace boost { namespace archive { + + // explicitly instantiate for this type of binary stream + template class basic_binary_oarchive; + + template class basic_binary_oprimitive< + eos::portable_oarchive + #if BOOST_VERSION < 103400 + , std::ostream + #else + , std::ostream::char_type + , std::ostream::traits_type + #endif + >; + +#if (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) +#if (BOOST_VERSION < 104000) + template class detail::archive_pointer_oserializer; +#else // (BOOST_VERSION < 104000) + template class detail::archive_serializer_map; +#endif // (BOOST_VERSION < 104000) +#endif // (! _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON) + +} } // namespace boost::archive + +#endif // NO_EXPLICIT_TEMPLATE_INSTANTIATION + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // _QX_PORTABLE_BINARY_OARCHIVE_H_ +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/std/QxSerialize_std_shared_ptr.h b/include/QxSerialize/std/QxSerialize_std_shared_ptr.h new file mode 100644 index 0000000..a94bb70 --- /dev/null +++ b/include/QxSerialize/std/QxSerialize_std_shared_ptr.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_STD_SHARED_PTR_H_ +#define _QX_SERIALIZE_STD_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#if (BOOST_VERSION >= 105600) + +#include + +#else // (BOOST_VERSION >= 105600) + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const std::shared_ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + const T *ptr = t.get(); + ar << boost::serialization::make_nvp("std_shared_ptr", ptr); + } + + template + inline void load(Archive &ar, std::shared_ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + T *ptr = NULL; + ar >> boost::serialization::make_nvp("std_shared_ptr", ptr); + t.reset(ptr); + } + + template + inline void serialize(Archive &ar, std::shared_ptr &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // (BOOST_VERSION >= 105600) +#endif // _QX_SERIALIZE_STD_SHARED_PTR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/std/QxSerialize_std_tuple.h b/include/QxSerialize/std/QxSerialize_std_tuple.h new file mode 100644 index 0000000..c446abf --- /dev/null +++ b/include/QxSerialize/std/QxSerialize_std_tuple.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_STD_TUPLE_H_ +#define _QX_SERIALIZE_STD_TUPLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", std::get<5>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", std::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", std::get<6>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", std::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", std::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", std::get<7>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", std::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", std::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", std::get<7>(t)); + ar &boost::serialization::make_nvp("tuple_9", std::get<8>(t)); + } + + template + inline void serialize(Archive &ar, std::tuple &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("tuple_1", std::get<0>(t)); + ar &boost::serialization::make_nvp("tuple_2", std::get<1>(t)); + ar &boost::serialization::make_nvp("tuple_3", std::get<2>(t)); + ar &boost::serialization::make_nvp("tuple_4", std::get<3>(t)); + ar &boost::serialization::make_nvp("tuple_5", std::get<4>(t)); + ar &boost::serialization::make_nvp("tuple_6", std::get<5>(t)); + ar &boost::serialization::make_nvp("tuple_7", std::get<6>(t)); + ar &boost::serialization::make_nvp("tuple_8", std::get<7>(t)); + ar &boost::serialization::make_nvp("tuple_9", std::get<8>(t)); + ar &boost::serialization::make_nvp("tuple_10", std::get<9>(t)); + } + + } // namespace boost +} // namespace serialization + +#endif // _QX_SERIALIZE_STD_TUPLE_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/std/QxSerialize_std_unique_ptr.h b/include/QxSerialize/std/QxSerialize_std_unique_ptr.h new file mode 100644 index 0000000..0310309 --- /dev/null +++ b/include/QxSerialize/std/QxSerialize_std_unique_ptr.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZE_STD_UNIQUE_PTR_H_ +#define _QX_SERIALIZE_STD_UNIQUE_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#if (BOOST_VERSION >= 105600) + +#include + +#else // (BOOST_VERSION >= 105600) + +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const std::unique_ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + const T *ptr = t.get(); + ar << boost::serialization::make_nvp("std_unique_ptr", ptr); + } + + template + inline void load(Archive &ar, std::unique_ptr &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + T *ptr = NULL; + ar >> boost::serialization::make_nvp("std_unique_ptr", ptr); + t.reset(ptr); + } + + template + inline void serialize(Archive &ar, std::unique_ptr &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +#endif // (BOOST_VERSION >= 105600) +#endif // _QX_SERIALIZE_STD_UNIQUE_PTR_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/std/QxSerialize_std_unordered_map.h b/include/QxSerialize/std/QxSerialize_std_unordered_map.h new file mode 100644 index 0000000..0da8271 --- /dev/null +++ b/include/QxSerialize/std/QxSerialize_std_unordered_map.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZATION_STD_UNORDERED_MAP_H_ +#define _QX_SERIALIZATION_STD_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#if (BOOST_VERSION >= 105600) + +#include + +#else // (BOOST_VERSION >= 105600) + +#include + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const std::unordered_map &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, std::unordered_map &t, const unsigned int /* file_version */) + { + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_map>, + boost::serialization::stl::no_reserve_imp>>(ar, t); + } + + template + inline void serialize(Archive &ar, std::unordered_map &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + template + inline void save(Archive &ar, const std::unordered_multimap &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, std::unordered_multimap &t, const unsigned int /* file_version */) + { +#if (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_map>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#else // (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_multimap>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#endif // (BOOST_VERSION >= 104200) + } + + template + inline void serialize(Archive &ar, std::unordered_multimap &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // (BOOST_VERSION >= 105600) +#endif // _QX_SERIALIZATION_STD_UNORDERED_MAP_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxSerialize/std/QxSerialize_std_unordered_set.h b/include/QxSerialize/std/QxSerialize_std_unordered_set.h new file mode 100644 index 0000000..974924f --- /dev/null +++ b/include/QxSerialize/std/QxSerialize_std_unordered_set.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#ifndef _QX_SERIALIZATION_STD_UNORDERED_SET_H_ +#define _QX_SERIALIZATION_STD_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#if (BOOST_VERSION >= 105600) + +#include + +#else // (BOOST_VERSION >= 105600) + +#include + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace serialization + { + + template + inline void save(Archive &ar, const std::unordered_set &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, std::unordered_set &t, const unsigned int /* file_version */) + { + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_set>, + boost::serialization::stl::no_reserve_imp>>(ar, t); + } + + template + inline void serialize(Archive &ar, std::unordered_set &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + template + inline void save(Archive &ar, const std::unordered_multiset &t, const unsigned int /* file_version */) + { + boost::serialization::stl::save_collection>(ar, t); + } + + template + inline void load(Archive &ar, std::unordered_multiset &t, const unsigned int /* file_version */) + { +#if (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_set>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#else // (BOOST_VERSION >= 104200) + boost::serialization::stl::load_collection, + boost::serialization::stl::archive_input_multiset>, + boost::serialization::stl::no_reserve_imp>>(ar, t); +#endif // (BOOST_VERSION >= 104200) + } + + template + inline void serialize(Archive &ar, std::unordered_multiset &t, const unsigned int file_version) + { + boost::serialization::split_free(ar, t, file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // (BOOST_VERSION >= 105600) +#endif // _QX_SERIALIZATION_STD_UNORDERED_SET_H_ +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/include/QxService/IxParameter.h b/include/QxService/IxParameter.h new file mode 100644 index 0000000..42be59c --- /dev/null +++ b/include/QxService/IxParameter.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _IX_SERVICE_PARAMETER_H_ +#define _IX_SERVICE_PARAMETER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxParameter.h + * \author XDL Team + * \ingroup QxService + * \brief Common interface for all parameters transfered by QxService module of QxOrm library + */ + +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +namespace qx +{ + namespace service + { + class IxParameter; + } // namespace service +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::service::IxParameter &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::service::IxParameter &t) QX_USED; + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::IxParameter : common interface for all parameters transfered by QxService module of QxOrm library + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT IxParameter + { + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::service::IxParameter &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::service::IxParameter &t); + + public: + IxParameter(); + virtual ~IxParameter(); + + // Need to override these methods only if you are using 'qx::service::QxConnect::serialization_qt' type (based on QDataStream) or 'qx::service::QxConnect::serialization_json' type (based on QJson engine) + // You can use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override + virtual void registerClass() const; + virtual QString getClassName() const; + virtual void save(QDataStream &stream) const; + virtual void load(QDataStream &stream); + +#ifndef _QX_NO_JSON + virtual QJsonValue saveToJson() const; + virtual qx_bool loadFromJson(const QJsonValue &val); +#endif // _QX_NO_JSON + }; + + typedef std::shared_ptr IxParameter_ptr; + + } // namespace service +} // namespace qx + +QX_REGISTER_INTERNAL_HELPER_HPP(QX_DLL_EXPORT, qx::service::IxParameter, 0) + +#define QX_SERVICE_IX_PARAMETER_QDATASTREAM_HPP(className) \ +public: \ + virtual void save(QDataStream &stream) const; \ + virtual void load(QDataStream &stream); + +#define QX_SERVICE_IX_PARAMETER_QDATASTREAM_CPP(className) \ + void className::save(QDataStream &stream) const { qx::QxSerializeRegistered::save(stream, (*this)); } \ + void className::load(QDataStream &stream) { qx::QxSerializeRegistered::load(stream, (*this)); } + +#ifndef _QX_NO_JSON + +#define QX_SERVICE_IX_PARAMETER_QJSON_HPP(className) \ +public: \ + virtual QJsonValue saveToJson() const; \ + virtual qx_bool loadFromJson(const QJsonValue &val); + +#define QX_SERVICE_IX_PARAMETER_QJSON_CPP(className) \ + QJsonValue className::saveToJson() const { return qx::cvt::detail::QxSerializeJsonRegistered::save((*this), ""); } \ + qx_bool className::loadFromJson(const QJsonValue &val) { return qx::cvt::detail::QxSerializeJsonRegistered::load(val, (*this), ""); } + +#else // _QX_NO_JSON +#define QX_SERVICE_IX_PARAMETER_QJSON_HPP(className) /* Nothing */ +#define QX_SERVICE_IX_PARAMETER_QJSON_CPP(className) /* Nothing */ +#endif // _QX_NO_JSON + +#define QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP(className) \ + QX_SERVICE_IX_PARAMETER_QDATASTREAM_HPP(className) \ + QX_SERVICE_IX_PARAMETER_QJSON_HPP(className) \ +public: \ + virtual void registerClass() const; \ + virtual QString getClassName() const; + +#define QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP(className) \ + QX_SERVICE_IX_PARAMETER_QDATASTREAM_CPP(className) \ + QX_SERVICE_IX_PARAMETER_QJSON_CPP(className) \ + void className::registerClass() const { qx::QxClass::getSingleton(); } \ + QString className::getClassName() const { return #className; } + +#endif // _IX_SERVICE_PARAMETER_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/IxService.h b/include/QxService/IxService.h new file mode 100644 index 0000000..8c2a72b --- /dev/null +++ b/include/QxService/IxService.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _IX_SERVICE_H_ +#define _IX_SERVICE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxService.h + * \author XDL Team + * \ingroup QxService + * \brief Common interface for all services defined with QxService module of QxOrm library + */ + +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace service + { + class QxTransaction; + class IxService; + } // namespace service +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::service::IxService &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::service::IxService &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::service::IxService &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::IxService &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::IxService : common interface for all services defined with QxService module of QxOrm library + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT IxService + { + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::service::IxService &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::service::IxService &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::service::IxService &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::IxService &t, const QString &format); +#endif // _QX_NO_JSON + + protected: + QString m_sServiceName; //!< Service name <=> class name + QString m_sServiceMethodName; //!< Service method name to call + IxParameter_ptr m_pInputParameter; //!< List of input parameters (request) + IxParameter_ptr m_pOutputParameter; //!< List of output parameters (reply) + qx_bool m_bMessageReturn; //!< Message return to indicate if an error occured + std::shared_ptr m_pTransaction; //!< Current transaction after executing service method + + public: + IxService(); + IxService(const QString &sServiceName); + virtual ~IxService(); + + QString getServiceName() const { return m_sServiceName; } + QString getServiceMethodName() const { return m_sServiceMethodName; } + IxParameter_ptr getInputParameter_BaseClass() const { return m_pInputParameter; } + IxParameter_ptr getOutputParameter_BaseClass() const { return m_pOutputParameter; } + qx_bool getMessageReturn() const { return m_bMessageReturn; } + std::shared_ptr getTransaction() const; + + void setServiceName(const QString &s) + { + qAssert(!s.isEmpty()); + m_sServiceName = s; + } + void setServiceMethodName(const QString &s) + { + qAssert(!s.isEmpty()); + m_sServiceMethodName = s; + } + void setInputParameter(IxParameter_ptr p) { m_pInputParameter = p; } + void setOutputParameter(IxParameter_ptr p) { m_pOutputParameter = p; } + void setMessageReturn(const qx_bool &b) { m_bMessageReturn = b; } + void setMessageReturn(long l, const QString &s) { m_bMessageReturn = qx_bool(l, s); } + void setTransaction(const std::shared_ptr &p); + + bool isValid() const { return m_bMessageReturn.getValue(); } + bool isValidWithOutput() const { return (isValid() && (m_pOutputParameter.get() != NULL)); } + + virtual void registerClass() const + { + qDebug("[QxOrm] qx::service::IxService : %s", "need to override 'registerClass()' method"); + qAssert(false); + } + virtual void onBeforeProcess() { ; } + virtual void onAfterProcess() { ; } + }; + + typedef std::shared_ptr IxService_ptr; + + } // namespace service +} // namespace qx + +QX_REGISTER_INTERNAL_HELPER_HPP(QX_DLL_EXPORT, qx::service::IxService, 0) + +#endif // _IX_SERVICE_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxClientAsync.h b/include/QxService/QxClientAsync.h new file mode 100644 index 0000000..435d5ef --- /dev/null +++ b/include/QxService/QxClientAsync.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_CLIENT_ASYNC_H_ +#define _QX_SERVICE_CLIENT_ASYNC_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxClientAsync.h + * \author XDL Team + * \ingroup QxService + * \brief Provide a class helper to easily execute an asynchronous transaction using a multi-thread process + */ + +#include +#include + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::QxClientAsync : class helper to easily execute an asynchronous transaction using a multi-thread process + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QxClientAsync : public QThread + { + + protected: + IxService_ptr m_pService; //!< Service to execute in thread + QString m_sServiceMethod; //!< Service method to call + + public: + QxClientAsync() : QThread() { ; } + virtual ~QxClientAsync() + { + if (isRunning()) + { + qDebug("[QxOrm] qx::service::QxClientAsync thread is running : %s", "wait thread finished"); + wait(); + } + } + + IxService_ptr getService() const { return m_pService; } + void setService(IxService_ptr service, const QString &method) + { + qAssert(!isRunning()); + m_pService = service; + m_sServiceMethod = method; + } + + protected: + virtual void run() { qx::service::execute_client(m_pService.get(), m_sServiceMethod); } + }; + + typedef std::shared_ptr QxClientAsync_ptr; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_CLIENT_ASYNC_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxConnect.h b/include/QxService/QxConnect.h new file mode 100644 index 0000000..9a54dc3 --- /dev/null +++ b/include/QxService/QxConnect.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_CONNECT_H_ +#define _QX_SERVICE_CONNECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxConnect.h + * \author XDL Team + * \ingroup QxService + * \brief Define connection parameters used by QxService module of QxOrm library + */ + +#ifndef QT_NO_SSL +#include +#include +#include +#include +#include +#endif // QT_NO_SSL + +#ifndef Q_MOC_RUN +#include +#endif // Q_MOC_RUN + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::QxConnect : define connection parameters used by QxService module of QxOrm library (this class is a singleton) + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxConnect : public qx::QxSingleton + { + + friend class qx::QxSingleton; + + public: + enum serialization_type + { + serialization_binary, + serialization_xml, + serialization_text, + serialization_portable_binary, + serialization_wide_binary, + serialization_wide_xml, + serialization_wide_text, + serialization_polymorphic_binary, + serialization_polymorphic_xml, + serialization_polymorphic_text, + serialization_qt, + serialization_json + }; + + private: + struct QxConnectImpl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + + QxConnect(); + virtual ~QxConnect(); + + public: + QString getIp(); + long getPort(); + serialization_type getSerializationType(); + long getThreadCount(); + int getMaxWait(); + bool getCompressData(); + bool getEncryptData(); + quint64 getEncryptKey(); + long getKeepAlive(); + bool getModeHTTP(); + qlonglong getSessionTimeOut(); + +#ifndef QT_NO_SSL + bool getSSLEnabled(); + QSslConfiguration getSSLConfiguration(); + QList getSSLCACertificates(); + QSslCertificate getSSLLocalCertificate(); + QSslKey getSSLPrivateKey(); + QList getSSLIgnoreErrors(); + QSsl::SslProtocol getSSLProtocol(); + QString getSSLPeerVerifyName(); + QSslSocket::PeerVerifyMode getSSLPeerVerifyMode(); + int getSSLPeerVerifyDepth(); +#endif // QT_NO_SSL + + void setIp(const QString &s); + void setPort(long l); + void setSerializationType(serialization_type e); + void setThreadCount(long l); + void setMaxWait(int i); + void setCompressData(bool b); + void setEncryptData(bool b, quint64 key = 0); + void setKeepAlive(long l); + void setModeHTTP(bool b); + void setSessionTimeOut(qlonglong l); + +#ifndef QT_NO_SSL + void setSSLEnabled(bool b); + void setSSLConfiguration(QSslConfiguration cfg); + void setSSLCACertificates(QList lst); + void setSSLLocalCertificate(QSslCertificate cert); + void setSSLPrivateKey(QSslKey key); + void setSSLIgnoreErrors(QList lst); + void setSSLProtocol(QSsl::SslProtocol e); + void setSSLPeerVerifyName(const QString &s); + void setSSLPeerVerifyMode(QSslSocket::PeerVerifyMode e); + void setSSLPeerVerifyDepth(int i); +#endif // QT_NO_SSL + }; + + } // namespace service +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::service::QxConnect) + +#endif // _QX_SERVICE_CONNECT_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxServer.h b/include/QxService/QxServer.h new file mode 100644 index 0000000..5b9533b --- /dev/null +++ b/include/QxService/QxServer.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_SERVER_H_ +#define _QX_SERVICE_SERVER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxServer.h + * \author XDL Team + * \ingroup QxService + * \brief Server side to manage a thread pool of incoming connections (new request from client) + */ + +#include + +namespace qx +{ + namespace service + { + + class QxThreadPool; + class QxThread; + + /*! + * \ingroup QxService + * \brief qx::service::QxServer : server side to manage a thread pool of incoming connections (new request from client) + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxServer : public QTcpServer + { + + protected: + QxThreadPool *m_pThreadPool; //!< Parent thread pool to prevent from incoming connection + QMutex m_mutex; //!< Mutex => 'QxServer' is thread-safe + + public: + QxServer(QxThreadPool *pool) : QTcpServer(), m_pThreadPool(pool) { qAssert(m_pThreadPool); } + virtual ~QxServer() { ; } + + protected: +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + virtual void incomingConnection(qintptr socketDescriptor); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + virtual void incomingConnection(int socketDescriptor); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + QxThread *getAvailable() const; + }; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_SERVER_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxService.h b/include/QxService/QxService.h new file mode 100644 index 0000000..bc452a1 --- /dev/null +++ b/include/QxService/QxService.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_H_ +#define _QX_SERVICE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxService.h + * \author XDL Team + * \ingroup QxService + * \brief Concrete service class defined with QxService module of QxOrm library + */ + +#include + +#include + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::QxService : concrete service class with INPUT parameters and OUTPUT parameters + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + template + class QxService : public IxService + { + + protected: + enum + { + is_input_parameter = std::is_base_of::value + }; + enum + { + is_output_parameter = std::is_base_of::value + }; + enum + { + is_input_registered = qx::trait::is_qx_registered::value + }; + enum + { + is_output_registered = qx::trait::is_qx_registered::value + }; + enum + { + is_valid_parameter = (is_input_parameter && is_output_parameter && is_input_registered && is_output_registered) + }; + + typedef std::shared_ptr INPUT_ptr; + typedef std::shared_ptr OUTPUT_ptr; + + public: + QxService(const QString &sServiceName) : IxService(sServiceName) { static_assert(is_valid_parameter, "is_valid_parameter"); } + virtual ~QxService() { ; } + + INPUT_ptr getInputParameter() const { return std::static_pointer_cast(m_pInputParameter); } + OUTPUT_ptr getOutputParameter() const { return std::static_pointer_cast(m_pOutputParameter); } + + virtual void registerClass() const + { + qx::QxClass::getSingleton(); + qx::QxClass::getSingleton(); + } + }; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxThread.h b/include/QxService/QxThread.h new file mode 100644 index 0000000..8345ff8 --- /dev/null +++ b/include/QxService/QxThread.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_THREAD_H_ +#define _QX_SERVICE_THREAD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxThread.h + * \author XDL Team + * \ingroup QxService + * \brief Thread to execute a transaction of QxService module + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#ifdef QT_NO_OPENSSL +#ifndef QT_NO_SSL +#define QT_NO_SSL /* Nothing */ +#endif // QT_NO_SSL +#endif // QT_NO_OPENSSL + +#include + +#ifndef QT_NO_SSL +#include +#include +#include +#include +#include +#endif // QT_NO_SSL + +#ifndef Q_MOC_RUN +#include +#endif // Q_MOC_RUN + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#define QX_TYPE_SOCKET_DESC qintptr +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#define QX_TYPE_SOCKET_DESC int +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +namespace qx +{ + namespace service + { + + class QxThreadPool; + + /*! + * \ingroup QxService + * \brief qx::service::QxThread : thread to execute a transaction of QxService module + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxThread : public QObject + { + + Q_OBJECT + + protected: + QX_TYPE_SOCKET_DESC m_iSocketDescriptor; //!< Socket descriptor to retrieve 'QTcpSocket' + QxThreadPool *m_pThreadPool; //!< Parent thread pool to set available + QThread *m_pThread; //!< Thread where this worker is executed + QxTransaction_ptr m_pTransaction; //!< Current service transaction + bool m_bIsStopped; //!< Set this flag to 'true' to terminate thread + bool m_bIsDisconnected; //!< Socket has been disconnected + QMutex m_mutex; //!< Mutex => 'QxThread' is thread-safe + + public: + QxThread(QxThreadPool *pool, QThread *thread) : QObject(), m_iSocketDescriptor(0), m_pThreadPool(pool), m_pThread(thread), m_bIsStopped(false), m_bIsDisconnected(false) + { + qAssert(m_pThreadPool); + qAssert(m_pThread); + } + virtual ~QxThread() { clearData(); } + + void init(); + void stop(); + void wait(); + bool isAvailable(); + void execute(QX_TYPE_SOCKET_DESC socketDescriptor); + + protected: + void quit(); + void clearData(); + bool hasBeenStopped(); + void doProcess(QTcpSocket &socket); + bool checkKeepAlive(QTcpSocket &socket); + QX_TYPE_SOCKET_DESC getSocketDescriptor(); + +#ifndef QT_NO_SSL + bool checkSocketSSLEncrypted(QTcpSocket *socket); + QSslSocket *initSocketSSL(); +#endif // QT_NO_SSL + + Q_SIGNALS: + + void error(const QString &err, qx::service::QxTransaction_ptr transaction); + void transactionStarted(qx::service::QxTransaction_ptr transaction); + void transactionFinished(qx::service::QxTransaction_ptr transaction); + void customRequestHandler(qx::service::QxTransaction_ptr transaction); + void incomingConnection(); + void finished(); + + private Q_SLOTS: + + void onCustomRequestHandler(); + void onIncomingConnection(); + void onSocketDisconnected(); + void onSocketReadyRead(); + +#ifndef QT_NO_SSL +#ifndef QT_NO_OPENSSL + void onSocketSSLEncrypted(); + void onSocketSSLErrors(const QList &errors); + void onSocketSSLPeerVerifyError(const QSslError &error); +#endif // QT_NO_OPENSSL +#endif // QT_NO_SSL + }; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_THREAD_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxThreadPool.h b/include/QxService/QxThreadPool.h new file mode 100644 index 0000000..e433b8f --- /dev/null +++ b/include/QxService/QxThreadPool.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_THREAD_POOL_H_ +#define _QX_SERVICE_THREAD_POOL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxThreadPool.h + * \author XDL Team + * \ingroup QxService + * \brief Thread pool to manage list of threads for executing all transactions of QxService module + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#ifndef Q_MOC_RUN +#include +#include +#endif // Q_MOC_RUN + +namespace qx +{ + namespace service + { + + class QxThread; + + /*! + * \ingroup QxService + * \brief qx::service::QxThreadPool : thread-safe thread pool to manage list of threads for executing all transactions of QxService module + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxThreadPool : public QThread + { + + Q_OBJECT + + protected: + QList m_lstAllServices; //!< List of all services created by 'QxThreadPool' + QQueue m_lstAvailable; //!< List of services available to execute process + bool m_bIsStopped; //!< Flag to indicate if thread has been stopped + QMutex m_mutex; //!< Mutex => 'QxThreadPool' is thread-safe + + public: + QxThreadPool() : QThread(), m_bIsStopped(false) { ; } + virtual ~QxThreadPool() + { + if (isRunning()) + { + qDebug("[QxOrm] qx::service::QxThreadPool thread is running : %s", "quit and wait"); + quit(); + wait(); + } + } + + bool isStopped() const; + QxThread *getAvailable(); + void setAvailable(QxThread *p); + void raiseError(const QString &err, QxTransaction_ptr transaction); + + static void sleepThread(unsigned long msecs) { QThread::msleep(msecs); } + + protected: + virtual void run(); + + void runServer(); + void initServices(); + void clearServices(); + + Q_SIGNALS: + + void error(const QString &err, qx::service::QxTransaction_ptr transaction); + void transactionStarted(qx::service::QxTransaction_ptr transaction); + void transactionFinished(qx::service::QxTransaction_ptr transaction); + void customRequestHandler(qx::service::QxTransaction_ptr transaction); + void serverIsRunning(bool bIsRunning, qx::service::QxServer *pServer); + }; + + typedef std::shared_ptr QxThreadPool_ptr; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_THREAD_POOL_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxTools.h b/include/QxService/QxTools.h new file mode 100644 index 0000000..2e91351 --- /dev/null +++ b/include/QxService/QxTools.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_TOOLS_H_ +#define _QX_SERVICE_TOOLS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxTools.h + * \author XDL Team + * \ingroup QxService + * \brief Provide some tools to read/write on socket all datas transfered by QxService module of QxOrm library + */ + +#include + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::QxTools : provide some tools to read/write on socket all datas transfered by QxService module of QxOrm library + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxTools + { + + public: + static qx_bool readSocket(QTcpSocket &socket, QxTransaction &transaction, quint32 &size); + static qx_bool writeSocket(QTcpSocket &socket, QxTransaction &transaction, quint32 &size); + }; + + } // namespace service +} // namespace qx + +#endif // _QX_SERVICE_TOOLS_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxService/QxTransaction.h b/include/QxService/QxTransaction.h new file mode 100644 index 0000000..76920c3 --- /dev/null +++ b/include/QxService/QxTransaction.h @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef Q_MOC_RUN +#include // Need to include this file for the 'moc' process +#endif // Q_MOC_RUN + +#ifdef _QX_ENABLE_QT_NETWORK +#ifndef _QX_SERVICE_TRANSACTION_H_ +#define _QX_SERVICE_TRANSACTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxTransaction.h + * \author XDL Team + * \ingroup QxService + * \brief Transaction of QxService module (contains request from client and reply from server) + */ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +#ifndef QT_NO_SSL +#include +#include +#include +#include +#include +#endif // QT_NO_SSL + +#ifndef Q_MOC_RUN +#include +#include +#include +#include +#include +#endif // Q_MOC_RUN + +namespace qx +{ + namespace service + { + class QxTransaction; + } // namespace service +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::service::QxTransaction &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::service::QxTransaction &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::service::QxTransaction &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::QxTransaction &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + namespace service + { + + /*! + * \ingroup QxService + * \brief qx::service::QxTransaction : transaction of QxService module (contains request from client and reply from server) + * + * Click here to access to a tutorial to explain how to work with QxService module. + */ + class QX_DLL_EXPORT QxTransaction : public QObject + { + + Q_OBJECT + QX_REGISTER_FRIEND_CLASS(qx::service::QxTransaction) + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::service::QxTransaction &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::service::QxTransaction &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::service::QxTransaction &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::QxTransaction &t, const QString &format); +#endif // _QX_NO_JSON + + public: + enum connection_status + { + conn_none, + conn_keep_alive, + conn_close + }; + + protected: + QString m_sTransactionId; //!< Transaction id (GUID) + quint32 m_uiInputTransactionSize; //!< Input transaction size + quint32 m_uiOutputTransactionSize; //!< Output transaction size + QDateTime m_dtTransactionBegin; //!< Date-time transaction begin + QDateTime m_dtTransactionRequestSent; //!< Date-time transaction request sent + QDateTime m_dtTransactionRequestReceived; //!< Date-time transaction request received + QDateTime m_dtTransactionReplySent; //!< Date-time transaction reply sent + QDateTime m_dtTransactionReplyReceived; //!< Date-time transaction reply received + QDateTime m_dtTransactionEnd; //!< Date-time transaction end + QString m_sIpSource; //!< Ip address source (request) + QString m_sIpTarget; //!< Ip address target (reply) + long m_lPortSource; //!< Port number source (request) + long m_lPortTarget; //!< Port number target (reply) + QString m_sServiceName; //!< Service name to create using 'QxFactory' + QString m_sServiceMethod; //!< Service method to call to execute transaction + qx_bool m_bMessageReturn; //!< Message return to indicate if an error occured + IxParameter_ptr m_pInputParameter; //!< List of input parameters (request) + IxParameter_ptr m_pOutputParameter; //!< List of output parameters (reply) + IxService_ptr m_pServiceInstance; //!< Service instance created by 'm_sServiceName' property + connection_status m_eForceConnectionStatus; //!< Sometimes we have to force connection status + + public: + QxTransaction() : QObject(), m_uiInputTransactionSize(0), m_uiOutputTransactionSize(0), m_lPortSource(0), m_lPortTarget(0), m_eForceConnectionStatus(conn_none) { ; } + virtual ~QxTransaction() { ; } + virtual void clear(); + + QString getTransactionId() const { return m_sTransactionId; } + quint32 getInputTransactionSize() const { return m_uiInputTransactionSize; } + quint32 getOutputTransactionSize() const { return m_uiOutputTransactionSize; } + QDateTime getTransactionBegin() const { return m_dtTransactionBegin; } + QDateTime getTransactionRequestSent() const { return m_dtTransactionRequestSent; } + QDateTime getTransactionRequestReceived() const { return m_dtTransactionRequestReceived; } + QDateTime getTransactionReplySent() const { return m_dtTransactionReplySent; } + QDateTime getTransactionReplyReceived() const { return m_dtTransactionReplyReceived; } + QDateTime getTransactionEnd() const { return m_dtTransactionEnd; } + QString getIpSource() const { return m_sIpSource; } + QString getIpTarget() const { return m_sIpTarget; } + long getPortSource() const { return m_lPortSource; } + long getPortTarget() const { return m_lPortTarget; } + QString getServiceName() const { return m_sServiceName; } + QString getServiceMethod() const { return m_sServiceMethod; } + qx_bool getMessageReturn() const { return m_bMessageReturn; } + IxParameter_ptr getInputParameter() const { return m_pInputParameter; } + IxParameter_ptr getOutputParameter() const { return m_pOutputParameter; } + connection_status getForceConnectionStatus() const { return m_eForceConnectionStatus; } + + void setTransactionId(const QString &s) { m_sTransactionId = s; } + void setInputTransactionSize(quint32 ui) { m_uiInputTransactionSize = ui; } + void setOutputTransactionSize(quint32 ui) { m_uiOutputTransactionSize = ui; } + void setTransactionBegin(const QDateTime &dt) { m_dtTransactionBegin = dt; } + void setTransactionRequestSent(const QDateTime &dt) { m_dtTransactionRequestSent = dt; } + void setTransactionRequestReceived(const QDateTime &dt) { m_dtTransactionRequestReceived = dt; } + void setTransactionReplySent(const QDateTime &dt) { m_dtTransactionReplySent = dt; } + void setTransactionReplyReceived(const QDateTime &dt) { m_dtTransactionReplyReceived = dt; } + void setTransactionEnd(const QDateTime &dt) { m_dtTransactionEnd = dt; } + void setIpSource(const QString &s) { m_sIpSource = s; } + void setIpTarget(const QString &s) { m_sIpTarget = s; } + void setPortSource(long l) { m_lPortSource = l; } + void setPortTarget(long l) { m_lPortTarget = l; } + void setServiceName(const QString &s) { m_sServiceName = s; } + void setServiceMethod(const QString &s) { m_sServiceMethod = s; } + void setMessageReturn(const qx_bool &b) { m_bMessageReturn = b; } + void setInputParameter(IxParameter_ptr p) { m_pInputParameter = p; } + void setOutputParameter(IxParameter_ptr p) { m_pOutputParameter = p; } + void setForceConnectionStatus(connection_status e) { m_eForceConnectionStatus = e; } + + virtual void executeServer(); + virtual qx_bool writeSocketServer(QTcpSocket &socket); + virtual qx_bool readSocketServer(QTcpSocket &socket); + + virtual void executeClient(IxService *pService, const QString &sMethod); + virtual qx_bool writeSocketClient(QTcpSocket &socket); + virtual qx_bool readSocketClient(QTcpSocket &socket); + + QString getInfos() const; + + protected: +#ifndef QT_NO_SSL + QSslSocket *initSocketSSL(); + bool checkSocketSSLEncrypted(QTcpSocket *socket); +#endif // QT_NO_SSL + + Q_SIGNALS: + + void onCustomRequestHandler(); + }; + + typedef std::shared_ptr QxTransaction_ptr; + QX_DLL_EXPORT void execute_client(IxService *pService, const QString &sMethod); + + } // namespace service +} // namespace qx + +QX_REGISTER_INTERNAL_HELPER_HPP(QX_DLL_EXPORT, qx::service::QxTransaction, 0) + +#endif // _QX_SERVICE_TRANSACTION_H_ +#endif // _QX_ENABLE_QT_NETWORK diff --git a/include/QxServices.h b/include/QxServices.h new file mode 100644 index 0000000..e7b6512 --- /dev/null +++ b/include/QxServices.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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_SERVICES_H_ +#define _QX_SERVICES_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxServices.h + * \author XDL Team + * \ingroup QxService + * \brief Include all headers required to use QxService module : https://www.qxorm.com/qxorm_en/manual.html#manual_80 + */ + +#include + +#ifdef _QX_ENABLE_QT_NETWORK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // _QX_ENABLE_QT_NETWORK + +#endif // _QX_SERVICES_H_ diff --git a/include/QxSingleton/IxSingleton.h b/include/QxSingleton/IxSingleton.h new file mode 100644 index 0000000..7a36a52 --- /dev/null +++ b/include/QxSingleton/IxSingleton.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 _IX_SINGLETON_H_ +#define _IX_SINGLETON_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxSingleton.h + * \author XDL Team + * \ingroup QxSingleton + * \brief Common interface for all singleton of QxOrm library + */ + +namespace qx +{ + + class QxSingletonX; + + /*! + * \ingroup QxSingleton + * \brief qx::IxSingleton : common interface for all singleton of QxOrm library + */ + class QX_DLL_EXPORT IxSingleton + { + + friend class QxSingletonX; + + protected: + QString m_sKeySingleton; //!< Singleton key used by 'QxSingletonX' container + + protected: + IxSingleton(const QString &sKey); + virtual ~IxSingleton(); + + virtual void deleteInstance() = 0; + + static void initQxSingletonX(); + + private: + IxSingleton(const IxSingleton &other) { Q_UNUSED(other); } + IxSingleton &operator=(const IxSingleton &other) + { + Q_UNUSED(other); + return (*this); + } + }; + +} // namespace qx + +#endif // _IX_SINGLETON_H_ diff --git a/include/QxSingleton/QxSingleton.h b/include/QxSingleton/QxSingleton.h new file mode 100644 index 0000000..009856b --- /dev/null +++ b/include/QxSingleton/QxSingleton.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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_SINGLETON_H_ +#define _QX_SINGLETON_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSingleton.h + * \author XDL Team + * \ingroup QxSingleton + * \brief Concrete class to define a thread-safe singleton of QxOrm library + */ + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxSingleton + * \brief qx::QxSingleton : concrete class to define a thread-safe singleton of type T + */ + template + class QxSingleton : public IxSingleton + { + + private: + static T *m_pSingleton; //!< Singleton -> only 1 instance allowed + static QMutex m_oMutexSingleton; //!< Mutex -> 'QxSingleton' is thread-safe + + protected: + QxSingleton(const QString &sKey) : IxSingleton(sKey) { ; } + virtual ~QxSingleton() { ; } + + public: + static T *getSingleton(); + static void deleteSingleton(); + + protected: + static bool isSingletonNull() { return (m_pSingleton == NULL); } + + virtual void deleteInstance() { QxSingleton::deleteSingleton(); } + }; + +} // namespace qx + +#include "../../inl/QxSingleton/QxSingleton.inl" + +#endif // _QX_SINGLETON_H_ diff --git a/include/QxSingleton/QxSingletonInit.h b/include/QxSingleton/QxSingletonInit.h new file mode 100644 index 0000000..a4dc3f5 --- /dev/null +++ b/include/QxSingleton/QxSingletonInit.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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_SINGLETON_INIT_H_ +#define _QX_SINGLETON_INIT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSingletonInit.h + * \author XDL Team + * \ingroup QxSingleton + * \brief Initialize some singletons hosted by QxOrm shared library + */ + +#include + +#include + +#include + +#ifdef _QX_ENABLE_QT_NETWORK +#include +#include +#include +#endif // _QX_ENABLE_QT_NETWORK + +#include + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxDataMemberX) + +#ifdef _QX_ENABLE_QT_NETWORK + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxDataMemberX) + +#endif // _QX_ENABLE_QT_NETWORK + +#endif // _QX_SINGLETON_INIT_H_ diff --git a/include/QxSingleton/QxSingletonX.h b/include/QxSingleton/QxSingletonX.h new file mode 100644 index 0000000..b44b1f5 --- /dev/null +++ b/include/QxSingleton/QxSingletonX.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_SINGLETON_X_H_ +#define _QX_SINGLETON_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxSingletonX.h + * \author XDL Team + * \ingroup QxSingleton + * \brief List of all singleton defined by QxOrm library + */ + +#include + +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxSingleton + * \brief qx::QxSingletonX : list of all singleton defined by QxOrm library (this container is also a singleton) + */ + class QX_DLL_EXPORT QxSingletonX : public QxSingleton + { + + friend class QxSingleton; + friend class IxSingleton; + + private: + static QHash &getMapSingletonX(); //!< Collection of all 'IxSingleton' pointer + static QMutex *getMutexSingletonX(); //!< Mutex -> 'QxSingletonX' is thread-safe + static bool &getOnClearSingletonX(); //!< Clear collection of 'IxSingleton' in event + + private: + QxSingletonX(); + virtual ~QxSingletonX() { ; } + + static bool addSingleton(const QString &sKey, IxSingleton *pSingleton); + static bool removeSingleton(const QString &sKey); + static void deleteAllSingleton(); + }; + +} // namespace qx + +QX_DLL_EXPORT_QX_SINGLETON_HPP(qx::QxSingletonX) + +#endif // _QX_SINGLETON_X_H_ diff --git a/include/QxTraits/archive_printable.h b/include/QxTraits/archive_printable.h new file mode 100644 index 0000000..3fa6fc7 --- /dev/null +++ b/include/QxTraits/archive_printable.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** 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_ARCHIVE_PRINTABLE_H_ +#define _QX_ARCHIVE_PRINTABLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file archive_printable.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_archive_printable::value : define if a boost::archive type is readable by a human (for example XML archive) or not (for example binary archive) + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_archive_printable::value : define if a boost::archive type is readable by a human (for example XML archive) or not (for example binary archive) + */ + template + struct is_archive_printable + { + enum + { + value = false + }; + }; + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_TEXT + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_WIDE_TEXT + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; + template <> + struct is_archive_printable + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + } // namespace trait +} // namespace qx + +#endif // _QX_ARCHIVE_PRINTABLE_H_ diff --git a/include/QxTraits/archive_wide_traits.h b/include/QxTraits/archive_wide_traits.h new file mode 100644 index 0000000..b9c525a --- /dev/null +++ b/include/QxTraits/archive_wide_traits.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** 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_ARCHIVE_WIDE_TRAITS_H_ +#define _QX_ARCHIVE_WIDE_TRAITS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file archive_wide_traits.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_archive_wide::value : define if a boost::archive type uses wide string character and stream (for example std::wstring) or not (for example std::string) + */ + +#include +#include +#include +#include + +#include + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_archive_wide::value : define if a boost::archive type uses wide string character and stream (for example std::wstring) or not (for example std::string) + */ + template + struct is_archive_wide + { + enum + { + value = false + }; + }; + +#if _QX_SERIALIZE_WIDE_BINARY + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; + template <> + struct is_archive_wide + { + enum + { + value = true + }; + }; +#endif // _QX_SERIALIZE_WIDE_XML + + template + class archive_wide_traits + { + + public: + enum + { + is_wide = qx::trait::is_archive_wide::value + }; + + typedef typename std::conditional::type type_char; + typedef typename std::conditional::type type_string; + + typedef typename std::conditional::type type_istream; + typedef typename std::conditional::type type_ostream; + + typedef typename std::conditional::type type_stringstream; + typedef typename std::conditional::type type_istringstream; + typedef typename std::conditional::type type_ostringstream; + + typedef typename std::conditional::type type_fstream; + typedef typename std::conditional::type type_ifstream; + typedef typename std::conditional::type type_ofstream; + + static inline QString toQString(const type_string &str) { return cvtQString::toQString(str); } + static inline void fromQString(const QString &str, type_string &result) { cvtQString::fromQString(str, result); } + + static inline QByteArray toQByteArray(const type_string &str, type_string *owner) { return cvtQByteArray::toQByteArray(str, owner); } + static inline void fromQByteArray(const QByteArray &data, type_string &result) { cvtQByteArray::fromQByteArray(data, result); } + + private: + template + struct cvtQString + { +#ifndef QT_NO_STL + static inline QString toQString(const std::string &str) { return QString::fromStdString(str); } + static inline void fromQString(const QString &str, std::string &result) { result = str.toStdString(); } +#else // QT_NO_STL + static inline QString toQString(const std::string &str) { return QString::fromLatin1(str.data(), int(str.size())); } + static inline void fromQString(const QString &str, std::string &result) { result = str.toLatin1().constData(); } +#endif // QT_NO_STL + }; + + template + struct cvtQString + { +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + static inline QString toQString(const std::wstring &str) { return QString::fromStdWString(str); } + static inline void fromQString(const QString &str, std::wstring &result) { result = str.toStdWString(); } +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + static inline QString toQString(const std::wstring &str) + { + Q_UNUSED(str); + qAssert(false); /* Need STL compatibility ! */ + return QString(); + } + static inline void fromQString(const QString &str, std::wstring &result) + { + Q_UNUSED(str); + Q_UNUSED(result); + qAssert(false); /* Need STL compatibility ! */ + } +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + }; + + template + struct cvtQByteArray + { + static inline QByteArray toQByteArray(const std::string &str, std::string *owner) + { + if (owner) + { + (*owner) = str; + }; + return (owner ? QByteArray::fromRawData(owner->data(), owner->size()) : QByteArray(str.data(), str.size())); + } + static inline void fromQByteArray(const QByteArray &data, std::string &result) + { + result.clear(); + result.append(data.constData(), data.size()); + } + }; + + template + struct cvtQByteArray + { + static inline QByteArray toQByteArray(const std::wstring &str, std::wstring *owner) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(owner); + return QString::fromStdWString(str).toUtf8(); + } +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(owner); + Q_UNUSED(str); + qAssert(false); /* Need STL compatibility ! */ + return QByteArray(); + } +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + static inline void fromQByteArray(const QByteArray &data, std::wstring &result) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + result = QString::fromUtf8(data.constData(), data.size()).toStdWString(); + } +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(data); + Q_UNUSED(result); + qAssert(false); /* Need STL compatibility ! */ + } +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + }; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_ARCHIVE_WIDE_TRAITS_H_ diff --git a/include/QxTraits/construct_null_qvariant.h b/include/QxTraits/construct_null_qvariant.h new file mode 100644 index 0000000..8bcce28 --- /dev/null +++ b/include/QxTraits/construct_null_qvariant.h @@ -0,0 +1,727 @@ +/**************************************************************************** +** +** 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_CONSTRUCT_NULL_QVARIANT_H_ +#define _QX_CONSTRUCT_NULL_QVARIANT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file construct_null_qvariant.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::construct_null_qvariant::get() : create a NULL QVariant which matches QVariant::Type with type T + */ + +#include + +#include +#include +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::construct_null_qvariant::get() : create a NULL QVariant which matches QVariant::Type with type T + */ + template + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::BitArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::BitArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::BitArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::BitArray); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ByteArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ByteArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ByteArray); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ByteArray); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Bool); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Bool); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Bool); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Bool); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Int); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::LongLong); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Double); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::UInt); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::ULongLong); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::StringList); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::StringList); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::StringList); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::StringList); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Date); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Date); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Date); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Date); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::DateTime); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::DateTime); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::DateTime); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::DateTime); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Time); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Time); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Time); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Time); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::String); } + }; + +#ifdef _QX_ENABLE_QT_GUI + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Brush); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Brush); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Brush); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Brush); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Color); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Color); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Color); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Color); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Font); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Font); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Font); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Font); } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Matrix); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Matrix); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Matrix); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Matrix); } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Region); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Region); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Region); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Region); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Image); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Image); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Image); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Image); } + }; + + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Pixmap); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Pixmap); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Pixmap); } + }; + template <> + struct construct_null_qvariant + { + static inline QVariant get() { return QVariant(QVariant::Pixmap); } + }; + +#endif // _QX_ENABLE_QT_GUI + + } // namespace trait +} // namespace qx + +#endif // _QX_CONSTRUCT_NULL_QVARIANT_H_ diff --git a/include/QxTraits/construct_ptr.h b/include/QxTraits/construct_ptr.h new file mode 100644 index 0000000..560f16d --- /dev/null +++ b/include/QxTraits/construct_ptr.h @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** 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_CONSTRUCT_PTR_H_ +#define _QX_CONSTRUCT_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file construct_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::construct_ptr::get(T & t, bool bReset = false) : instantiate (or reset) a new pointer, support both nude-pointer and smart-pointer of boost, Qt and QxOrm libraries + */ + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::construct_ptr::get(T & t, bool bReset = false) : instantiate (or reset) a new pointer, support both nude-pointer and smart-pointer of boost, Qt and QxOrm libraries + */ + template + struct construct_ptr + { + + private: + typedef typename std::remove_pointer::type type_ptr; + + public: + static inline void get(T &t, bool bReset = false) + { + new_ptr::value, 0>::get(t, bReset); + } + + private: + template + struct new_ptr + { + static inline void get(T &t, bool bReset) + { + if (bReset) + { + t = NULL; + } + else + { + t = new type_ptr(); + } + } + }; + + template + struct new_ptr + { + static inline void get(T &t, bool bReset) + { + Q_UNUSED(t); + Q_UNUSED(bReset); + qDebug("[QxOrm] qx::trait::construct_ptr : %s", "cannot instantiate abstract class"); + } + }; + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct construct_ptr> + { + static inline void get(boost::scoped_ptr &t, bool bReset = false) + { + if (bReset) + { + t.reset(); + } + else + { + t.reset(new T()); + } + } + }; + + template + struct construct_ptr> + { + static inline void get(boost::shared_ptr &t, bool bReset = false) + { + if (bReset) + { + t.reset(); + } + else + { + t.reset(new T()); + } + } + }; + + template + struct construct_ptr> + { + static inline void get(boost::intrusive_ptr &t, bool bReset = false) + { + if (bReset) + { + t.reset(); + } + else + { + t.reset(new T()); + } + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct construct_ptr> + { + static inline void get(QSharedPointer &t, bool bReset = false) + { + if (bReset) + { + t = QSharedPointer(); + } + else + { + t = QSharedPointer(new T()); + } + } + }; + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + template + struct construct_ptr> + { + static inline void get(QScopedPointer &t, bool bReset = false) + { + if (bReset) + { + t = QScopedPointer(); + } + else + { + t = QScopedPointer(new T()); + } + } + }; +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + + template + struct construct_ptr> + { + static inline void get(qx::dao::ptr &t, bool bReset = false) + { + if (bReset) + { + t = qx::dao::ptr(); + } + else + { + t = qx::dao::ptr(new T()); + } + } + }; + + template + struct construct_ptr> + { + static inline void get(std::unique_ptr &t, bool bReset = false) + { + if (bReset) + { + t.reset(); + } + else + { + t.reset(new T()); + } + } + }; + + template + struct construct_ptr> + { + static inline void get(std::shared_ptr &t, bool bReset = false) + { + if (bReset) + { + t.reset(); + } + else + { + t = std::make_shared(); + } + } + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_CONSTRUCT_PTR_H_ diff --git a/include/QxTraits/generic_container.h b/include/QxTraits/generic_container.h new file mode 100644 index 0000000..4b11eb7 --- /dev/null +++ b/include/QxTraits/generic_container.h @@ -0,0 +1,662 @@ +/**************************************************************************** +** +** 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_GENERIC_CONTAINER_H_ +#define _QX_GENERIC_CONTAINER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file generic_container.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::generic_container : provide some tools to manage all containers without knowing its type + */ + +#include +#include +#include +#include + +namespace qx +{ + namespace trait + { + + class no_type + { + private: + void dummy() const { ; } + }; + + /*! + * \ingroup QxTraits + * \brief qx::trait::generic_container : provide some tools to manage all containers without knowing its type + */ + template + struct generic_container + { + typedef no_type type_item; + typedef no_type type_key; + typedef no_type type_value; + typedef no_type type_value_qx; + typedef no_type type_iterator; + }; + + template + struct generic_container_item + { + + typedef Key type_key; + typedef Value type_value; + typedef typename qx::trait::remove_attr::type type_value_qx_tmp; + typedef typename qx::trait::remove_smart_ptr::type type_value_qx; + + enum + { + is_key_pointer = (std::is_pointer::value || qx::trait::is_smart_ptr::value) + }; + enum + { + is_value_pointer = (std::is_pointer::value || qx::trait::is_smart_ptr::value) + }; + + private: + std::pair m_pair; + + public: + generic_container_item() { ; } + generic_container_item(const Key &key, const Value &value) { m_pair = std::make_pair(key, value); } + ~generic_container_item() { ; } + + inline type_key &key() { return m_pair.first; } + inline type_value &value() { return m_pair.second; } + inline const type_key &key() const { return m_pair.first; } + inline const type_value &value() const { return m_pair.second; } + inline type_value_qx &value_qx() { return value_qx_Helper::get(m_pair.second); } + inline const type_value_qx &value_qx() const { return value_qx_Helper::get(m_pair.second); } + + inline void key(const Key &key) { m_pair.first = key; } + inline void value(const Value &value) { m_pair.second = value; } + + static inline type_key newKey() { return new_Helper::get(); } + static inline type_value newValue() { return new_Helper::get(); } + + private: + template + struct new_Helper + { + static inline T get() + { + T t; + qx::trait::construct_ptr::get(t); + return t; + } + }; + + template + struct new_Helper + { + static inline T get() { return T(); } + }; + + template + struct value_qx_Helper + { + static inline U &get(T &t) { return (*t); } + }; + + template + struct value_qx_Helper + { + static inline U &get(T &t) { return t; } + }; + }; + + } // namespace trait +} // namespace qx + +#define QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(TypeContainer, TypeKey, TypeValue) \ + typedef qx::trait::generic_container_item type_item; \ + typedef typename type_item::type_key type_key; \ + typedef typename type_item::type_value type_value; \ + typedef typename type_item::type_value_qx type_value_qx; \ + typedef typename TypeContainer::iterator type_iterator; + +namespace qx +{ + namespace trait + { + namespace detail + { + + template + struct generic_container_base + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, qx::trait::no_type, Item) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) { t.reserve(l); } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Item *insertItem(Container &t, type_item &item) + { + t.push_back(item.value()); + return (&t.back()); + } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin()); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr); + return itr; + } + }; + + template + struct generic_container_base_without_reserve + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, qx::trait::no_type, Item) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) + { + Q_UNUSED(t); + Q_UNUSED(l); + } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Item *insertItem(Container &t, type_item &item) + { + t.push_back(item.value()); + return (&t.back()); + } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin()); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr); + return itr; + } + }; + + template + struct generic_container_base_set + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, qx::trait::no_type, Item) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) + { + Q_UNUSED(t); + Q_UNUSED(l); + } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Item *insertItem(Container &t, type_item &item) { return const_cast(&(*(t.insert(item.value()).first))); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin()); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr); + return itr; + } + }; + + template + struct generic_container_base_multi_set + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, qx::trait::no_type, Item) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) + { + Q_UNUSED(t); + Q_UNUSED(l); + } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Item *insertItem(Container &t, type_item &item) { return const_cast(&(*(t.insert(item.value())))); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin()); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr); + return itr; + } + }; + + template + struct generic_container_base_key_value_std_style + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, Key, Value) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) { t.reserve(l); } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Value *insertItem(Container &t, type_item &item) { return (&(t.insert(std::make_pair(item.key(), item.value())).first->second)); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin().second); + item.key(*t.begin().first); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr.second); + item.key(*itr.first); + return itr; + } + }; + + template + struct generic_container_base_key_value_without_reserve + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, Key, Value) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) + { + Q_UNUSED(t); + Q_UNUSED(l); + } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Value *insertItem(Container &t, type_item &item) { return (&(t.insert(std::make_pair(item.key(), item.value())).first->second)); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin().second); + item.key(*t.begin().first); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr.second); + item.key(*itr.first); + return itr; + } + }; + + template + struct generic_container_base_key_value_multi_std_style + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, Key, Value) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) { t.reserve(l); } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Value *insertItem(Container &t, type_item &item) { return (&(t.insert(std::make_pair(item.key(), item.value()))->second)); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin().second); + item.key(*t.begin().first); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr.second); + item.key(*itr.first); + return itr; + } + }; + + template + struct generic_container_base_key_value_qt_style + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(Container, Key, Value) + + static inline long size(const Container &t) { return static_cast(t.size()); } + static inline void clear(Container &t) { t.clear(); } + static inline void reserve(Container &t, long l) { t.reserve(l); } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Value *insertItem(Container &t, type_item &item) { return (&(t.insert(item.key(), item.value()).value())); } + static inline type_iterator end(Container &t) { return t.end(); } + + static inline type_iterator begin(Container &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(*t.begin().value()); + item.key(*t.begin().key()); + return t.begin(); + } + + static inline type_iterator next(Container &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + item.value(*itr.value()); + item.key(*itr.key()); + return itr; + } + }; + + } // namespace detail + + template + struct generic_container> : public qx::trait::detail::generic_container_base, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(std::vector, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_without_reserve, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(std::list, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(std::set, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_without_reserve, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(std::map, Key, Value), Key, Value) + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct generic_container> : public qx::trait::detail::generic_container_base_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(boost::unordered_set, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_multi_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(boost::unordered_multiset, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_std_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(boost::unordered_map, Key, Value), Key, Value) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_multi_std_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(boost::unordered_multimap, Key, Value), Key, Value) + }; + +#endif // _QX_ENABLE_BOOST + + template + struct generic_container> : public qx::trait::detail::generic_container_base_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(std::unordered_set, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_multi_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(std::unordered_multiset, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_std_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(std::unordered_map, Key, Value), Key, Value) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_multi_std_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(std::unordered_multimap, Key, Value), Key, Value) + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct generic_container> : public qx::trait::detail::generic_container_base, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(QVector, T), qx::trait::no_type, T) + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + + template + struct generic_container> : public qx::trait::detail::generic_container_base, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(QList, T), qx::trait::no_type, T) + }; + +#else // (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + + template + struct generic_container> : public qx::trait::detail::generic_container_base_without_reserve, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(QList, T), qx::trait::no_type, T) + }; + +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct generic_container> : public qx::trait::detail::generic_container_base_without_reserve, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(QLinkedList, T), qx::trait::no_type, T) + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct generic_container> : public qx::trait::detail::generic_container_base_multi_set, T> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1(QSet, T), qx::trait::no_type, T) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_qt_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(QMap, Key, Value), Key, Value) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_qt_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(QMultiMap, Key, Value), Key, Value) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_qt_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(QHash, Key, Value), Key, Value) + }; + + template + struct generic_container> : public qx::trait::detail::generic_container_base_key_value_qt_style, Key, Value> + { + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(QMultiHash, Key, Value), Key, Value) + }; + + template + struct generic_container> + { + + QX_TRAIT_GENERIC_CONTAINER_TYPEDEF(QX_TEMPLATE_T_P1_P2(qx::QxCollection, Key, Value), Key, Value) + + static inline long size(const qx::QxCollection &t) { return static_cast(t.size()); } + static inline void clear(qx::QxCollection &t) { t.clear(); } + static inline void reserve(qx::QxCollection &t, long l) { t.reserve(l); } + static inline type_item createItem() { return type_item(type_item::newKey(), type_item::newValue()); } + static inline Value *insertItem(qx::QxCollection &t, type_item &item) + { + t.insert(item.key(), item.value()); + return const_cast(&t.getByKey(item.key())); + } + static inline type_iterator end(qx::QxCollection &t) { return t.end(); } + + static inline type_iterator begin(qx::QxCollection &t, type_item &item) + { + if (t.size() <= 0) + { + return t.end(); + }; + item.value(t.getByIndex(0)); + item.key(t.getKeyByIndex(0)); + return t.begin(); + } + + static inline type_iterator next(qx::QxCollection &t, type_iterator itr, type_item &item) + { + itr++; + if (itr == t.end()) + { + return t.end(); + }; + long l = (itr - t.begin()); + item.value(t.getByIndex(l)); + item.key(t.getKeyByIndex(l)); + return itr; + } + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_GENERIC_CONTAINER_H_ diff --git a/include/QxTraits/get_base_class.h b/include/QxTraits/get_base_class.h new file mode 100644 index 0000000..7756783 --- /dev/null +++ b/include/QxTraits/get_base_class.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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_GET_BASE_CLASS_H_ +#define _QX_GET_BASE_CLASS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file get_base_class.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::get_base_class::type : retrieve base class of type T registered into QxOrm context and return qx::trait::no_base_class_defined if no base class defined + */ + +#include + +namespace qx +{ + namespace trait + { + + class no_base_class_defined + { + public: + no_base_class_defined() { ; }; + virtual ~no_base_class_defined() { ; }; + virtual void dummy() = 0; + }; + + /*! + * \ingroup QxTraits + * \brief qx::trait::get_base_class::type : retrieve base class of type T registered into QxOrm context and return qx::trait::no_base_class_defined if no base class defined + */ + template + class get_base_class + { + public: + typedef qx::trait::no_base_class_defined type; + }; + + template + class is_base_class_defined + { + public: + enum + { + value = (std::is_same::type, qx::trait::no_base_class_defined>::value ? 0 : 1) + }; + }; + + template + class get_base_class_2 + { + private: + typedef typename qx::trait::get_base_class::type type_base; + + private: + enum + { + is_base_ok = (std::is_same::value ? 0 : 1) + }; + + public: + typedef typename std::conditional::type type; + }; + + } // namespace trait +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::trait::no_base_class_defined) + +#define QX_REGISTER_BASE_CLASS(derivedClass, baseClass) \ + namespace qx \ + { \ + namespace trait \ + { \ + template <> \ + class get_base_class \ + { \ + public: \ + typedef baseClass type; \ + }; \ + } \ + } // namespace qx::trait + +#define QX_GET_BASE_CLASS(T) qx::trait::get_base_class::type +#define QX_GET_BASE_CLASS_WITH_TYPENAME(T) qx::trait::get_base_class::type +#define QX_IS_BASE_CLASS_DEFINED(T) qx::trait::is_base_class_defined::value +#define QX_IS_BASE_CLASS_DEFINED_WITH_TYPENAME(T) qx::trait::is_base_class_defined::value +#define QX_GET_BASE_CLASS_2(T) qx::trait::get_base_class_2::type +#define QX_GET_BASE_CLASS_2_WITH_TYPENAME(T) qx::trait::get_base_class_2::type + +#endif // _QX_GET_BASE_CLASS_H_ diff --git a/include/QxTraits/get_class_name.h b/include/QxTraits/get_class_name.h new file mode 100644 index 0000000..dff540b --- /dev/null +++ b/include/QxTraits/get_class_name.h @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** 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_GET_CLASS_NAME_H_ +#define _QX_GET_CLASS_NAME_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file get_class_name.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::get_class_name::get() : return class name of type T under const char * format, T must be registered with QX_REGISTER_CLASS_NAME(T) macro + */ + +#ifndef _QX_NO_RTTI +#include +#endif // _QX_NO_RTTI + +#include + +#define QX_REGISTER_CLASS_NAME_SEP_INF "<" +#define QX_REGISTER_CLASS_NAME_SEP_SUP ">" +#define QX_REGISTER_CLASS_NAME_SEP_NXT ", " + +#define QX_REGISTER_CLASS_NAME_SEP_INF_XML_TAG "-" +#define QX_REGISTER_CLASS_NAME_SEP_SUP_XML_TAG "-" +#define QX_REGISTER_CLASS_NAME_SEP_NXT_XML_TAG "_" + +#define QX_GET_CLASS_NAME(TYPE) \ + qx::trait::get_class_name::type>::get() + +#define QX_GET_CLASS_NAME_STD_STR(TYPE) \ + std::string(qx::trait::get_class_name::type>::get()) + +#define QX_GET_CLASS_NAME_XML_TAG(TYPE) \ + qx::trait::get_class_name::type>::get_xml_tag() + +#define QX_GET_CLASS_NAME_XML_TAG_STD_STR(TYPE) \ + std::string(qx::trait::get_class_name::type>::get_xml_tag()) + +#define QX_GET_CLASS_NAME_WITH_TYPENAME(TYPE) \ + qx::trait::get_class_name::type>::get() + +#define QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(TYPE) \ + std::string(qx::trait::get_class_name::type>::get()) + +#define QX_GET_CLASS_NAME_XML_TAG_WITH_TYPENAME(TYPE) \ + qx::trait::get_class_name::type>::get_xml_tag() + +#define QX_GET_CLASS_NAME_XML_TAG_STD_STR_WITH_TYPENAME(TYPE) \ + std::string(qx::trait::get_class_name::type>::get_xml_tag()) + +#define QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG() \ + static inline const char *get_xml_tag() \ + { \ + static std::string result_xml; \ + if (!result_xml.empty()) \ + { \ + return result_xml.c_str(); \ + } \ + QString tmp = get_class_name::get(); \ + tmp.replace(QX_REGISTER_CLASS_NAME_SEP_INF, QX_REGISTER_CLASS_NAME_SEP_INF_XML_TAG); \ + tmp.replace(QX_REGISTER_CLASS_NAME_SEP_SUP, QX_REGISTER_CLASS_NAME_SEP_SUP_XML_TAG); \ + tmp.replace(QX_REGISTER_CLASS_NAME_SEP_NXT, QX_REGISTER_CLASS_NAME_SEP_NXT_XML_TAG); \ + tmp.replace("::", "."); \ + tmp.replace(" ", ""); \ + result_xml = tmp.toLatin1().constData(); \ + return result_xml.c_str(); \ + } + +#ifdef _QX_NO_RTTI +#define QX_REGISTER_CLASS_NAME_NO_RTTI(className) std::string(#className) +#endif // _QX_NO_RTTI + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::get_class_name::get() : return class name of type T under const char * format, T must be registered with QX_REGISTER_CLASS_NAME(T) macro + */ + template + struct get_class_name + { + + static inline const char *get() + { + static std::string result; + if (!result.empty()) + { + return result.c_str(); + } + +#ifndef _QX_NO_RTTI + T *dummy = NULL; + Q_UNUSED(dummy); + result = std::string(typeid(dummy).name()); +#else // _QX_NO_RTTI + result = QX_REGISTER_CLASS_NAME_NO_RTTI(T); +#endif // _QX_NO_RTTI + + qDebug("[QxOrm] Unable to define correct class name : '%s' => use macro 'QX_REGISTER_CLASS_NAME()' or 'QX_REGISTER_CLASS_NAME_TEMPLATE_X()'", result.c_str()); + return result.c_str(); + } + + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); + }; + + } // namespace trait +} // namespace qx + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className) \ + static std::string result; \ + if (!result.empty()) \ + { \ + return result.c_str(); \ + } \ + result = std::string(#className); + +#define QX_REGISTER_CLASS_NAME(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template <> \ + struct get_class_name \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_1(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_2(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_3(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_4(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_5(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T5) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_6(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T5) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T6) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_7(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T5) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T6) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T7) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_8(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T5) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T6) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T7) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T8) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#define QX_REGISTER_CLASS_NAME_TEMPLATE_9(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct get_class_name> \ + { \ + static inline const char *get() \ + { \ + QX_REGISTER_CLASS_NAME_TEMPLATE_INIT(className); \ + result += QX_REGISTER_CLASS_NAME_SEP_INF + QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T1) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T2) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T3) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T4) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T5) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T6) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T7) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T8) + QX_REGISTER_CLASS_NAME_SEP_NXT; \ + result += QX_GET_CLASS_NAME_STD_STR_WITH_TYPENAME(T9) + QX_REGISTER_CLASS_NAME_SEP_SUP; \ + return result.c_str(); \ + } \ + QX_GET_CLASS_NAME_IMPLEMENT_FCT_GET_XML_TAG(); \ + }; \ + } \ + } // namespace qx::trait + +#endif // _QX_GET_CLASS_NAME_H_ diff --git a/include/QxTraits/get_class_name_primitive.h b/include/QxTraits/get_class_name_primitive.h new file mode 100644 index 0000000..1832736 --- /dev/null +++ b/include/QxTraits/get_class_name_primitive.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** 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_GET_CLASS_NAME_PRIMITIVE_H_ +#define _QX_GET_CLASS_NAME_PRIMITIVE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file get_class_name_primitive.h + * \author XDL Team + * \ingroup QxTraits + * \brief Register all primitive and useful types of stl, boost and Qt libraries using QX_REGISTER_CLASS_NAME(T) macro + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#include + +#ifdef _QX_ENABLE_QT_GUI +#include +#include +#include +#include +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#include +#include +#endif // _QX_ENABLE_QT_GUI + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#include + +#include + +QX_REGISTER_CLASS_NAME(void) +QX_REGISTER_CLASS_NAME(bool) +QX_REGISTER_CLASS_NAME(int) +QX_REGISTER_CLASS_NAME(short) +QX_REGISTER_CLASS_NAME(long) +QX_REGISTER_CLASS_NAME(float) +QX_REGISTER_CLASS_NAME(double) +QX_REGISTER_CLASS_NAME(long double) +QX_REGISTER_CLASS_NAME(char) +QX_REGISTER_CLASS_NAME(unsigned int) +QX_REGISTER_CLASS_NAME(unsigned short) +QX_REGISTER_CLASS_NAME(unsigned long) +QX_REGISTER_CLASS_NAME(unsigned char) + +QX_REGISTER_CLASS_NAME(std::string) +QX_REGISTER_CLASS_NAME(std::wstring) + +QX_REGISTER_CLASS_NAME(QObject) +QX_REGISTER_CLASS_NAME(QString) +QX_REGISTER_CLASS_NAME(QStringList) +QX_REGISTER_CLASS_NAME(QByteArray) +QX_REGISTER_CLASS_NAME(QDate) +QX_REGISTER_CLASS_NAME(QDateTime) +QX_REGISTER_CLASS_NAME(QPoint) +QX_REGISTER_CLASS_NAME(QRect) +QX_REGISTER_CLASS_NAME(QSize) +QX_REGISTER_CLASS_NAME(QTime) +QX_REGISTER_CLASS_NAME(QUrl) +QX_REGISTER_CLASS_NAME(QVariant) +QX_REGISTER_CLASS_NAME(QUuid) +QX_REGISTER_CLASS_NAME(QSqlError) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_REGISTER_CLASS_NAME(QRegExp) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_QT_GUI +QX_REGISTER_CLASS_NAME(QColor) +QX_REGISTER_CLASS_NAME(QFont) +QX_REGISTER_CLASS_NAME(QImage) +QX_REGISTER_CLASS_NAME(QBrush) +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_REGISTER_CLASS_NAME(QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_REGISTER_CLASS_NAME(QPicture) +QX_REGISTER_CLASS_NAME(QPixmap) +QX_REGISTER_CLASS_NAME(QRegion) +#endif // _QX_ENABLE_QT_GUI + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::allocator) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::vector) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::list) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::set) + +#ifdef _QX_ENABLE_BOOST + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::shared_ptr) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::scoped_ptr) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::weak_ptr) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::optional) + +#endif // _QX_ENABLE_BOOST + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QList) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QSharedPointer) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QWeakPointer) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QFlags) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QSet) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QVector) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QLinkedList) +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(qx::dao::ptr) + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::unique_ptr) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::shared_ptr) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::weak_ptr) + +QX_REGISTER_CLASS_NAME_TEMPLATE_2(std::pair) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(std::map) + +#ifdef _QX_ENABLE_BOOST +QX_REGISTER_CLASS_NAME_TEMPLATE_2(boost::unordered_map) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(boost::unordered_multimap) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::unordered_set) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::unordered_multiset) +#endif // _QX_ENABLE_BOOST + +QX_REGISTER_CLASS_NAME_TEMPLATE_2(std::unordered_map) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(std::unordered_multimap) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::unordered_set) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::unordered_multiset) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(QPair) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_REGISTER_CLASS_NAME_TEMPLATE_2(QHash) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(QMultiHash) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(QMap) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(QMultiMap) + +#ifdef _QX_ENABLE_BOOST +QX_REGISTER_CLASS_NAME_TEMPLATE_1(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_3(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_4(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_5(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_6(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_7(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_8(boost::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_9(boost::tuple) +#endif // _QX_ENABLE_BOOST + +QX_REGISTER_CLASS_NAME_TEMPLATE_1(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_2(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_3(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_4(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_5(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_6(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_7(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_8(std::tuple) +QX_REGISTER_CLASS_NAME_TEMPLATE_9(std::tuple) + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +QX_REGISTER_CLASS_NAME_TEMPLATE_1(QScopedPointer) +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#endif // _QX_GET_CLASS_NAME_PRIMITIVE_H_ diff --git a/include/QxTraits/get_primary_key.h b/include/QxTraits/get_primary_key.h new file mode 100644 index 0000000..1bbf13b --- /dev/null +++ b/include/QxTraits/get_primary_key.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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_GET_PRIMARY_KEY_H_ +#define _QX_GET_PRIMARY_KEY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file get_primary_key.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::get_primary_key::type : return primary key type of T, by default primary key is long type, use QX_REGISTER_PRIMARY_KEY() macro to register another type (for example QX_REGISTER_PRIMARY_KEY(T, QString)) + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::get_primary_key::type : return primary key type of T, by default primary key is long type, use QX_REGISTER_PRIMARY_KEY() macro to register another type (for example QX_REGISTER_PRIMARY_KEY(T, QString)) + */ + template + class get_primary_key + { + public: + typedef long type; + }; + + } // namespace trait +} // namespace qx + +#define QX_REGISTER_PRIMARY_KEY(daoClass, primaryKey) \ + namespace qx \ + { \ + namespace trait \ + { \ + template <> \ + class get_primary_key \ + { \ + public: \ + typedef primaryKey type; \ + }; \ + } \ + } // namespace qx::trait + +#endif // _QX_GET_PRIMARY_KEY_H_ diff --git a/include/QxTraits/get_sql_type.h b/include/QxTraits/get_sql_type.h new file mode 100644 index 0000000..8412e71 --- /dev/null +++ b/include/QxTraits/get_sql_type.h @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** 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_GET_SQL_TYPE_H_ +#define _QX_GET_SQL_TYPE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file get_sql_type.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::get_sql_type::get() : return type name under const char * format used by database engine to map a C++ type T + */ + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace qx +{ + namespace trait + { + namespace detail + { + + template + struct get_sql_type_helper + { + + private: + typedef typename qx::trait::remove_attr::type type_1; + typedef typename std::conditional::value, typename qx::trait::get_primary_key::type, type_1>::type type_2; + typedef typename std::conditional::value, long, type_2>::type type_3; + + public: + typedef typename qx::trait::detail::get_sql_type_helper::type_3 type; + }; + + template + struct get_sql_type + { + static inline const char *get() { return ""; } + }; + + /* Implemented into './src/QxRegister/QxClassX.cpp' file */ + QX_DLL_EXPORT const char *get_sql_type_by_class_name(const char *sClassName, const char *sDefaultValue); + + } // namespace detail + + /*! + * \ingroup QxTraits + * \brief qx::trait::get_sql_type::get() : return type name under const char * format used by database engine to map a C++ type T + */ + template + struct get_sql_type + { + typedef typename qx::trait::detail::get_sql_type_helper::type type_sql; + static inline const char *get() { return (std::is_same::value ? qx::trait::detail::get_sql_type::get() : qx::trait::get_sql_type::get()); } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() { return qx::trait::get_sql_type::get(); } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_BOOST + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + template + struct get_sql_type> + { + static inline const char *get() + { + static std::string s; + s = (std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get()) + "|" + std::string(qx::trait::get_sql_type::get())); + return s.c_str(); + } + }; + + } // namespace trait +} // namespace qx + +#define QX_REGISTER_TRAIT_GET_SQL_TYPE(className, sqlType) \ + namespace qx \ + { \ + namespace trait \ + { \ + namespace detail \ + { \ + template <> \ + struct get_sql_type \ + { \ + static inline const char *get() { return get_sql_type_by_class_name(#className, sqlType); } \ + }; \ + } \ + } \ + } + +QX_REGISTER_TRAIT_GET_SQL_TYPE(bool, "SMALLINT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(qx_bool, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(char, "SMALLINT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(short, "SMALLINT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(int, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(long, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(long long, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(float, "FLOAT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(double, "FLOAT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(long double, "FLOAT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(unsigned short, "SMALLINT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(unsigned int, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(unsigned long, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(unsigned long long, "INTEGER") +QX_REGISTER_TRAIT_GET_SQL_TYPE(std::string, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(std::wstring, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QString, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QVariant, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QUuid, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QDate, "DATE") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QTime, "TIME") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QDateTime, "TIMESTAMP") +QX_REGISTER_TRAIT_GET_SQL_TYPE(QByteArray, "BLOB") +QX_REGISTER_TRAIT_GET_SQL_TYPE(qx::QxDateNeutral, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(qx::QxTimeNeutral, "TEXT") +QX_REGISTER_TRAIT_GET_SQL_TYPE(qx::QxDateTimeNeutral, "TEXT") + +#endif // _QX_GET_SQL_TYPE_H_ diff --git a/include/QxTraits/is_boost_intrusive_ptr.h b/include/QxTraits/is_boost_intrusive_ptr.h new file mode 100644 index 0000000..28eb3b3 --- /dev/null +++ b/include/QxTraits/is_boost_intrusive_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_INTRUSIVE_PTR_H_ +#define _QX_IS_BOOST_INTRUSIVE_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_intrusive_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_intrusive_ptr::value : return true if T is a boost::intrusive_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_intrusive_ptr::value : return true if T is a boost::intrusive_ptr<> smart-pointer, otherwise return false + */ + template + struct is_boost_intrusive_ptr : public std::false_type + { + ; + }; + + template + struct is_boost_intrusive_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_intrusive_ptr &> : public std::true_type + { + ; + }; + + template + struct is_boost_intrusive_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_intrusive_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_INTRUSIVE_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_boost_scoped_ptr.h b/include/QxTraits/is_boost_scoped_ptr.h new file mode 100644 index 0000000..871dd9f --- /dev/null +++ b/include/QxTraits/is_boost_scoped_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_SCOPED_PTR_H_ +#define _QX_IS_BOOST_SCOPED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_scoped_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_scoped_ptr::value : return true if T is a boost::scoped_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_scoped_ptr::value : return true if T is a boost::scoped_ptr<> smart-pointer, otherwise return false + */ + template + struct is_boost_scoped_ptr : public std::false_type + { + ; + }; + + template + struct is_boost_scoped_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_scoped_ptr &> : public std::true_type + { + ; + }; + + template + struct is_boost_scoped_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_scoped_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_SCOPED_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_boost_shared_ptr.h b/include/QxTraits/is_boost_shared_ptr.h new file mode 100644 index 0000000..eb2c095 --- /dev/null +++ b/include/QxTraits/is_boost_shared_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_SHARED_PTR_H_ +#define _QX_IS_BOOST_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_shared_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_shared_ptr::value : return true if T is a boost::shared_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_shared_ptr::value : return true if T is a boost::shared_ptr<> smart-pointer, otherwise return false + */ + template + struct is_boost_shared_ptr : public std::false_type + { + ; + }; + + template + struct is_boost_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_shared_ptr &> : public std::true_type + { + ; + }; + + template + struct is_boost_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_shared_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_SHARED_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_boost_unordered_map.h b/include/QxTraits/is_boost_unordered_map.h new file mode 100644 index 0000000..d9f76d1 --- /dev/null +++ b/include/QxTraits/is_boost_unordered_map.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_UNORDERED_MAP_H_ +#define _QX_IS_BOOST_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_unordered_map.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_unordered_map::value : return true if T is a boost::unordered_map<> or boost::unordered_multimap<> container, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_unordered_map::value : return true if T is a boost::unordered_map<> or boost::unordered_multimap<> container, otherwise return false + */ + template + struct is_boost_unordered_map : public std::false_type + { + ; + }; + + template + struct is_boost_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_map &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_UNORDERED_MAP_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_boost_unordered_set.h b/include/QxTraits/is_boost_unordered_set.h new file mode 100644 index 0000000..96c3f7c --- /dev/null +++ b/include/QxTraits/is_boost_unordered_set.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_UNORDERED_SET_H_ +#define _QX_IS_BOOST_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_unordered_set.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_unordered_set::value : return true if T is a boost::unordered_set<> or boost::unordered_multiset<> container, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_unordered_set::value : return true if T is a boost::unordered_set<> or boost::unordered_multiset<> container, otherwise return false + */ + template + struct is_boost_unordered_set : public std::false_type + { + ; + }; + + template + struct is_boost_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_boost_unordered_set &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_UNORDERED_SET_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_boost_weak_ptr.h b/include/QxTraits/is_boost_weak_ptr.h new file mode 100644 index 0000000..732a668 --- /dev/null +++ b/include/QxTraits/is_boost_weak_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST +#ifndef _QX_IS_BOOST_WEAK_PTR_H_ +#define _QX_IS_BOOST_WEAK_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_boost_weak_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_boost_weak_ptr::value : return true if T is a boost::weak_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_boost_weak_ptr::value : return true if T is a boost::weak_ptr<> smart-pointer, otherwise return false + */ + template + struct is_boost_weak_ptr : public std::false_type + { + ; + }; + + template + struct is_boost_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_weak_ptr &> : public std::true_type + { + ; + }; + + template + struct is_boost_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_boost_weak_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_BOOST_WEAK_PTR_H_ +#endif // _QX_ENABLE_BOOST diff --git a/include/QxTraits/is_container.h b/include/QxTraits/is_container.h new file mode 100644 index 0000000..f3a488a --- /dev/null +++ b/include/QxTraits/is_container.h @@ -0,0 +1,596 @@ +/**************************************************************************** +** +** 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_IS_CONTAINER_H_ +#define _QX_IS_CONTAINER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_container.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_container::value : return true if T is a container from stl, boost, Qt or QxOrm library, otherwise return false + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_container::value : return true if T is a container from stl, boost, Qt or QxOrm library, otherwise return false + */ + template + struct is_container : public std::false_type + { + ; + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + +#endif // _QX_ENABLE_BOOST + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + template + struct is_container> : public std::true_type + { + ; + }; + + template + struct is_container &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_CONTAINER_H_ diff --git a/include/QxTraits/is_container_base_of.h b/include/QxTraits/is_container_base_of.h new file mode 100644 index 0000000..39762f6 --- /dev/null +++ b/include/QxTraits/is_container_base_of.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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_IS_CONTAINER_BASE_OF_H_ +#define _QX_IS_CONTAINER_BASE_OF_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#define qx_container_base_of_test_0() (sizeof(qx::trait::is_container_base_of::removeContainer(b, d)) == sizeof(char)) +#define qx_container_base_of_test_1() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_std_vector), d)) == sizeof(char)) +#define qx_container_base_of_test_2() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_std_list), d)) == sizeof(char)) +#define qx_container_base_of_test_3() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_std_set), d)) == sizeof(char)) +#define qx_container_base_of_test_4() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_qt_vector), d)) == sizeof(char)) +#define qx_container_base_of_test_5() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_qt_list), d)) == sizeof(char)) +#define qx_container_base_of_test_6() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_qt_set), d)) == sizeof(char)) +#define qx_container_base_of_test_7() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_qt_linked_list), d)) == sizeof(char)) +#define qx_container_base_of_test_8() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_boost_unordered_set), d)) == sizeof(char)) +#define qx_container_base_of_test_9() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_boost_unordered_multi_set), d)) == sizeof(char)) + +#define qx_container_base_of_test_10() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_std_unordered_set), d)) == sizeof(char)) +#define qx_container_base_of_test_11() (sizeof(qx::trait::is_container_base_of::removeContainer((*b_std_unordered_multi_set), d)) == sizeof(char)) + +#define qx_container_base_of_all_test() \ + qx_container_base_of_test_1() || qx_container_base_of_test_2() || qx_container_base_of_test_3() || \ + qx_container_base_of_test_4() || qx_container_base_of_test_5() || qx_container_base_of_test_6() || \ + qx_container_base_of_test_7() || qx_container_base_of_test_8() || qx_container_base_of_test_9() || \ + qx_container_base_of_test_10() || qx_container_base_of_test_11() + +namespace qx +{ + namespace trait + { + + template + class is_container_base_of + { + + private: + template + static typename std::conditional::value, char, int>::type removeContainer(const std::vector &, const std::vector &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::list &, const std::list &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::set &, const std::set &); + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + static typename std::conditional::value, char, int>::type removeContainer(const QVector &, const QVector &); +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + static typename std::conditional::value, char, int>::type removeContainer(const QList &, const QList &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const QSet &, const QSet &); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + static typename std::conditional::value, char, int>::type removeContainer(const QLinkedList &, const QLinkedList &); +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +#ifdef _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeContainer(const boost::unordered_set &, const boost::unordered_set &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const boost::unordered_multiset &, const boost::unordered_multiset &); + +#endif // _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::unordered_set &, const std::unordered_set &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::unordered_multiset &, const std::unordered_multiset &); + + static int removeContainer(...); + static B b; + static D d; + + static std::vector *b_std_vector; + static std::list *b_std_list; + static std::set *b_std_set; + static QVector *b_qt_vector; + static QList *b_qt_list; + static QSet *b_qt_set; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + static QLinkedList *b_qt_linked_list; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +#ifdef _QX_ENABLE_BOOST + + static boost::unordered_set *b_boost_unordered_set; + static boost::unordered_multiset *b_boost_unordered_multi_set; + +#endif // _QX_ENABLE_BOOST + + static std::unordered_set *b_std_unordered_set; + static std::unordered_multiset *b_std_unordered_multi_set; + + enum + { + value_0 = (qx::trait::is_container::value) + }; + enum + { + value_1 = (qx::trait::is_container::value) + }; + enum + { + value_2 = ((value_0 && value_1) ? qx_container_base_of_test_0() : 0) + }; + enum + { + value_3 = ((value_0 && !value_1) ? qx_container_base_of_all_test() : 0) + }; + + public: + enum + { + value = (qx::trait::is_container_base_of::value_2 || qx::trait::is_container_base_of::value_3) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_CONTAINER_BASE_OF_H_ diff --git a/include/QxTraits/is_container_key_value.h b/include/QxTraits/is_container_key_value.h new file mode 100644 index 0000000..ddab4f8 --- /dev/null +++ b/include/QxTraits/is_container_key_value.h @@ -0,0 +1,310 @@ +/**************************************************************************** +** +** 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_IS_CONTAINER_KEY_VALUE_H_ +#define _QX_IS_CONTAINER_KEY_VALUE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_container_key_value.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_container_key_value::value : return true if T is a map or hash-map (with template format) container from stl, boost, Qt or QxOrm library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_container_key_value::value : return true if T is a map or hash-map (with template format) container from stl, boost, Qt or QxOrm library, otherwise return false + */ + template + struct is_container_key_value : public std::false_type + { + ; + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + +#endif // _QX_ENABLE_BOOST + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + template + struct is_container_key_value> : public std::true_type + { + ; + }; + + template + struct is_container_key_value &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_CONTAINER_KEY_VALUE_H_ diff --git a/include/QxTraits/is_container_to_pod.h b/include/QxTraits/is_container_to_pod.h new file mode 100644 index 0000000..9469f32 --- /dev/null +++ b/include/QxTraits/is_container_to_pod.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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_IS_CONTAINER_TO_POD_H_ +#define _QX_IS_CONTAINER_TO_POD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +namespace qx +{ + namespace trait + { + + template + class is_container_to_pod + { + + private: + template + static typename std::conditional::value, char, int>::type removeContainer(const std::vector &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::list &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::set &); + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + static typename std::conditional::value, char, int>::type removeContainer(const QVector &); +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + static typename std::conditional::value, char, int>::type removeContainer(const QList &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const QSet &); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + static typename std::conditional::value, char, int>::type removeContainer(const QLinkedList &); +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +#ifdef _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeContainer(const boost::unordered_set &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const boost::unordered_multiset &); + +#endif // _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::unordered_set &); + + template + static typename std::conditional::value, char, int>::type removeContainer(const std::unordered_multiset &); + + static int removeContainer(...); + static T t; + + public: + enum + { + value = (qx::trait::is_container::value && (sizeof(qx::trait::is_container_to_pod::removeContainer(t)) == sizeof(char))) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_CONTAINER_TO_POD_H_ diff --git a/include/QxTraits/is_equal.h b/include/QxTraits/is_equal.h new file mode 100644 index 0000000..bad32e7 --- /dev/null +++ b/include/QxTraits/is_equal.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** 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_TRAIT_IS_EQUAL_H_ +#define _QX_TRAIT_IS_EQUAL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_equal.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::has_operator_equal_equal::value : return true if T provides operator==() function, T must be registered with QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(T) macro + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_QT_GUI +#include +#include +#include +#include +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // _QX_ENABLE_QT_GUI + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::has_operator_equal_equal::value : return true if T provides operator==() function, T must be registered with QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(T) macro + */ + template + struct has_operator_equal_equal + { + enum + { + value = std::is_pointer::value + }; + }; + + } // namespace trait +} // namespace qx + +#define QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template <> \ + struct has_operator_equal_equal \ + { \ + enum \ + { \ + value = true \ + }; \ + }; \ + } \ + } // namespace qx::trait + +#define QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template \ + struct has_operator_equal_equal> \ + { \ + enum \ + { \ + value = true \ + }; \ + }; \ + } \ + } // namespace qx::trait + +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(bool) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(int) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(short) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(long) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(float) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(double) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(long double) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(char) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(unsigned int) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(unsigned short) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(unsigned long) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(unsigned char) + +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(std::string) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(std::wstring) + +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QString) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QByteArray) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QDate) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QDateTime) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QPoint) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QRect) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QSize) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QTime) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QUrl) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QVariant) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QUuid) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QRegExp) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_QT_GUI +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QColor) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QFont) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QImage) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QBrush) +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL(QRegion) +#endif // _QX_ENABLE_QT_GUI + +#ifdef _QX_ENABLE_BOOST +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(boost::shared_ptr) +#endif // _QX_ENABLE_BOOST + +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(QSharedPointer) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(QWeakPointer) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(qx::dao::ptr) + +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(std::shared_ptr) +QX_TYPE_HAS_OPERATOR_EQUAL_EQUAL_TEMPLATE_1(std::weak_ptr) + +#endif // _QX_TRAIT_IS_EQUAL_H_ diff --git a/include/QxTraits/is_ptr_base_of.h b/include/QxTraits/is_ptr_base_of.h new file mode 100644 index 0000000..a45189c --- /dev/null +++ b/include/QxTraits/is_ptr_base_of.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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_IS_PTR_BASE_OF_H_ +#define _QX_IS_PTR_BASE_OF_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_ptr_base_of.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_ptr_base_of::value : return true if B and D are pointer type and (*B) is a base class of (*D) or if B and D are same type, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_ptr_base_of::value : return true if B and D are pointer type and (*B) is a base class of (*D) or if B and D are same type, otherwise return false + */ + template + class is_ptr_base_of + { + + private: + template + static typename std::conditional::value, char, int>::type removePtr(const volatile V *const volatile, const volatile W *const volatile); + + static int removePtr(...); + static B b; + static D d; + + public: + enum + { + value = (std::is_pointer::value && std::is_pointer::value && (sizeof(qx::trait::is_ptr_base_of::removePtr(b, d)) == sizeof(char))) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_PTR_BASE_OF_H_ diff --git a/include/QxTraits/is_ptr_to_pod.h b/include/QxTraits/is_ptr_to_pod.h new file mode 100644 index 0000000..d5a3192 --- /dev/null +++ b/include/QxTraits/is_ptr_to_pod.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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_IS_PTR_TO_POD_H_ +#define _QX_IS_PTR_TO_POD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_ptr_to_pod.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_ptr_to_pod::value : return true if T is a pointer to a POD type (char, int, long, etc.), otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_ptr_to_pod::value : return true if T is a pointer to a POD type (char, int, long, etc.), otherwise return false + */ + template + class is_ptr_to_pod + { + + private: + template + static typename std::conditional::value, char, int>::type removePtr(const volatile U *const volatile); + + static int removePtr(...); + static T t; + + public: + enum + { + value = (std::is_pointer::value && (sizeof(qx::trait::is_ptr_to_pod::removePtr(t)) == sizeof(char))) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_PTR_TO_POD_H_ diff --git a/include/QxTraits/is_qt_hash.h b/include/QxTraits/is_qt_hash.h new file mode 100644 index 0000000..0e927bb --- /dev/null +++ b/include/QxTraits/is_qt_hash.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_HASH_H_ +#define _QX_IS_QT_HASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_hash.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_hash::value : return true if T is a QHash<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_hash::value : return true if T is a QHash<> container of Qt library, otherwise return false + */ + template + struct is_qt_hash : public std::false_type + { + ; + }; + + template + struct is_qt_hash> : public std::true_type + { + ; + }; + + template + struct is_qt_hash &> : public std::true_type + { + ; + }; + + template + struct is_qt_hash> : public std::true_type + { + ; + }; + + template + struct is_qt_hash &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_HASH_H_ diff --git a/include/QxTraits/is_qt_linked_list.h b/include/QxTraits/is_qt_linked_list.h new file mode 100644 index 0000000..dad7541 --- /dev/null +++ b/include/QxTraits/is_qt_linked_list.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +#ifndef _QX_IS_QT_LINKED_LIST_H_ +#define _QX_IS_QT_LINKED_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_linked_list.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_linked_list::value : return true if T is a QLinkedList<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_linked_list::value : return true if T is a QLinkedList<> container of Qt library, otherwise return false + */ + template + struct is_qt_linked_list : public std::false_type + { + ; + }; + + template + struct is_qt_linked_list> : public std::true_type + { + ; + }; + + template + struct is_qt_linked_list &> : public std::true_type + { + ; + }; + + template + struct is_qt_linked_list> : public std::true_type + { + ; + }; + + template + struct is_qt_linked_list &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_LINKED_LIST_H_ +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) diff --git a/include/QxTraits/is_qt_list.h b/include/QxTraits/is_qt_list.h new file mode 100644 index 0000000..d297f7a --- /dev/null +++ b/include/QxTraits/is_qt_list.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_LIST_H_ +#define _QX_IS_QT_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_list.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_list::value : return true if T is a QList<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_list::value : return true if T is a QList<> container of Qt library, otherwise return false + */ + template + struct is_qt_list : public std::false_type + { + ; + }; + + template + struct is_qt_list> : public std::true_type + { + ; + }; + + template + struct is_qt_list &> : public std::true_type + { + ; + }; + + template + struct is_qt_list> : public std::true_type + { + ; + }; + + template + struct is_qt_list &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_LIST_H_ diff --git a/include/QxTraits/is_qt_map.h b/include/QxTraits/is_qt_map.h new file mode 100644 index 0000000..58e815c --- /dev/null +++ b/include/QxTraits/is_qt_map.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_MAP_H_ +#define _QX_IS_QT_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_map.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_map::value : return true if T is a QMap<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_map::value : return true if T is a QMap<> container of Qt library, otherwise return false + */ + template + struct is_qt_map : public std::false_type + { + ; + }; + + template + struct is_qt_map> : public std::true_type + { + ; + }; + + template + struct is_qt_map &> : public std::true_type + { + ; + }; + + template + struct is_qt_map> : public std::true_type + { + ; + }; + + template + struct is_qt_map &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_MAP_H_ diff --git a/include/QxTraits/is_qt_multi_hash.h b/include/QxTraits/is_qt_multi_hash.h new file mode 100644 index 0000000..defdaa6 --- /dev/null +++ b/include/QxTraits/is_qt_multi_hash.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_MULTI_HASH_H_ +#define _QX_IS_QT_MULTI_HASH_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_multi_hash.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_multi_hash::value : return true if T is a QMultiHash<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_multi_hash::value : return true if T is a QMultiHash<> container of Qt library, otherwise return false + */ + template + struct is_qt_multi_hash : public std::false_type + { + ; + }; + + template + struct is_qt_multi_hash> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_hash &> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_hash> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_hash &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_MULTI_HASH_H_ diff --git a/include/QxTraits/is_qt_multi_map.h b/include/QxTraits/is_qt_multi_map.h new file mode 100644 index 0000000..35d9478 --- /dev/null +++ b/include/QxTraits/is_qt_multi_map.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_MULTI_MAP_H_ +#define _QX_IS_QT_MULTI_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_multi_map.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_multi_map::value : return true if T is a QMultiMap<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_multi_map::value : return true if T is a QMultiMap<> container of Qt library, otherwise return false + */ + template + struct is_qt_multi_map : public std::false_type + { + ; + }; + + template + struct is_qt_multi_map> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_map &> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_map> : public std::true_type + { + ; + }; + + template + struct is_qt_multi_map &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_MULTI_MAP_H_ diff --git a/include/QxTraits/is_qt_scoped_ptr.h b/include/QxTraits/is_qt_scoped_ptr.h new file mode 100644 index 0000000..c9974b3 --- /dev/null +++ b/include/QxTraits/is_qt_scoped_ptr.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#ifndef _QX_IS_QT_SCOPED_PTR_H_ +#define _QX_IS_QT_SCOPED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_scoped_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_scoped_ptr::value : return true if T is a QScopedPointer<> smart-pointer of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_scoped_ptr::value : return true if T is a QScopedPointer<> smart-pointer of Qt library, otherwise return false + */ + template + struct is_qt_scoped_ptr : public std::false_type + { + ; + }; + + template + struct is_qt_scoped_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_scoped_ptr &> : public std::true_type + { + ; + }; + + template + struct is_qt_scoped_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_scoped_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_SCOPED_PTR_H_ +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#if (QT_VERSION < QT_VERSION_CHECK(4, 6, 0)) +#ifndef _QX_IS_QT_SCOPED_PTR_H_ +#define _QX_IS_QT_SCOPED_PTR_H_ +namespace qx +{ + namespace trait + { + template + class is_qt_scoped_ptr + { + public: + enum + { + value = false + }; + typedef std::false_type type; + }; + } +} // namespace qx::trait +#endif // _QX_IS_QT_SCOPED_PTR_H_ +#endif // (QT_VERSION < QT_VERSION_CHECK(4, 6, 0)) diff --git a/include/QxTraits/is_qt_set.h b/include/QxTraits/is_qt_set.h new file mode 100644 index 0000000..03936fe --- /dev/null +++ b/include/QxTraits/is_qt_set.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_SET_H_ +#define _QX_IS_QT_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_set.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_set::value : return true if T is a QSet<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_set::value : return true if T is a QSet<> container of Qt library, otherwise return false + */ + template + struct is_qt_set : public std::false_type + { + ; + }; + + template + struct is_qt_set> : public std::true_type + { + ; + }; + + template + struct is_qt_set &> : public std::true_type + { + ; + }; + + template + struct is_qt_set> : public std::true_type + { + ; + }; + + template + struct is_qt_set &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_SET_H_ diff --git a/include/QxTraits/is_qt_shared_data_ptr.h b/include/QxTraits/is_qt_shared_data_ptr.h new file mode 100644 index 0000000..9b5c27c --- /dev/null +++ b/include/QxTraits/is_qt_shared_data_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_SHARED_DATA_PTR_H_ +#define _QX_IS_QT_SHARED_DATA_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_shared_data_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_shared_data_ptr::value : return true if T is a QSharedDataPointer<> smart-pointer of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_shared_data_ptr::value : return true if T is a QSharedDataPointer<> smart-pointer of Qt library, otherwise return false + */ + template + struct is_qt_shared_data_ptr : public std::false_type + { + ; + }; + + template + struct is_qt_shared_data_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_data_ptr &> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_data_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_data_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_SHARED_DATA_PTR_H_ diff --git a/include/QxTraits/is_qt_shared_ptr.h b/include/QxTraits/is_qt_shared_ptr.h new file mode 100644 index 0000000..9ecb7a8 --- /dev/null +++ b/include/QxTraits/is_qt_shared_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_SHARED_PTR_H_ +#define _QX_IS_QT_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_shared_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_shared_ptr::value : return true if T is a QSharedPointer<> smart-pointer of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_shared_ptr::value : return true if T is a QSharedPointer<> smart-pointer of Qt library, otherwise return false + */ + template + struct is_qt_shared_ptr : public std::false_type + { + ; + }; + + template + struct is_qt_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_ptr &> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_shared_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_SHARED_PTR_H_ diff --git a/include/QxTraits/is_qt_variant_compatible.h b/include/QxTraits/is_qt_variant_compatible.h new file mode 100644 index 0000000..70b0f47 --- /dev/null +++ b/include/QxTraits/is_qt_variant_compatible.h @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** 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_IS_QT_VARIANT_COMPATIBLE_H_ +#define _QX_IS_QT_VARIANT_COMPATIBLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_variant_compatible.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_variant_compatible::value : return true if T can be host into a QVariant object of Qt library, otherwise return false + */ + +#include + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_variant_compatible::value : return true if T can be host into a QVariant object of Qt library, otherwise return false + */ + template + struct is_qt_variant_compatible + { + enum + { + value = (std::is_enum::value || std::is_integral::value) + }; + }; + + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_QT_GUI + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible + { + enum + { + value = true + }; + }; +#endif // _QX_ENABLE_QT_GUI + + template <> + struct is_qt_variant_compatible> + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible> + { + enum + { + value = true + }; + }; + template <> + struct is_qt_variant_compatible> + { + enum + { + value = true + }; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_VARIANT_COMPATIBLE_H_ diff --git a/include/QxTraits/is_qt_vector.h b/include/QxTraits/is_qt_vector.h new file mode 100644 index 0000000..bcd6dc4 --- /dev/null +++ b/include/QxTraits/is_qt_vector.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_VECTOR_H_ +#define _QX_IS_QT_VECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_vector.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_vector::value : return true if T is a QVector<> container of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_vector::value : return true if T is a QVector<> container of Qt library, otherwise return false + */ + template + struct is_qt_vector : public std::false_type + { + ; + }; + + template + struct is_qt_vector> : public std::true_type + { + ; + }; + + template + struct is_qt_vector &> : public std::true_type + { + ; + }; + + template + struct is_qt_vector> : public std::true_type + { + ; + }; + + template + struct is_qt_vector &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_VECTOR_H_ diff --git a/include/QxTraits/is_qt_weak_ptr.h b/include/QxTraits/is_qt_weak_ptr.h new file mode 100644 index 0000000..a7a11b9 --- /dev/null +++ b/include/QxTraits/is_qt_weak_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QT_WEAK_PTR_H_ +#define _QX_IS_QT_WEAK_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qt_weak_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qt_weak_ptr::value : return true if T is a QWeakPointer<> smart-pointer of Qt library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qt_weak_ptr::value : return true if T is a QWeakPointer<> smart-pointer of Qt library, otherwise return false + */ + template + struct is_qt_weak_ptr : public std::false_type + { + ; + }; + + template + struct is_qt_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_weak_ptr &> : public std::true_type + { + ; + }; + + template + struct is_qt_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_qt_weak_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QT_WEAK_PTR_H_ diff --git a/include/QxTraits/is_qx_collection.h b/include/QxTraits/is_qx_collection.h new file mode 100644 index 0000000..2fe2f44 --- /dev/null +++ b/include/QxTraits/is_qx_collection.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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_IS_QX_COLLECTION_H_ +#define _QX_IS_QX_COLLECTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qx_collection.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qx_collection::value : return true if T is a qx::QxCollection<> container of QxOrm library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qx_collection::value : return true if T is a qx::QxCollection<> container of QxOrm library, otherwise return false + */ + template + class is_qx_collection + { + + public: + enum + { + value = std::is_base_of::value + }; + + typedef typename std::conditional::value, + std::true_type, + std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QX_COLLECTION_H_ diff --git a/include/QxTraits/is_qx_dao_ptr.h b/include/QxTraits/is_qx_dao_ptr.h new file mode 100644 index 0000000..c6f24b3 --- /dev/null +++ b/include/QxTraits/is_qx_dao_ptr.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_QX_DAO_PTR_H_ +#define _QX_IS_QX_DAO_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qx_dao_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qx_dao_ptr::value : return true if T is a qx::dao::ptr<> smart-pointer of QxOrm library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qx_dao_ptr::value : return true if T is a qx::dao::ptr<> smart-pointer of QxOrm library, otherwise return false + */ + template + struct is_qx_dao_ptr : public std::false_type + { + ; + }; + + template + struct is_qx_dao_ptr> : public std::true_type + { + ; + }; + + template + struct is_qx_dao_ptr &> : public std::true_type + { + ; + }; + + template + struct is_qx_dao_ptr> : public std::true_type + { + ; + }; + + template + struct is_qx_dao_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QX_DAO_PTR_H_ diff --git a/include/QxTraits/is_qx_pod.h b/include/QxTraits/is_qx_pod.h new file mode 100644 index 0000000..f08935c --- /dev/null +++ b/include/QxTraits/is_qx_pod.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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_IS_QX_POD_H_ +#define _QX_IS_QX_POD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qx_pod.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qx_pod::value : return true if T is a POD type and not a pointer + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qx_pod::value : return true if T is a POD type and not a pointer + */ + template + struct is_qx_pod + { + + enum + { + value = (std::is_pod::value && !std::is_pointer::value && !std::is_member_pointer::value) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_QX_POD_H_ diff --git a/include/QxTraits/is_qx_registered.h b/include/QxTraits/is_qx_registered.h new file mode 100644 index 0000000..99b2229 --- /dev/null +++ b/include/QxTraits/is_qx_registered.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_IS_QX_REGISTERED_H_ +#define _QX_IS_QX_REGISTERED_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_qx_registered.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_qx_registered::value : return true if T is registered into QxOrm context to provide persitence (ORM), serialization and introspection features + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_qx_registered::value : return true if T is registered into QxOrm context to provide persitence (ORM), serialization and introspection features + */ + template + struct is_qx_registered + { + enum + { + value = false + }; + }; + + } // namespace trait +} // namespace qx + +#define QX_SET_REGISTERED(className) \ + namespace qx \ + { \ + namespace trait \ + { \ + template <> \ + struct is_qx_registered \ + { \ + enum \ + { \ + value = true \ + }; \ + }; \ + } \ + } // namespace qx::trait + +#endif // _QX_IS_QX_REGISTERED_H_ diff --git a/include/QxTraits/is_smart_ptr.h b/include/QxTraits/is_smart_ptr.h new file mode 100644 index 0000000..e327485 --- /dev/null +++ b/include/QxTraits/is_smart_ptr.h @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** 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_IS_SMART_PTR_H_ +#define _QX_IS_SMART_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_smart_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr::value : return true if T is a smart-pointer of boost, Qt or QxOrm libraries, otherwise return false + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr::value : return true if T is a smart-pointer of boost, Qt or QxOrm libraries, otherwise return false + */ + template + struct is_smart_ptr : public std::false_type + { + ; + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + +#endif // _QX_ENABLE_BOOST + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr> : public std::true_type + { + ; + }; + + template + struct is_smart_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_SMART_PTR_H_ diff --git a/include/QxTraits/is_smart_ptr_base_of.h b/include/QxTraits/is_smart_ptr_base_of.h new file mode 100644 index 0000000..c4bc51d --- /dev/null +++ b/include/QxTraits/is_smart_ptr_base_of.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** 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_IS_SMART_PTR_BASE_OF_H_ +#define _QX_IS_SMART_PTR_BASE_OF_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_smart_ptr_base_of.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr_base_of::value : return true if B and D are smart-pointers of boost, Qt or QxOrm libraries and if (*B) is a base class of (*D), otherwise return false + */ + +#include + +#define qx_smart_ptr_base_of_test_0() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr(b, d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_1() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_boost_scoped_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_2() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_boost_shared_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_3() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_boost_weak_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_4() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_boost_intrusive_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_5() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_qt_shared_data_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_6() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_qt_shared_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_7() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_qt_weak_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_8() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_qx_dao_ptr), d)) == sizeof(char)) + +#define qx_smart_ptr_base_of_test_9() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_std_unique_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_10() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_std_shared_ptr), d)) == sizeof(char)) +#define qx_smart_ptr_base_of_test_11() (sizeof(qx::trait::is_smart_ptr_base_of::removeSmartPtr((*b_std_weak_ptr), d)) == sizeof(char)) + +#define qx_smart_ptr_base_of_all_test() \ + qx_smart_ptr_base_of_test_1() || qx_smart_ptr_base_of_test_2() || qx_smart_ptr_base_of_test_3() || \ + qx_smart_ptr_base_of_test_4() || qx_smart_ptr_base_of_test_5() || qx_smart_ptr_base_of_test_6() || \ + qx_smart_ptr_base_of_test_7() || qx_smart_ptr_base_of_test_8() || qx_smart_ptr_base_of_test_9() || \ + qx_smart_ptr_base_of_test_10() || qx_smart_ptr_base_of_test_11() + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr_base_of::value : return true if B and D are smart-pointers of boost, Qt or QxOrm libraries and if (*B) is a base class of (*D), otherwise return false + */ + template + class is_smart_ptr_base_of + { + + private: +#ifdef _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::scoped_ptr &, const boost::scoped_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::shared_ptr &, const boost::shared_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::weak_ptr &, const boost::weak_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::intrusive_ptr &, const boost::intrusive_ptr &); + +#endif // _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QSharedDataPointer &, const QSharedDataPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QSharedPointer &, const QSharedPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QWeakPointer &, const QWeakPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const qx::dao::ptr &, const qx::dao::ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::unique_ptr &, const std::unique_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::shared_ptr &, const std::shared_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::weak_ptr &, const std::weak_ptr &); + + static int removeSmartPtr(...); + static B b; + static D d; + +#ifdef _QX_ENABLE_BOOST + + static boost::scoped_ptr *b_boost_scoped_ptr; + static boost::shared_ptr *b_boost_shared_ptr; + static boost::weak_ptr *b_boost_weak_ptr; + static boost::intrusive_ptr *b_boost_intrusive_ptr; + +#endif // _QX_ENABLE_BOOST + + static QSharedDataPointer *b_qt_shared_data_ptr; + static QSharedPointer *b_qt_shared_ptr; + static QWeakPointer *b_qt_weak_ptr; + static qx::dao::ptr *b_qx_dao_ptr; + + static std::unique_ptr *b_std_unique_ptr; + static std::shared_ptr *b_std_shared_ptr; + static std::weak_ptr *b_std_weak_ptr; + + enum + { + value_0 = (qx::trait::is_smart_ptr::value) + }; + enum + { + value_1 = (qx::trait::is_smart_ptr::value) + }; + enum + { + value_2 = ((value_0 && value_1) ? qx_smart_ptr_base_of_test_0() : 0) + }; + enum + { + value_3 = ((value_0 && !value_1) ? qx_smart_ptr_base_of_all_test() : 0) + }; + + public: + enum + { + value = (qx::trait::is_smart_ptr_base_of::value_2 || qx::trait::is_smart_ptr_base_of::value_3) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_SMART_PTR_BASE_OF_H_ diff --git a/include/QxTraits/is_smart_ptr_to_pod.h b/include/QxTraits/is_smart_ptr_to_pod.h new file mode 100644 index 0000000..9cda1bd --- /dev/null +++ b/include/QxTraits/is_smart_ptr_to_pod.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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_IS_SMART_PTR_TO_POD_H_ +#define _QX_IS_SMART_PTR_TO_POD_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_smart_ptr_to_pod.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr_to_pod::value : return true if T is a smart-pointer of boost, Qt or QxOrm libraries and (*T) is a POD type (char, int, long, etc.), otherwise return false + */ + +#include +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_smart_ptr_to_pod::value : return true if T is a smart-pointer of boost, Qt or QxOrm libraries and (*T) is a POD type (char, int, long, etc.), otherwise return false + */ + template + class is_smart_ptr_to_pod + { + + private: +#ifdef _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::scoped_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::shared_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::weak_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const boost::intrusive_ptr &); + +#endif // _QX_ENABLE_BOOST + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QSharedDataPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QSharedPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const QWeakPointer &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const qx::dao::ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::unique_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::shared_ptr &); + + template + static typename std::conditional::value, char, int>::type removeSmartPtr(const std::weak_ptr &); + + static int removeSmartPtr(...); + static T t; + + public: + enum + { + value = (qx::trait::is_smart_ptr::value && (sizeof(qx::trait::is_smart_ptr_to_pod::removeSmartPtr(t)) == sizeof(char))) + }; + + typedef typename std::conditional::value, std::true_type, std::false_type>::type type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_SMART_PTR_TO_POD_H_ diff --git a/include/QxTraits/is_std_list.h b/include/QxTraits/is_std_list.h new file mode 100644 index 0000000..c12b670 --- /dev/null +++ b/include/QxTraits/is_std_list.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_STD_LIST_H_ +#define _QX_IS_STD_LIST_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_list.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_list::value : return true if T is a std::list<> container of stl library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_list::value : return true if T is a std::list<> container of stl library, otherwise return false + */ + template + struct is_std_list : public std::false_type + { + ; + }; + + template + struct is_std_list> : public std::true_type + { + ; + }; + + template + struct is_std_list &> : public std::true_type + { + ; + }; + + template + struct is_std_list> : public std::true_type + { + ; + }; + + template + struct is_std_list &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_LIST_H_ diff --git a/include/QxTraits/is_std_map.h b/include/QxTraits/is_std_map.h new file mode 100644 index 0000000..ce06c04 --- /dev/null +++ b/include/QxTraits/is_std_map.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_STD_MAP_H_ +#define _QX_IS_STD_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_map.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_map::value : return true if T is a std::map<> container of stl library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_map::value : return true if T is a std::map<> container of stl library, otherwise return false + */ + template + struct is_std_map : public std::false_type + { + ; + }; + + template + struct is_std_map> : public std::true_type + { + ; + }; + + template + struct is_std_map &> : public std::true_type + { + ; + }; + + template + struct is_std_map> : public std::true_type + { + ; + }; + + template + struct is_std_map &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_MAP_H_ diff --git a/include/QxTraits/is_std_set.h b/include/QxTraits/is_std_set.h new file mode 100644 index 0000000..97118bf --- /dev/null +++ b/include/QxTraits/is_std_set.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_STD_SET_H_ +#define _QX_IS_STD_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_set.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_set::value : return true if T is a std::set<> container of stl library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_set::value : return true if T is a std::set<> container of stl library, otherwise return false + */ + template + struct is_std_set : public std::false_type + { + ; + }; + + template + struct is_std_set> : public std::true_type + { + ; + }; + + template + struct is_std_set &> : public std::true_type + { + ; + }; + + template + struct is_std_set> : public std::true_type + { + ; + }; + + template + struct is_std_set &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_SET_H_ diff --git a/include/QxTraits/is_std_shared_ptr.h b/include/QxTraits/is_std_shared_ptr.h new file mode 100644 index 0000000..f5813ae --- /dev/null +++ b/include/QxTraits/is_std_shared_ptr.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_IS_STD_SHARED_PTR_H_ +#define _QX_IS_STD_SHARED_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_shared_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_shared_ptr::value : return true if T is a std::shared_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_shared_ptr::value : return true if T is a std::shared_ptr<> smart-pointer, otherwise return false + */ + template + struct is_std_shared_ptr : public std::false_type + { + ; + }; + + template + struct is_std_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_shared_ptr &> : public std::true_type + { + ; + }; + + template + struct is_std_shared_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_shared_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_SHARED_PTR_H_ diff --git a/include/QxTraits/is_std_unique_ptr.h b/include/QxTraits/is_std_unique_ptr.h new file mode 100644 index 0000000..30d426f --- /dev/null +++ b/include/QxTraits/is_std_unique_ptr.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_IS_STD_UNIQUE_PTR_H_ +#define _QX_IS_STD_UNIQUE_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_unique_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_unique_ptr::value : return true if T is a std::unique_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_unique_ptr::value : return true if T is a std::unique_ptr<> smart-pointer, otherwise return false + */ + template + struct is_std_unique_ptr : public std::false_type + { + ; + }; + + template + struct is_std_unique_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_unique_ptr &> : public std::true_type + { + ; + }; + + template + struct is_std_unique_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_unique_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_UNIQUE_PTR_H_ diff --git a/include/QxTraits/is_std_unordered_map.h b/include/QxTraits/is_std_unordered_map.h new file mode 100644 index 0000000..b55347b --- /dev/null +++ b/include/QxTraits/is_std_unordered_map.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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_IS_STD_UNORDERED_MAP_H_ +#define _QX_IS_STD_UNORDERED_MAP_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_unordered_map.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_unordered_map::value : return true if T is a std::unordered_map<> or std::unordered_multimap<> container, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_unordered_map::value : return true if T is a std::unordered_map<> or std::unordered_multimap<> container, otherwise return false + */ + template + struct is_std_unordered_map : public std::false_type + { + ; + }; + + template + struct is_std_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_map &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_UNORDERED_MAP_H_ diff --git a/include/QxTraits/is_std_unordered_set.h b/include/QxTraits/is_std_unordered_set.h new file mode 100644 index 0000000..cce4cba --- /dev/null +++ b/include/QxTraits/is_std_unordered_set.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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_IS_STD_UNORDERED_SET_H_ +#define _QX_IS_STD_UNORDERED_SET_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_unordered_set.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_unordered_set::value : return true if T is a std::unordered_set<> or std::unordered_multiset<> container, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_unordered_set::value : return true if T is a std::unordered_set<> or std::unordered_multiset<> container, otherwise return false + */ + template + struct is_std_unordered_set : public std::false_type + { + ; + }; + + template + struct is_std_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set &> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set> : public std::true_type + { + ; + }; + + template + struct is_std_unordered_set &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_UNORDERED_SET_H_ diff --git a/include/QxTraits/is_std_vector.h b/include/QxTraits/is_std_vector.h new file mode 100644 index 0000000..4c697e0 --- /dev/null +++ b/include/QxTraits/is_std_vector.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_IS_STD_VECTOR_H_ +#define _QX_IS_STD_VECTOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_vector.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_vector::value : return true if T is a std::vector<> container of stl library, otherwise return false + */ + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_vector::value : return true if T is a std::vector<> container of stl library, otherwise return false + */ + template + struct is_std_vector : public std::false_type + { + ; + }; + + template + struct is_std_vector> : public std::true_type + { + ; + }; + + template + struct is_std_vector &> : public std::true_type + { + ; + }; + + template + struct is_std_vector> : public std::true_type + { + ; + }; + + template + struct is_std_vector &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_VECTOR_H_ diff --git a/include/QxTraits/is_std_weak_ptr.h b/include/QxTraits/is_std_weak_ptr.h new file mode 100644 index 0000000..811d1fe --- /dev/null +++ b/include/QxTraits/is_std_weak_ptr.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_IS_STD_WEAK_PTR_H_ +#define _QX_IS_STD_WEAK_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_std_weak_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_std_weak_ptr::value : return true if T is a std::weak_ptr<> smart-pointer, otherwise return false + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_std_weak_ptr::value : return true if T is a std::weak_ptr<> smart-pointer, otherwise return false + */ + template + struct is_std_weak_ptr : public std::false_type + { + ; + }; + + template + struct is_std_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_weak_ptr &> : public std::true_type + { + ; + }; + + template + struct is_std_weak_ptr> : public std::true_type + { + ; + }; + + template + struct is_std_weak_ptr &> : public std::true_type + { + ; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_STD_WEAK_PTR_H_ diff --git a/include/QxTraits/is_valid_primary_key.h b/include/QxTraits/is_valid_primary_key.h new file mode 100644 index 0000000..acde9fe --- /dev/null +++ b/include/QxTraits/is_valid_primary_key.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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_IS_VALID_PRIMARY_KEY_H_ +#define _QX_IS_VALID_PRIMARY_KEY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file is_valid_primary_key.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::is_valid_primary_key(const T & t) : return true if t can be a valid primary key to be inserted into a database, otherwise return false + */ + +namespace qx +{ + namespace trait + { + namespace detail + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::is_valid_primary_key(const T & t) : return true if t can be a valid primary key to be inserted into a database, otherwise return false + */ + template + struct is_valid_primary_key + { + static inline bool get(const T &t) + { + Q_UNUSED(t); + qAssert(false); + return false; + } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const short &t) { return (t != 0); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const int &t) { return (t != 0); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const long &t) { return (t != 0); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const long long &t) { return (t != 0); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const QString &t) { return (!t.isEmpty()); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const QByteArray &t) { return (!t.isEmpty()); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const std::string &t) { return (!t.empty()); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const std::wstring &t) { return (!t.empty()); } + }; + + template <> + struct is_valid_primary_key + { + static inline bool get(const QVariant &t) + { + if (t.type() == QVariant::ByteArray) + { + return qx::trait::detail::is_valid_primary_key::get(t.toByteArray()); + } + if (t.type() == QVariant::String) + { + return qx::trait::detail::is_valid_primary_key::get(t.toString()); + } + return (!t.isNull() && (t.toLongLong() != 0)); + } + }; + + } // namespace detail + + template + inline bool is_valid_primary_key(const T &t) + { + return qx::trait::detail::is_valid_primary_key::get(t); + } + + } // namespace trait +} // namespace qx + +#endif // _QX_IS_VALID_PRIMARY_KEY_H_ diff --git a/include/QxTraits/qt_meta_object.h b/include/QxTraits/qt_meta_object.h new file mode 100644 index 0000000..3a035b1 --- /dev/null +++ b/include/QxTraits/qt_meta_object.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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_QT_META_OBJECT_H_ +#define _QX_QT_META_OBJECT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file qt_meta_object.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::qt_meta_object::get() : if T is based on QObject class, then return QMetaObject instance of Qt introspection engine, else return NULL + */ + +#include +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::qt_meta_object::get() : if T is based on QObject class, then return QMetaObject instance of Qt introspection engine, else return NULL + */ + template + class qt_meta_object + { + + public: + enum + { + is_valid = (std::is_base_of::value) + }; + + static const QMetaObject *get() + { + return qtMetaObject::is_valid, 0>::get(); + } + + private: + template + struct qtMetaObject + { + static inline const QMetaObject *get() { return NULL; } + }; + + template + struct qtMetaObject + { + static inline const QMetaObject *get() { return (&T::staticMetaObject); } + }; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_QT_META_OBJECT_H_ diff --git a/include/QxTraits/qx_traits.h b/include/QxTraits/qx_traits.h new file mode 100644 index 0000000..7978374 --- /dev/null +++ b/include/QxTraits/qx_traits.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_TRAITS_H_ +#define _QX_TRAITS_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _QX_ENABLE_BOOST +#include +#include +#include +#include +#include +#include +#endif // _QX_ENABLE_BOOST + +#endif // _QX_TRAITS_H_ diff --git a/include/QxTraits/remove_attr.h b/include/QxTraits/remove_attr.h new file mode 100644 index 0000000..818e198 --- /dev/null +++ b/include/QxTraits/remove_attr.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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_REMOVE_ATTR_H_ +#define _QX_REMOVE_ATTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file remove_attr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::remove_attr::type : return a type without pointer, const, reference and/or volatile attributes + */ + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::remove_attr::type : return a type without pointer, const, reference and/or volatile attributes + */ + template + class remove_attr + { + + private: + typedef typename std::conditional::type, T>::type type_1; + typedef typename std::conditional::type, type_1>::type type_2; + typedef typename std::conditional::type, type_2>::type type_3; + typedef typename std::conditional::type, type_3>::type type_4; + + public: + typedef type_4 type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_REMOVE_ATTR_H_ diff --git a/include/QxTraits/remove_smart_ptr.h b/include/QxTraits/remove_smart_ptr.h new file mode 100644 index 0000000..dd2ff34 --- /dev/null +++ b/include/QxTraits/remove_smart_ptr.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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_REMOVE_SMART_PTR_H_ +#define _QX_REMOVE_SMART_PTR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file remove_smart_ptr.h + * \author XDL Team + * \ingroup QxTraits + * \brief qx::trait::remove_smart_ptr::type : return a type without smart-pointer attribute from boost, Qt or QxOrm library + */ + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + +#include + +namespace qx +{ + namespace trait + { + + /*! + * \ingroup QxTraits + * \brief qx::trait::remove_smart_ptr::type : return a type without smart-pointer attribute from boost, Qt or QxOrm library + */ + template + struct remove_smart_ptr + { + typedef T type; + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct remove_smart_ptr> + { + typedef T type; + }; + + template + struct remove_smart_ptr> + { + typedef T type; + }; + + template + struct remove_smart_ptr> + { + typedef T type; + }; + +#endif // _QX_ENABLE_BOOST + + template + struct remove_smart_ptr> + { + typedef T type; + }; + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + template + struct remove_smart_ptr> + { + typedef T type; + }; +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + + template + struct remove_smart_ptr> + { + typedef T type; + }; + + template + struct remove_smart_ptr> + { + typedef T type; + }; + + template + struct remove_smart_ptr> + { + typedef T type; + }; + + } // namespace trait +} // namespace qx + +#endif // _QX_REMOVE_SMART_PTR_H_ diff --git a/include/QxValidator/IxValidator.h b/include/QxValidator/IxValidator.h new file mode 100644 index 0000000..606a78a --- /dev/null +++ b/include/QxValidator/IxValidator.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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 _IX_VALIDATOR_H_ +#define _IX_VALIDATOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxValidator.h + * \author XDL Team + * \ingroup QxValidator + * \brief Common interface for validator engine + */ + +#include + +namespace qx +{ + + class IxDataMember; + class QxInvalidValueX; + + /*! + * \ingroup QxValidator + * \brief qx::IxValidator : common interface for validator engine + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + class QX_DLL_EXPORT IxValidator : public QxPropertyBag + { + + public: + enum validator_type + { + not_null, + not_empty, + min_value, + max_value, + min_length, + max_length, + date_past, + date_future, + min_decimal, + max_decimal, + regular_expression, + e_mail, + recursive_validator, + custom_validator + }; + + protected: + validator_type m_type; //!< Validator type + QString m_message; //!< Validator message when invalid value is detected + QString m_group; //!< Validator group + QVariantList m_Constraints; //!< List of constraints to verify + IxDataMember *m_pDataMember; //!< Registered property associated to validator + + public: + IxValidator(validator_type type); + virtual ~IxValidator(); + + validator_type getType() const; + QString getMessage() const; + QString getGroup() const; + QVariant getConstraint() const; + QVariantList getConstraints() const; + IxDataMember *getDataMember() const; + + void setMessage(const QString &s); + void setGroup(const QString &s); + void setConstraint(const QVariant &v); + void setConstraints(const QVariantList &lst); + void setDataMember(IxDataMember *p); + + virtual void validate(void *pOwner, QxInvalidValueX &lstInvalidValues) const; + + protected: + void initDefaultMessage(); + + void validateNotNull(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateNotEmpty(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMinValue(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMaxValue(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMinDecimal(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMaxDecimal(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMinLength(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateMaxLength(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateDatePast(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateDateFuture(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateRegularExpression(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + void validateEMail(const QVariant &v, QxInvalidValueX &lstInvalidValues) const; + }; + + typedef std::shared_ptr IxValidator_ptr; + +} // namespace qx + +#endif // _IX_VALIDATOR_H_ diff --git a/include/QxValidator/IxValidatorX.h b/include/QxValidator/IxValidatorX.h new file mode 100644 index 0000000..968687e --- /dev/null +++ b/include/QxValidator/IxValidatorX.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** 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 _IX_VALIDATOR_X_H_ +#define _IX_VALIDATOR_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file IxValidatorX.h + * \author XDL Team + * \ingroup QxValidator + * \brief Common interface for a list of validators + */ + +#include + +#include + +namespace qx +{ + + class IxClass; + class IxDataMember; + class QxInvalidValueX; + + /*! + * \ingroup QxValidator + * \brief qx::IxValidatorX : common interface for a list of validators + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + class QX_DLL_EXPORT IxValidatorX + { + + friend class IxClass; + + protected: + typedef QList type_lst_validator; + typedef std::shared_ptr type_lst_validator_ptr; + typedef QxCollection type_lst_validator_ptr_by_group; + + type_lst_validator_ptr_by_group m_lstValidatorByGroup; //!< List of validator by group + IxClass *m_pClass; //!< Class registered into QxOrm context + + public: + IxValidatorX(); + virtual ~IxValidatorX() = 0; + + QxInvalidValueX validate(void *pOwner, const QString &sGroup = QString()) const; + + IxValidator *add_NotNull(const QString &sPropertyKey, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_NotEmpty(const QString &sPropertyKey, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MinValue(const QString &sPropertyKey, long lMinValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MaxValue(const QString &sPropertyKey, long lMaxValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_Range(const QString &sPropertyKey, long lMinValue, long lMaxValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MinDecimal(const QString &sPropertyKey, double dMinValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MaxDecimal(const QString &sPropertyKey, double dMaxValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_RangeDecimal(const QString &sPropertyKey, double dMinValue, double dMaxValue, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MinLength(const QString &sPropertyKey, long lMinLength, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_MaxLength(const QString &sPropertyKey, long lMaxLength, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_Size(const QString &sPropertyKey, long lMinLength, long lMaxLength, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_DatePast(const QString &sPropertyKey, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_DateFuture(const QString &sPropertyKey, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_RegExp(const QString &sPropertyKey, const QString &sPattern, const QString &sMessage = QString(), const QString &sGroup = QString()); + IxValidator *add_EMail(const QString &sPropertyKey, const QString &sMessage = QString(), const QString &sGroup = QString()); + + QStringList getAllGroup() const; + QList getAllValidatorByGroup(const QString &group) const; + + protected: + void setClass(IxClass *p); + void insertIntoGroup(IxValidator_ptr pValidator, const QString &sGroup); + IxValidator_ptr createValidator(IxValidator::validator_type type, const QString &sPropertyKey, const QString &sMessage, const QString &sGroup); + IxDataMember *getDataMember(const QString &sPropertyKey) const; + }; + + typedef std::shared_ptr IxValidatorX_ptr; + +} // namespace qx + +#endif // _IX_VALIDATOR_X_H_ diff --git a/include/QxValidator/QxInvalidValue.h b/include/QxValidator/QxInvalidValue.h new file mode 100644 index 0000000..b635f65 --- /dev/null +++ b/include/QxValidator/QxInvalidValue.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** 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_VALIDATOR_INVALID_VALUE_H_ +#define _QX_VALIDATOR_INVALID_VALUE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxInvalidValue.h + * \author XDL Team + * \ingroup QxValidator + * \brief Invalid value when a property fails to pass a constraint + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +#include +#include +#include + +#include + +#include + +#include + +namespace qx +{ + class IxValidator; + class QxInvalidValue; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxInvalidValue &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxInvalidValue &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::QxInvalidValue &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValue &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxValidator + * \brief qx::QxInvalidValue : invalid value when a property fails to pass a constraint + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + class QX_DLL_EXPORT QxInvalidValue : public QxPropertyBag + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxInvalidValue &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxInvalidValue &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::QxInvalidValue &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValue &t, const QString &format); +#endif // _QX_NO_JSON + + protected: + QString m_sMessage; //!< Message associated to the invalid value + QString m_sPropertyName; //!< Property name failing to pass the constraint + QString m_sPath; //!< Path of property failing to pass the constraint + const IxValidator *m_pValidator; //!< IxValidator class associated to the invalid value + + public: + QxInvalidValue(); + virtual ~QxInvalidValue(); + + QString getMessage() const { return m_sMessage; } + QString getPropertyName() const { return m_sPropertyName; } + QString getPath() const { return m_sPath; } + QString getFullName() const; + const IxValidator *getValidator() const; + + void setMessage(const QString &s) { m_sMessage = s; } + void setPropertyName(const QString &s) { m_sPropertyName = s; } + void setPath(const QString &s) { m_sPath = s; } + void setValidator(const IxValidator *p); + + private: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("message", m_sMessage); + ar &boost::serialization::make_nvp("property_name", m_sPropertyName); + ar &boost::serialization::make_nvp("path", m_sPath); + ar &boost::serialization::make_nvp("list_property_bag", this->m_lstPropertyBag); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::QxInvalidValue) + +#endif // _QX_VALIDATOR_INVALID_VALUE_H_ diff --git a/include/QxValidator/QxInvalidValueX.h b/include/QxValidator/QxInvalidValueX.h new file mode 100644 index 0000000..de5028a --- /dev/null +++ b/include/QxValidator/QxInvalidValueX.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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_VALIDATOR_INVALID_VALUE_X_H_ +#define _QX_VALIDATOR_INVALID_VALUE_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxInvalidValueX.h + * \author XDL Team + * \ingroup QxValidator + * \brief List of invalid values + */ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#include +#include +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include +#include + +#include + +#include + +#include + +namespace qx +{ + class QxInvalidValueX; +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxInvalidValueX &t) QX_USED; +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxInvalidValueX &t) QX_USED; + +#ifndef _QX_NO_JSON +namespace qx +{ + namespace cvt + { + namespace detail + { + template <> + struct QxConvert_ToJson; + template <> + struct QxConvert_FromJson; + QX_DLL_EXPORT QJsonValue QxConvert_ToJson_Helper(const qx::QxInvalidValueX &t, const QString &format) QX_USED; + QX_DLL_EXPORT qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValueX &t, const QString &format) QX_USED; + } // namespace detail + } // namespace cvt +} // namespace qx +#endif // _QX_NO_JSON + +namespace qx +{ + + /*! + * \ingroup QxValidator + * \brief qx::QxInvalidValueX : list of invalid values + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + class QX_DLL_EXPORT QxInvalidValueX + { + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + friend class boost::serialization::access; +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + friend QX_DLL_EXPORT QDataStream & ::operator<<(QDataStream &stream, const qx::QxInvalidValueX &t); + friend QX_DLL_EXPORT QDataStream & ::operator>>(QDataStream &stream, qx::QxInvalidValueX &t); + +#ifndef _QX_NO_JSON + friend struct qx::cvt::detail::QxConvert_ToJson; + friend struct qx::cvt::detail::QxConvert_FromJson; + friend QX_DLL_EXPORT QJsonValue qx::cvt::detail::QxConvert_ToJson_Helper(const qx::QxInvalidValueX &t, const QString &format); + friend QX_DLL_EXPORT qx_bool qx::cvt::detail::QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValueX &t, const QString &format); +#endif // _QX_NO_JSON + + protected: + QList m_lstInvalidValues; //!< List of invalid values + QString m_sCurrentPath; //!< Current path of validation process + + public: + QxInvalidValueX(); + virtual ~QxInvalidValueX(); + + QString getCurrentPath() const; + void setCurrentPath(const QString &s); + + long count() const; + QxInvalidValue at(long l) const; + void insert(const IxValidator *pValidator); + void insert(const QString &sMessage); + void insert(const QxInvalidValue &invalidValue); + void insert(const QxInvalidValueX &other); + + QString text() const; + void dump() const; + + inline operator bool() const + { + return (m_lstInvalidValues.count() == 0); + } + + private: +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void serialize(Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("list_invalid_values", m_lstInvalidValues); + ar &boost::serialization::make_nvp("current_path", m_sCurrentPath); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + }; + +} // namespace qx + +QX_REGISTER_CLASS_NAME(qx::QxInvalidValueX) + +#endif // _QX_VALIDATOR_INVALID_VALUE_X_H_ diff --git a/include/QxValidator/QxValidator.h b/include/QxValidator/QxValidator.h new file mode 100644 index 0000000..6a93fbd --- /dev/null +++ b/include/QxValidator/QxValidator.h @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** 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_VALIDATOR_H_ +#define _QX_VALIDATOR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxValidator.h + * \author XDL Team + * \ingroup QxValidator + * \brief Concrete class for a custom or recursive validator + */ + +#include +#include + +#include + +namespace qx +{ + + template + QxInvalidValueX validate(T &t, const QString &group); + + /*! + * \ingroup QxValidator + * \brief qx::QxValidator : concrete class for a custom validator + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + template + class QxValidator : public IxValidator + { + + public: + typedef std::function type_fct_custom_validator_member; + typedef std::function type_fct_custom_validator_variant; + typedef std::function type_fct_custom_validator_variant_validator; + + protected: + type_fct_custom_validator_member m_fctCustomValidator_Member; //!< Custom validator function : class method + type_fct_custom_validator_variant m_fctCustomValidator_Variant; //!< Custom validator function : global function with value converted to QVariant type + type_fct_custom_validator_variant_validator m_fctCustomValidator_VariantValidator; //!< Custom validator function : global function with value converted to QVariant type and a IxValidator pointer containing all parameters + + public: + QxValidator() : IxValidator(IxValidator::custom_validator) { ; } + virtual ~QxValidator() { ; } + + void setFunction(type_fct_custom_validator_member fct) { m_fctCustomValidator_Member = fct; } + void setFunction(type_fct_custom_validator_variant fct) { m_fctCustomValidator_Variant = fct; } + void setFunction(type_fct_custom_validator_variant_validator fct) { m_fctCustomValidator_VariantValidator = fct; } + + virtual void validate(void *pOwner, QxInvalidValueX &lstInvalidValues) const + { + if (m_fctCustomValidator_Member) + { + m_fctCustomValidator_Member(static_cast(pOwner), lstInvalidValues); + } + else if (m_fctCustomValidator_Variant && m_pDataMember) + { + m_fctCustomValidator_Variant(m_pDataMember->toVariant(pOwner), lstInvalidValues); + } + else if (m_fctCustomValidator_VariantValidator && m_pDataMember) + { + m_fctCustomValidator_VariantValidator(m_pDataMember->toVariant(pOwner), this, lstInvalidValues); + } + } + }; + + /*! + * \ingroup QxValidator + * \brief qx::QxValidator_WithDataType : concrete class for a custom validator with data type + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + template + class QxValidator_WithDataType : public IxValidator + { + + public: + typedef std::function type_fct_custom_validator_data_type; + typedef std::function type_fct_custom_validator_data_type_validator; + + protected: + type_fct_custom_validator_data_type m_fctCustomValidator_DataType; //!< Custom validator function : global function with value + type_fct_custom_validator_data_type_validator m_fctCustomValidator_DataTypeValidator; //!< Custom validator function : global function with value and a IxValidator pointer containing all parameters + + public: + QxValidator_WithDataType() : IxValidator(IxValidator::custom_validator) { ; } + virtual ~QxValidator_WithDataType() { ; } + + void setFunction(type_fct_custom_validator_data_type fct) { m_fctCustomValidator_DataType = fct; } + void setFunction(type_fct_custom_validator_data_type_validator fct) { m_fctCustomValidator_DataTypeValidator = fct; } + + virtual void validate(void *pOwner, QxInvalidValueX &lstInvalidValues) const + { + if (!m_pDataMember) + { + return; + } + IxDataMember *pDataMember = const_cast(m_pDataMember); + DataType *val = pDataMember->getValuePtr(pOwner); + if (m_fctCustomValidator_DataType && val) + { + m_fctCustomValidator_DataType((*val), lstInvalidValues); + } + else if (m_fctCustomValidator_DataTypeValidator && val) + { + m_fctCustomValidator_DataTypeValidator((*val), this, lstInvalidValues); + } + } + }; + + /*! + * \ingroup QxValidator + * \brief qx::QxValidator_Recursive : concrete class for a recursive validator + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + template + class QxValidator_Recursive : public IxValidator + { + + public: + QxValidator_Recursive() : IxValidator(IxValidator::recursive_validator) { ; } + virtual ~QxValidator_Recursive() { ; } + + virtual void validate(void *pOwner, QxInvalidValueX &lstInvalidValues) const + { + if (!m_pDataMember) + { + qAssert(false); + return; + } + IxDataMember *pDataMember = const_cast(m_pDataMember); + DataType *val = pDataMember->getValuePtr(pOwner); + if (!val) + { + qAssert(false); + return; + } + QxInvalidValueX invalidValues; + invalidValues.setCurrentPath(m_pDataMember->getName()); + invalidValues.insert(qx::validate((*val), m_group)); + lstInvalidValues.insert(invalidValues); + } + }; + +} // namespace qx + +#endif // _QX_VALIDATOR_H_ diff --git a/include/QxValidator/QxValidatorError.h b/include/QxValidator/QxValidatorError.h new file mode 100644 index 0000000..6b7228a --- /dev/null +++ b/include/QxValidator/QxValidatorError.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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_VALIDATOR_ERROR_H_ +#define _QX_VALIDATOR_ERROR_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxValidatorError.h + * \author XDL Team + * \ingroup QxValidator + * \brief Define a validator error exception (for example, inserting or updating an element into database) and retrieve list of invalid values + */ + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxValidator + * \brief qx::validator_error : define a validator error exception (for example, inserting or updating an element into database) and retrieve list of invalid values + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + class validator_error : public std::exception + { + + private: + QxInvalidValueX m_lstInvalidValues; + + public: + validator_error(const QxInvalidValueX &err) : std::exception(), m_lstInvalidValues(err) { ; } + virtual ~validator_error() throw() { ; } + + virtual const char *what() const throw() + { + return qPrintable(m_lstInvalidValues.text()); + } + + QxInvalidValueX get() const + { + return m_lstInvalidValues; + } + }; + +} // namespace qx + +#endif // _QX_VALIDATOR_ERROR_H_ diff --git a/include/QxValidator/QxValidatorFct.h b/include/QxValidator/QxValidatorFct.h new file mode 100644 index 0000000..e605a2f --- /dev/null +++ b/include/QxValidator/QxValidatorFct.h @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** 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_VALIDATOR_FUNCTION_H_ +#define _QX_VALIDATOR_FUNCTION_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxValidatorFct.h + * \author XDL Team + * \ingroup QxValidator + * \brief Implementation of qx::validate() function (validator engine) + */ + +#include +#include + +#include + +#include +#include +#include + +namespace qx +{ + template + QxInvalidValueX validate(T &t, const QString &group); +} // namespace qx + +namespace qx +{ + namespace validator + { + namespace detail + { + + template + struct QxValidator_Helper_Generic + { + + static inline qx::QxInvalidValueX validate(T &t, const QString &group) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + + qx::QxInvalidValueX invalidValues; + qx::IxClass *pClass = qx::QxClass::getSingleton(); + if (!pClass) + { + qAssert(false); + return invalidValues; + } + qx::IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return invalidValues; + } + invalidValues.setCurrentPath(pClass->getName()); + invalidValues.insert(pAllValidator->validate((&t), group)); + return invalidValues; + } + }; + + template + struct QxValidator_Helper_Container + { + + static inline qx::QxInvalidValueX validate(T &t, const QString &group) + { + qx::QxInvalidValueX invalidValues; + long lIndex = 0; + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + invalidValues.setCurrentPath("[" + QString::number(lIndex) + "]"); + invalidValues.insert(validateItem((*it), group)); + lIndex++; + } + return invalidValues; + } + + private: + template + static inline qx::QxInvalidValueX validateItem(U &item, const QString &group) + { + return validateItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::validate(item, group); + } + + template + struct validateItem_Helper + { + static inline qx::QxInvalidValueX validate(U &item, const QString &group) + { + return (item ? qx::validator::detail::QxValidator_Helper_Container::validateItem((*item), group) : qx::QxInvalidValueX()); + } + }; + + template + struct validateItem_Helper, false> + { + static inline qx::QxInvalidValueX validate(std::pair &item, const QString &group) + { + return qx::validator::detail::QxValidator_Helper_Container::validateItem(item.second, group); + } + }; + + template + struct validateItem_Helper, false> + { + static inline qx::QxInvalidValueX validate(const std::pair &item, const QString &group) + { + return qx::validator::detail::QxValidator_Helper_Container::validateItem(item.second, group); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct validateItem_Helper, false> + { + static inline qx::QxInvalidValueX validate(QPair &item, const QString &group) + { + return qx::validator::detail::QxValidator_Helper_Container::validateItem(item.second, group); + } + }; + + template + struct validateItem_Helper, false> + { + static inline qx::QxInvalidValueX validate(const QPair &item, const QString &group) + { + return qx::validator::detail::QxValidator_Helper_Container::validateItem(item.second, group); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct validateItem_Helper + { + static qx::QxInvalidValueX validate(U &item, const QString &group) { return qx::validate(item, group); } + }; + }; + + template + struct QxValidator_Helper_Ptr + { + + static inline qx::QxInvalidValueX validate(T &t, const QString &group) + { + return (t ? qx::validate((*t), group) : qx::QxInvalidValueX()); + } + }; + + template + struct QxValidator_Helper + { + + static inline qx::QxInvalidValueX validate(T &t, const QString &group) + { + typedef typename std::conditional::value, qx::validator::detail::QxValidator_Helper_Ptr, qx::validator::detail::QxValidator_Helper_Generic>::type type_validator_1; + typedef typename std::conditional::value, qx::validator::detail::QxValidator_Helper_Ptr, type_validator_1>::type type_validator_2; + typedef typename std::conditional::value, qx::validator::detail::QxValidator_Helper_Container, type_validator_2>::type type_validator_3; + + return type_validator_3::validate(t, group); + } + }; + + } // namespace detail + } // namespace validator +} // namespace qx + +namespace qx +{ + + template + QxInvalidValueX validate(T &t, const QString &group) + { + return qx::validator::detail::QxValidator_Helper::validate(t, group); + } + + template + QxInvalidValueX validate(T &t) + { + return qx::validator::detail::QxValidator_Helper::validate(t, ""); + } + + template + QxInvalidValueX validate(T &t, const QStringList &groups) + { + QxInvalidValueX invalidValues; + if (groups.count() <= 0) + { + return qx::validate(t); + } + for (long l = 0; l < groups.count(); l++) + { + invalidValues.insert(qx::validate(t, groups.at(l))); + } + return invalidValues; + } + +} // namespace qx + +#endif // _QX_VALIDATOR_FUNCTION_H_ diff --git a/include/QxValidator/QxValidatorX.h b/include/QxValidator/QxValidatorX.h new file mode 100644 index 0000000..56df29d --- /dev/null +++ b/include/QxValidator/QxValidatorX.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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_VALIDATOR_X_H_ +#define _QX_VALIDATOR_X_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +/*! + * \file QxValidatorX.h + * \author XDL Team + * \ingroup QxValidator + * \brief Concrete class for a list of validators associated to a type registered into QxOrm context + */ + +#include +#include + +#include + +namespace qx +{ + + /*! + * \ingroup QxValidator + * \brief qx::QxValidatorX : concrete class for a list of validators associated to a type registered into QxOrm context + * + * For more informations about QxValidator module, goto the FAQ of QxOrm website : + * https://www.qxorm.com/qxorm_en/faq.html#faq_250 + */ + template + class QxValidatorX : public IxValidatorX + { + + public: + QxValidatorX() : IxValidatorX() { ; } + virtual ~QxValidatorX() { ; } + + template + IxValidator *add_RecursiveValidator(const QString &sPropertyKey, const QString &sGroup = QString()) + { + IxValidator_ptr pValidator = std::make_shared>(); + pValidator->setGroup(sGroup); + pValidator->setDataMember(getDataMember(sPropertyKey)); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *add_CustomValidator(typename QxValidator::type_fct_custom_validator_member fct, const QString &sGroup = QString()) + { + return add_CustomValidator_Helper(new QxValidator(), fct, "", sGroup); + } + + IxValidator *add_CustomValidator_QVariant(typename QxValidator::type_fct_custom_validator_variant_validator fct, const QString &sPropertyKey, const QString &sGroup = QString()) + { + return add_CustomValidator_Helper(new QxValidator(), fct, sPropertyKey, sGroup); + } + + template + IxValidator *add_CustomValidator_DataType(typename QxValidator_WithDataType::type_fct_custom_validator_data_type_validator fct, const QString &sPropertyKey, const QString &sGroup = QString()) + { + return add_CustomValidator_Helper(new QxValidator_WithDataType(), fct, sPropertyKey, sGroup); + } + + private: + template + IxValidator *add_CustomValidator_Helper(Validator *validator, FunctionType fct, const QString &sPropertyKey, const QString &sGroup) + { + if (!validator) + { + qAssert(false); + return NULL; + } + IxValidator_ptr pValidator; + pValidator.reset(validator); + validator->setGroup(sGroup); + validator->setFunction(fct); + validator->setDataMember(getDataMember(sPropertyKey)); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + }; + +} // namespace qx + +#endif // _QX_VALIDATOR_X_H_ diff --git a/include/QxXml/QxXml.h b/include/QxXml/QxXml.h new file mode 100644 index 0000000..44bed13 --- /dev/null +++ b/include/QxXml/QxXml.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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_XML_H_ +#define _QX_XML_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +#include + +namespace qx +{ + + template + class QxXml + { + + private: + QxXml() { ; } + virtual ~QxXml() { ; } + + public: + static QString toXml(T *pOwner); + static bool fromXml(T *pOwner, const QString &sXml); + + static std::shared_ptr toXmlWriter(T *pOwner); + static bool fromXmlReader(T *pOwner, QxXmlReader *pXmlReader); + }; + +#include "../../inl/QxXml/QxXml.inl" + +} // namespace qx + +#endif // _QX_XML_H_ diff --git a/include/QxXml/QxXmlReader.h b/include/QxXml/QxXmlReader.h new file mode 100644 index 0000000..21b91c9 --- /dev/null +++ b/include/QxXml/QxXmlReader.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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_XML_READER_H_ +#define _QX_XML_READER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) + +#include + +namespace qx +{ + + class QX_DLL_EXPORT QxXmlReader : public QXmlStreamReader + { + + public: + typedef std::shared_ptr type_byte_arr_ptr; + typedef QHash type_hash_bin_data; + typedef QHashIterator type_hash_bin_data_itr; + + protected: + type_hash_bin_data m_mapBinaryData; // Collection of binary data associated with xml (<=> attached files) + + public: + QxXmlReader() : QXmlStreamReader() { ; } + QxXmlReader(const QString &data) : QXmlStreamReader(data) { ; } + virtual ~QxXmlReader() { ; } + + void addBinaryData(const type_hash_bin_data &other, bool bClear); + void addBinaryData(const QString &sKey, type_byte_arr_ptr pData); + void removeBinaryData(const QString &sKey); + void removeAllBinaryData(); + + bool isStartBinaryData() const; + type_byte_arr_ptr readBinaryData(); + }; + +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator>>(QDataStream &stream, qx::QxXmlReader &xmlReader); + +#endif // _QX_XML_READER_H_ diff --git a/include/QxXml/QxXmlWriter.h b/include/QxXml/QxXmlWriter.h new file mode 100644 index 0000000..83b8cf4 --- /dev/null +++ b/include/QxXml/QxXmlWriter.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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_XML_WRITER_H_ +#define _QX_XML_WRITER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) + +#define QX_XML_PREFIX_BINARY_DATA_KEY "qx_binary_data_key_" +#define QX_XML_ATTRIBUTE_IS_BINARY_DATA "qx_is_binary_data" + +namespace qx +{ + + class QX_DLL_EXPORT QxXmlWriter : public QXmlStreamWriter + { + + public: + typedef std::shared_ptr type_byte_arr_ptr; + typedef QHash type_hash_bin_data; + typedef QHashIterator type_hash_bin_data_itr; + + protected: + type_hash_bin_data m_mapBinaryData; // Collection of binary data associated with xml (<=> attached files) + long m_lKeyBinaryData; // Current binary data key to write to xml + QString m_pStringWriter; // String containing xml to write + + public: + QxXmlWriter() : QXmlStreamWriter(&m_pStringWriter), m_lKeyBinaryData(0) { initQxXmlWriter(); } + virtual ~QxXmlWriter() { ; } + + QString getXml() const { return m_pStringWriter; } + type_hash_bin_data_itr getBinaryDataItr() const { return type_hash_bin_data_itr(m_mapBinaryData); } + long getBinaryDataCount() const { return m_mapBinaryData.count(); } + + QString writeBinaryData(const QString &namespaceUri, const QString &name, type_byte_arr_ptr pData); + QString writeBinaryData(const QString &qualifiedName, type_byte_arr_ptr pData); + + protected: + inline QString getNextKeyBinaryData() { return (QString(QX_XML_PREFIX_BINARY_DATA_KEY) + QString::number(++m_lKeyBinaryData)); } + inline void initQxXmlWriter() + { + setAutoFormatting(true); + setAutoFormattingIndent(3); + } + }; + +} // namespace qx + +QX_DLL_EXPORT QDataStream &operator<<(QDataStream &stream, const qx::QxXmlWriter &xmlWriter); + +#endif // _QX_XML_WRITER_H_ diff --git a/inl/QxCollection/QxCollection.inl b/inl/QxCollection/QxCollection.inl new file mode 100644 index 0000000..2b4c1b6 --- /dev/null +++ b/inl/QxCollection/QxCollection.inl @@ -0,0 +1,615 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + + template + QxCollection::QxCollection() : IxCollection(), m_batch(false) + { + } + + template + QxCollection::QxCollection(const QxCollection &other) : IxCollection(), m_batch(false) + { + cloneCollection(this, other); + } + + template + QxCollection::~QxCollection() + { + } + + template + QxCollection &QxCollection::operator=(const QxCollection &other) + { + if (this != (&other)) + { + cloneCollection(this, other); + } + return (*this); + } + + template + bool QxCollection::operator==(const QxCollection &other) const + { + return isSameCollection(this, other); + } + + template + bool QxCollection::operator!=(const QxCollection &other) const + { + return (!isSameCollection(this, other)); + } + + template + void QxCollection::cloneCollection(QxCollection *pClone, const QxCollection &pRef) + { + if (!pClone) + { + return; + } + if (pClone == (&pRef)) + { + return; + } + QMutexLocker locker1(&pRef.m_mutex); + QMutexLocker locker2(&pClone->m_mutex); + qAssert(pRef.m_list.size() == pRef.m_hash.size()); + pClone->m_list = pRef.m_list; + pClone->m_hash = pRef.m_hash; + } + + template + bool QxCollection::isSameCollection(const QxCollection *p1, const QxCollection &p2) const + { + if (!p1) + { + return false; + } + if (p1 == (&p2)) + { + return true; + } + if (p1->size() != p2.size()) + { + return false; + } + QMutexLocker locker1(&p2.m_mutex); + QMutexLocker locker2(&p1->m_mutex); + qAssert(p2.m_list.size() == p2.m_hash.size()); + return ((p1->m_list == p2.m_list) && (p1->m_hash == p2.m_hash)); + } + + template + void QxCollection::updateHashPosition(long from /* = 0 */, long to /* = -1 */, bool check /* = false */) + { + if (m_batch) + { + return; + } + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + if (to == -1) + { + to = (m_list.size() - 1); + } + if ((from < 0) || (to >= m_list.size()) || (from > to)) + { + return; + } + for (long idx = from; idx <= to; idx++) + { + const Key &key = m_list.at(idx).first; + m_hash.insert(key, idx); + } + if (check) + { + qAssert(m_list.size() == m_hash.size()); + } + } + + template + typename QxCollection::iterator QxCollection::begin() + { + QMutexLocker locker(&m_mutex); + return m_list.begin(); + } + + template + typename QxCollection::iterator QxCollection::end() + { + QMutexLocker locker(&m_mutex); + return m_list.end(); + } + + template + typename QxCollection::const_iterator QxCollection::begin() const + { + QMutexLocker locker(&m_mutex); + return m_list.begin(); + } + + template + typename QxCollection::const_iterator QxCollection::end() const + { + QMutexLocker locker(&m_mutex); + return m_list.end(); + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + + template + typename QxCollection::reverse_iterator QxCollection::rbegin() + { + QMutexLocker locker(&m_mutex); + return m_list.rbegin(); + } + + template + typename QxCollection::reverse_iterator QxCollection::rend() + { + QMutexLocker locker(&m_mutex); + return m_list.rend(); + } + + template + typename QxCollection::const_reverse_iterator QxCollection::rbegin() const + { + QMutexLocker locker(&m_mutex); + return m_list.rbegin(); + } + + template + typename QxCollection::const_reverse_iterator QxCollection::rend() const + { + QMutexLocker locker(&m_mutex); + return m_list.rend(); + } + +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + + template + void QxCollection::reserve(long size) + { + if (size <= 0) + { + return; + } + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + m_list.reserve(size); + m_hash.reserve(size); + } + + template + void QxCollection::reverse() + { + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + std::reverse(m_list.begin(), m_list.end()); + } + updateHashPosition(); + } + + template + void QxCollection::clear() + { + QMutexLocker locker(&m_mutex); + m_hash.clear(); + m_list.clear(); + } + + template + long QxCollection::count() const + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + return static_cast(m_list.size()); + } + + template + long QxCollection::size() const + { + return this->count(); + } + + template + bool QxCollection::contains(const Key &key) const + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + return (m_hash.contains(key)); + } + + template + bool QxCollection::exist(const Key &key) const + { + return this->contains(key); + } + + template + bool QxCollection::empty() const + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + return m_list.isEmpty(); + } + + template + bool QxCollection::push_back(const Key &key, const Value &value) + { + return this->insert(key, value); + } + + template + bool QxCollection::push_front(const Key &key, const Value &value) + { + return this->insert(0, key, value); + } + + template + bool QxCollection::insert(const Key &key, const Value &value) + { + qAssert(!exist(key)); + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + m_list.append(qMakePair(key, value)); + m_hash.insert(key, (m_list.size() - 1)); + return true; + } + + template + bool QxCollection::insert(long index, const Key &key, const Value &value) + { + qAssert(!exist(key)); + if (index < 0) + { + index = 0; + } + if (index >= size()) + { + return this->insert(key, value); + } + + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + m_list.insert(index, qMakePair(key, value)); + m_hash.insert(key, index); + } + + updateHashPosition(index); + return true; + } + + template + bool QxCollection::insert(const QxCollection &other) + { + { + if (this == (&other)) + { + return false; + } + QMutexLocker locker1(&m_mutex); + QMutexLocker locker2(&other.m_mutex); + m_list.append(other.m_list); + m_hash.unite(other.m_hash); + } + + updateHashPosition(0, -1, true); + return true; + } + + template + bool QxCollection::insert(long index, const QxCollection &other) + { + if (index < 0) + { + index = 0; + } + if ((index >= size()) && (index != 0)) + { + index = (size() - 1); + } + if (this == (&other)) + { + return false; + } + QMutexLocker locker1(&other.m_mutex); + + { + QMutexLocker locker2(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + m_batch = true; + } + + for (long l = 0; l < other.size(); l++) + { + const type_pair_key_value &pair = other.m_list.at(l); + this->insert((index + l), pair.first, pair.second); + } + + { + QMutexLocker locker3(&m_mutex); + m_batch = false; + } + updateHashPosition(index); + return true; + } + + template + bool QxCollection::replace(long index, const Key &key, const Value &value) + { + qAssert(!exist(key)); + QMutexLocker locker(&m_mutex); + m_hash.remove(m_list.at(index).first); + m_list.replace(index, qMakePair(key, value)); + m_hash.insert(key, index); + qAssert(m_list.size() == m_hash.size()); + return true; + } + + template + bool QxCollection::swap(long index1, long index2) + { + if (index1 < 0 || index1 >= size()) + { + return false; + } + if (index2 < 0 || index2 >= size()) + { + return false; + } + if (index1 == index2) + { + return true; + } + + QMutexLocker locker(&m_mutex); + const Key &key1 = m_list.at(index1).first; + const Key &key2 = m_list.at(index2).first; + m_hash.insert(key1, index2); + m_hash.insert(key2, index1); + m_list.swap(index1, index2); + qAssert(m_list.size() == m_hash.size()); + return true; + } + + template + bool QxCollection::move(long indexFrom, long indexTo) + { + return swap(indexFrom, indexTo); + } + + template + bool QxCollection::removeByKey(const Key &key) + { + qAssert(exist(key)); + long pos = 0; + + { + QMutexLocker locker(&m_mutex); + pos = m_hash.value(key, -1); + if ((pos < 0) || (pos >= m_list.size())) + { + return false; + } + qAssert(m_list.at(pos).first == key); + m_hash.remove(key); + m_list.removeAt(pos); + } + + updateHashPosition(pos, -1, true); + return true; + } + + template + bool QxCollection::removeByIndex(long index) + { + if (index < 0 || index >= size()) + { + return false; + } + + { + QMutexLocker locker(&m_mutex); + const Key &key = m_list.at(index).first; + qAssert(m_hash.value(key, -1) == index); + m_hash.remove(key); + m_list.removeAt(index); + } + + updateHashPosition(index, -1, true); + return true; + } + + template + bool QxCollection::removeByIndex(long first, long last) + { + if (first < 0 || first >= size()) + { + return false; + } + if (last < 0 || last >= size()) + { + return false; + } + if (first > last) + { + return false; + } + { + QMutexLocker locker(&m_mutex); + m_batch = true; + } + for (long idx = first; idx <= last; idx++) + { + removeByIndex(idx); + } + { + QMutexLocker locker(&m_mutex); + m_batch = false; + } + updateHashPosition(first); + return true; + } + + template + bool QxCollection::removeFirst() + { + return this->removeByIndex(0); + } + + template + bool QxCollection::removeLast() + { + return this->removeByIndex(size() - 1); + } + + template + typename QxCollection::const_reference_value QxCollection::getByKey(const Key &key) const + { + qAssert(exist(key)); + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + const type_pair_key_value &pair = m_list.at(m_hash.value(key, -1)); + qAssert(pair.first == key); + return pair.second; + } + + template + typename QxCollection::const_reference_value QxCollection::getByIndex(long index) const + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + qAssert((index >= 0) && (index < static_cast(m_list.size()))); + qAssert(m_hash.value(m_list.at(index).first, -1) == index); + return m_list.at(index).second; + } + + template + typename QxCollection::const_reference_value QxCollection::getFirst() const + { + qAssert(!empty()); + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + return m_list.at(0).second; + } + + template + typename QxCollection::const_reference_value QxCollection::getLast() const + { + qAssert(!empty()); + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + return m_list.at(m_list.size() - 1).second; + } + + template + typename QxCollection::const_reference_key QxCollection::getKeyByIndex(long index) const + { + QMutexLocker locker(&m_mutex); + qAssert(m_list.size() == m_hash.size()); + qAssert((index >= 0) && (index < static_cast(m_list.size()))); + qAssert(m_hash.value(m_list.at(index).first, -1) == index); + return m_list.at(index).first; + } + + template + void QxCollection::sortByKey(bool bAscending /* = true */) + { + if (bAscending) + { + QMutexLocker locker(&m_mutex); + std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer::value || qx::trait::is_smart_ptr::value, 0 > ::compareByKeyAscending)); + } + else + { + QMutexLocker locker(&m_mutex); + std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer::value || qx::trait::is_smart_ptr::value, 0 > ::compareByKeyDescending)); + } + updateHashPosition(0, -1, true); + } + + template + void QxCollection::sortByValue(bool bAscending /* = true */) + { + if (bAscending) + { + QMutexLocker locker(&m_mutex); + std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer::value || qx::trait::is_smart_ptr::value, 0 > ::compareByValueAscending)); + } + else + { + QMutexLocker locker(&m_mutex); + std::sort(m_list.begin(), m_list.end(), (&compareKeyValue < std::is_pointer::value || qx::trait::is_smart_ptr::value, 0 > ::compareByValueDescending)); + } + updateHashPosition(0, -1, true); + } + +} // namespace qx + +template +QDataStream &operator<<(QDataStream &stream, const qx::QxCollection &t) +{ + long lCount = t.count(); + stream << (qint32)(lCount); + + for (long l = 0; l < lCount; l++) + { + stream << t.getKeyByIndex(l); + stream << t.getByIndex(l); + } + + return stream; +} + +template +QDataStream &operator>>(QDataStream &stream, qx::QxCollection &t) +{ + qint32 lCount = 0; + stream >> lCount; + t.clear(); + t.reserve(lCount); + + for (qint32 l = 0; l < lCount; l++) + { + Key key; + stream >> key; + Value value; + stream >> value; + t.insert(key, value); + } + + return stream; +} diff --git a/inl/QxCollection/QxCollectionIterator.inl b/inl/QxCollection/QxCollectionIterator.inl new file mode 100644 index 0000000..eaf4d10 --- /dev/null +++ b/inl/QxCollection/QxCollectionIterator.inl @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + + template + QxCollectionIterator::QxCollectionIterator(const QxCollection &col) : m_pCollection(&col), m_lCurrIndex(-1) + { + } + + template + QxCollectionIterator::~QxCollectionIterator() + { + } + + template + inline const Key &QxCollectionIterator::key() const + { + qAssert(m_pCollection && (m_lCurrIndex >= 0) && (m_lCurrIndex < m_pCollection->size())); + return m_pCollection->getKeyByIndex(m_lCurrIndex); + } + + template + inline const Value &QxCollectionIterator::value() const + { + qAssert(m_pCollection && (m_lCurrIndex >= 0) && (m_lCurrIndex < m_pCollection->size())); + return m_pCollection->getByIndex(m_lCurrIndex); + } + + template + inline void QxCollectionIterator::toFirst() + { + m_lCurrIndex = -1; + } + + template + inline void QxCollectionIterator::toLast() + { + m_lCurrIndex = m_pCollection->size(); + } + + template + inline bool QxCollectionIterator::next() + { + long lCurrIndex = m_lCurrIndex; + m_lCurrIndex = ((m_lCurrIndex < (m_pCollection->size() - 1)) ? (m_lCurrIndex + 1) : m_lCurrIndex); + return (m_lCurrIndex > lCurrIndex); + } + + template + inline bool QxCollectionIterator::previous() + { + long lCurrIndex = m_lCurrIndex; + m_lCurrIndex = ((m_lCurrIndex > 0) ? (m_lCurrIndex - 1) : m_lCurrIndex); + return (m_lCurrIndex < lCurrIndex); + } + +} // namespace qx diff --git a/inl/QxConvert/QxConvert_FromJson.inl b/inl/QxConvert/QxConvert_FromJson.inl new file mode 100644 index 0000000..0d63cce --- /dev/null +++ b/inl/QxConvert/QxConvert_FromJson.inl @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** 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_NO_JSON + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::trait::no_type &t, const QString &format) + { + Q_UNUSED(j); + Q_UNUSED(t); + Q_UNUSED(format); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, bool &t, const QString &format) + { + Q_UNUSED(format); + t = j.toBool(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, short &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, int &t, const QString &format) + { + Q_UNUSED(format); + t = qRound(j.toDouble()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, long &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound64(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, long long &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound64(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, float &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(j.toDouble()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, double &t, const QString &format) + { + Q_UNUSED(format); + t = j.toDouble(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, unsigned short &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, unsigned int &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, unsigned long &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound64(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, unsigned long long &t, const QString &format) + { + Q_UNUSED(format); + t = static_cast(qRound64(j.toDouble())); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QDateTime &t, const QString &format) + { +#ifdef _QX_ENABLE_MONGODB + if (j.isObject() && format.startsWith("mongodb")) + { + QJsonObject obj = j.toObject(); + QString dt; + if (obj.contains("$date")) + { + dt = obj.value("$date").toString(); + } + if (!dt.isEmpty()) + { + t = QDateTime::fromString(dt, QX_JSON_DATE_TIME_FORMAT); + return qx_bool(true); + } + } +#endif // _QX_ENABLE_MONGODB + + Q_UNUSED(format); + t = (j.isNull() ? QDateTime() : QDateTime::fromString(j.toString(), QX_JSON_DATE_TIME_FORMAT)); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QDate &t, const QString &format) + { +#ifdef _QX_ENABLE_MONGODB + if (j.isObject() && format.startsWith("mongodb")) + { + QDateTime dt; + QxConvert_FromJson::fromJson(j, dt, format); + t = dt.date(); + return qx_bool(true); + } +#endif // _QX_ENABLE_MONGODB + + Q_UNUSED(format); + t = (j.isNull() ? QDate() : QDate::fromString(j.toString(), Qt::ISODate)); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QTime &t, const QString &format) + { + Q_UNUSED(format); + t = (j.isNull() ? QTime() : QTime::fromString(j.toString(), QX_JSON_DATE_TIME_FORMAT)); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QByteArray &t, const QString &format) + { + Q_UNUSED(format); + t = QByteArray::fromBase64(j.toString().toLatin1()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QString &t, const QString &format) + { + Q_UNUSED(format); + t = j.toString(); + +#ifdef _QX_ENABLE_MONGODB + if (t.isEmpty() && j.isObject() && format.startsWith("mongodb")) + { + QJsonObject obj = j.toObject(); + if (obj.contains("$oid")) + { + t = obj.value("$oid").toString(); + } + if (!t.isEmpty()) + { + t = "qx_oid:" + t; + } + } +#endif // _QX_ENABLE_MONGODB + + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QVariant &t, const QString &format) + { + Q_UNUSED(format); + t = j.toVariant(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, QUuid &t, const QString &format) + { + Q_UNUSED(format); + t = QUuid(j.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxDateNeutral &t, const QString &format) + { + Q_UNUSED(format); + t = qx::QxDateNeutral::fromNeutral(j.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxTimeNeutral &t, const QString &format) + { + Q_UNUSED(format); + t = qx::QxTimeNeutral::fromNeutral(j.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx::QxDateTimeNeutral &t, const QString &format) + { + Q_UNUSED(format); + t = qx::QxDateTimeNeutral::fromNeutral(j.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, std::string &t, const QString &format) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + t = j.toString().toStdString(); + return qx_bool(true); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + t = j.toString().toLatin1().constData(); + return qx_bool(true); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, std::wstring &t, const QString &format) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + t = j.toString().toStdWString(); + return qx_bool(true); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(t); + Q_UNUSED(j); + qAssert(false); /* Need STL compatibility ! */ + return qx_bool(true); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + template <> + struct QxConvert_FromJson + { + static inline qx_bool fromJson(const QJsonValue &j, qx_bool &t, const QString &format) + { + Q_UNUSED(format); + t = qx_bool(); + if (j.isObject()) + { + QJsonObject obj = j.toObject(); + t.setValue(obj["value"].toBool()); + t.setCode(static_cast(qRound64(obj["code"].toDouble()))); + t.setDesc(obj["desc"].toString()); + } + return qx_bool(true); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromJson> + { + static inline qx_bool fromJson(const QJsonValue &j, boost::optional &t, const QString &format) + { + if (j.isNull()) + { + t = boost::none; + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_json(j, (*t), format); + } + }; + +#endif // _QX_ENABLE_BOOST + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/inl/QxConvert/QxConvert_FromString.inl b/inl/QxConvert/QxConvert_FromString.inl new file mode 100644 index 0000000..97bba83 --- /dev/null +++ b/inl/QxConvert/QxConvert_FromString.inl @@ -0,0 +1,979 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, qx::trait::no_type &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(s); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QString &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = s; + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QUuid &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QUuid(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QDate &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QDate::fromString(s, (format.isEmpty() ? QString(QX_STR_CVT_QDATE_FORMAT) : format)); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QTime::fromString(s, (format.isEmpty() ? QString(QX_STR_CVT_QTIME_FORMAT) : format)); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QDateTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QDateTime::fromString(s, (format.isEmpty() ? QString(QX_STR_CVT_QDATETIME_FORMAT) : format)); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QByteArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = s.toLatin1(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QVariant &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + +#ifndef _QX_NO_JSON + if (s.startsWith("$$JSON$$")) + { + QJsonParseError err; + QString stream = s.right(s.size() - 16); // $$JSON$$0000XX$$ + QJsonDocument doc = QJsonDocument::fromJson(stream.toUtf8(), (&err)); + if (err.error == QJsonParseError::NoError) + { + QJsonValue json = (doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object())); + t = json.toVariant(); + return qx_bool(true); + } + } +#endif // _QX_NO_JSON + + t = QVariant(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, qx_bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t.fromString(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = (((s == "0") || s.trimmed().isEmpty()) ? false : true); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, char &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = (s.isEmpty() ? ' ' : s.toLatin1().at(0)); + return (!s.isEmpty()); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = s.toShort(&bOk); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = s.toInt(&bOk); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toLongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toLongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, float &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toDouble(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, double &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = s.toDouble(&bOk); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, unsigned short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toUShort(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, unsigned int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toUInt(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, unsigned long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toULongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, unsigned long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(s.toULongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, qx::QxDateNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxDateNeutral::fromNeutral(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, qx::QxTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxTimeNeutral::fromNeutral(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, qx::QxDateTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxDateTimeNeutral::fromNeutral(s); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, std::string &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = s.toStdString(); + return qx_bool(true); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = s.toLatin1().constData(); + return qx_bool(true); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, std::wstring &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = s.toStdWString(); + return qx_bool(true); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + Q_UNUSED(t); + Q_UNUSED(s); + qAssert(false); /* Need STL compatibility ! */ + return qx_bool(true); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + +#ifndef _QX_NO_JSON + + template <> + struct QxConvert_FromString + { + static inline qx_bool fromString(const QString &s, QJsonValue &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + QJsonParseError jsonError; + QByteArray dataAsByteArray = s.toUtf8(); + QJsonDocument doc = QJsonDocument::fromJson(dataAsByteArray, (&jsonError)); + if (jsonError.error != QJsonParseError::NoError) + { + return qx_bool(static_cast(jsonError.error), jsonError.errorString()); + } + t = (doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object())); + return qx_bool(true); + } + }; + +#endif // _QX_NO_JSON + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (!t) + { + t = T(); + }; + return qx::cvt::from_string(s, (*t), format, index, ctx); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::pair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QPair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::vector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::list &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QVector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QLinkedList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QFlags &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QFlags(QFlag(s.toInt())); + return true; + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QMultiHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, QMultiMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, qx::QxCollection &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + template + struct QxConvert_FromString> + { + static inline qx_bool fromString(const QString &s, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::from_string(t, s); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx diff --git a/inl/QxConvert/QxConvert_FromVariant.inl b/inl/QxConvert/QxConvert_FromVariant.inl new file mode 100644 index 0000000..9afc641 --- /dev/null +++ b/inl/QxConvert/QxConvert_FromVariant.inl @@ -0,0 +1,991 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT QX_CVT_DEFAULT_ARCHIVE::from_string(t, v.toString()) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT QX_CVT_DEFAULT_ARCHIVE::from_byte_array(t, v.toByteArray()) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, qx::trait::no_type &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(v); + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toBool(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toInt(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = v.toInt(&bOk); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toLongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toLongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, float &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toDouble(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, double &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = v.toDouble(&bOk); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, unsigned short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toUInt(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, unsigned int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toUInt(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, unsigned long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toULongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, unsigned long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + bool bOk = false; + t = static_cast(v.toULongLong(&bOk)); + return bOk; + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QDate &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toDate(); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toTime(); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QDateTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toDateTime(); + return t.isValid(); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QByteArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toByteArray(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QString &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toString(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QVariant &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_database) + { + t = v; + return qx_bool(true); + } + QString s = v.toString(); + if (!s.startsWith("$$JSON$$")) + { + t = v; + return qx_bool(true); + } + return qx::cvt::detail::QxConvert_FromString::fromString(s, t, format, index, ctx); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QUuid &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QUuid(v.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, qx::QxDateNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxDateNeutral::fromNeutral(v.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, qx::QxTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxTimeNeutral::fromNeutral(v.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, qx::QxDateTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = qx::QxDateTimeNeutral::fromNeutral(v.toString()); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, std::string &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toString().toStdString(); + return qx_bool(true); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toString().toLatin1().constData(); + return qx_bool(true); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, std::wstring &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toString().toStdWString(); + return qx_bool(true); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + Q_UNUSED(t); + Q_UNUSED(v); + qAssert(false); /* Need STL compatibility ! */ + return qx_bool(true); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, qx_bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + QString s = v.toString(); + t.fromString(s); + return qx_bool(true); + } + }; + +#ifndef _QX_NO_JSON + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QJsonValue &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QJsonValue::fromVariant(v); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QJsonArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toJsonArray(); + return qx_bool(true); + } + }; + + template <> + struct QxConvert_FromVariant + { + static inline qx_bool fromVariant(const QVariant &v, QJsonObject &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = v.toJsonObject(); + return qx_bool(true); + } + }; + +#endif // _QX_NO_JSON + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (v.isNull()) + { + t = boost::none; + return qx_bool(true); + } + else if (!t) + { + t = T(); + } + return qx::cvt::from_variant(v, (*t), format, index, ctx); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::pair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QPair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::vector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::list &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QVector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QLinkedList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QFlags &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + t = QFlags(QFlag(v.toInt())); + return true; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QMultiHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, QMultiMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, qx::QxCollection &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + template + struct QxConvert_FromVariant> + { + static inline qx_bool fromVariant(const QVariant &v, std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_FROM_VARIANT; + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx diff --git a/inl/QxConvert/QxConvert_Qt.inl b/inl/QxConvert/QxConvert_Qt.inl new file mode 100644 index 0000000..f43bc28 --- /dev/null +++ b/inl/QxConvert/QxConvert_Qt.inl @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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_STRING_CVT_QT_H_ +#define _QX_STRING_CVT_QT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include + +QX_CVT_USING_ARCHIVE_IMPL(QObject) +QX_CVT_USING_ARCHIVE_IMPL(QPoint) +QX_CVT_USING_ARCHIVE_IMPL(QRect) +QX_CVT_USING_ARCHIVE_IMPL(QSize) +QX_CVT_USING_ARCHIVE_IMPL(QStringList) +QX_CVT_USING_ARCHIVE_IMPL(QUrl) +QX_CVT_USING_ARCHIVE_IMPL(QSqlError) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_CVT_USING_ARCHIVE_IMPL(QRegExp) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_QT_GUI +QX_CVT_USING_ARCHIVE_IMPL(QBrush) +QX_CVT_USING_ARCHIVE_IMPL(QColor) +QX_CVT_USING_ARCHIVE_IMPL(QFont) +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_CVT_USING_ARCHIVE_IMPL(QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_CVT_USING_ARCHIVE_IMPL(QRegion) +QX_CVT_USING_ARCHIVE_IMPL(QImage) +QX_CVT_USING_ARCHIVE_IMPL(QPicture) +QX_CVT_USING_ARCHIVE_IMPL(QPixmap) +#endif // _QX_ENABLE_QT_GUI + +QX_CVT_USING_ARCHIVE_IMPL(qx::QxSqlQuery) +QX_CVT_USING_ARCHIVE_IMPL(qx::QxInvalidValue) +QX_CVT_USING_ARCHIVE_IMPL(qx::QxInvalidValueX) + +#endif // _QX_STRING_CVT_QT_H_ diff --git a/inl/QxConvert/QxConvert_ToJson.inl b/inl/QxConvert/QxConvert_ToJson.inl new file mode 100644 index 0000000..fa9d0f3 --- /dev/null +++ b/inl/QxConvert/QxConvert_ToJson.inl @@ -0,0 +1,387 @@ +/**************************************************************************** +** +** 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_NO_JSON + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::trait::no_type &t, const QString &format) + { + Q_UNUSED(t); + Q_UNUSED(format); + return QJsonValue(); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const bool &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const short &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const int &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const long &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const long long &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const float &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const double &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const unsigned short &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const unsigned int &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const unsigned long &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const unsigned long long &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QDateTime &t, const QString &format) + { +#ifdef _QX_ENABLE_MONGODB + if (t.isValid() && format.startsWith("mongodb")) + { + QString dt = t.toString(QX_JSON_DATE_TIME_FORMAT); + if (dt.count() <= QX_JSON_DATE_TIME_FORMAT_SIZE) + { + dt += "Z"; + } + QJsonObject obj; + obj.insert("$date", QJsonValue(dt)); + return QJsonValue(obj); + } +#endif // _QX_ENABLE_MONGODB + + Q_UNUSED(format); + if (t.isValid()) + { + return QJsonValue(t.toString(QX_JSON_DATE_TIME_FORMAT)); + }; + return QJsonValue(); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QDate &t, const QString &format) + { +#ifdef _QX_ENABLE_MONGODB + if (t.isValid() && format.startsWith("mongodb")) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + { + QTime time = ((t.isValid()) ? QTime(0, 0) : QTime()); + QDateTime dt(t, time); + return QxConvert_ToJson::toJson(dt, format); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + { + QDateTime dt(t); + return QxConvert_ToJson::toJson(dt, format); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +#endif // _QX_ENABLE_MONGODB + + Q_UNUSED(format); + if (t.isValid()) + { + return QJsonValue(t.toString(Qt::ISODate)); + }; + return QJsonValue(); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QTime &t, const QString &format) + { + Q_UNUSED(format); + if (t.isValid()) + { + return QJsonValue(t.toString(QX_JSON_DATE_TIME_FORMAT)); + }; + return QJsonValue(); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QByteArray &t, const QString &format) + { + Q_UNUSED(format); + QString s = t.toBase64(); + return QJsonValue(s); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QString &t, const QString &format) + { +#ifdef _QX_ENABLE_MONGODB + if (t.startsWith("qx_oid:") && format.startsWith("mongodb")) + { + QJsonObject obj; + obj.insert("$oid", QJsonValue(t.right(t.size() - 7))); + return QJsonValue(obj); + } +#endif // _QX_ENABLE_MONGODB + + Q_UNUSED(format); + return QJsonValue(t); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QVariant &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue::fromVariant(t); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const QUuid &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toString()); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxDateNeutral &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxTimeNeutral &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx::QxDateTimeNeutral &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const std::string &t, const QString &format) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + return QJsonValue(QString::fromStdString(t)); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + return QJsonValue(QString::fromLatin1(t.data(), int(t.size()))); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const std::wstring &t, const QString &format) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + return QJsonValue(QString::fromStdWString(t)); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(t); + qAssert(false); /* Need STL compatibility ! */ + return QJsonValue(); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + template <> + struct QxConvert_ToJson + { + static inline QJsonValue toJson(const qx_bool &t, const QString &format) + { + Q_UNUSED(format); + QJsonObject obj; + obj["value"] = t.getValue(); + obj["code"] = static_cast(t.getCode()); + obj["desc"] = t.getDesc(); + return QJsonValue(obj); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToJson> + { + static inline QJsonValue toJson(const boost::optional &t, const QString &format) + { + if (t) + { + return qx::cvt::to_json((*t), format); + }; + return QJsonValue(); + } + }; + +#endif // _QX_ENABLE_BOOST + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/inl/QxConvert/QxConvert_ToString.inl b/inl/QxConvert/QxConvert_ToString.inl new file mode 100644 index 0000000..75efe06 --- /dev/null +++ b/inl/QxConvert/QxConvert_ToString.inl @@ -0,0 +1,923 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToString + { + static inline QString toString(const qx::trait::no_type &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return ""; + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QString &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t; + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QUuid &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QDate &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(format.isEmpty() ? QString(QX_STR_CVT_QDATE_FORMAT) : format); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(format.isEmpty() ? QString(QX_STR_CVT_QTIME_FORMAT) : format); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QDateTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(format.isEmpty() ? QString(QX_STR_CVT_QDATETIME_FORMAT) : format); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QByteArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString(t); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QVariant &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + +#ifndef _QX_NO_JSON + if (qx::cvt::detail::helper::checkConvertQVariantToString(t)) + { + QString type = QString("%1").arg(static_cast(t.type()), 6, 10, QChar('0')); + QString val = "$$JSON$$" + type + "$$"; + QJsonValue json = QJsonValue::fromVariant(t); + QJsonDocument doc = (json.isArray() ? QJsonDocument(json.toArray()) : QJsonDocument(json.toObject())); + return (val + QString::fromUtf8(doc.toJson())); + } +#endif // _QX_NO_JSON + + return t.toString(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const qx_bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return (t ? "1" : "0"); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const char &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString(t); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const float &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const double &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const unsigned short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const unsigned int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const unsigned long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const unsigned long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + return (format.isEmpty() ? QString::number(t) : QString(format).arg(t)); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const qx::QxDateNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toNeutral(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const qx::QxTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toNeutral(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const qx::QxDateTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toNeutral(); + } + }; + + template <> + struct QxConvert_ToString + { + static inline QString toString(const std::string &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromStdString(t); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromLatin1(t.data(), int(t.size())); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_ToString + { + static inline QString toString(const std::wstring &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromStdWString(t); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + Q_UNUSED(t); + qAssert(false); /* Need STL compatibility ! */ + return QString(); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + +#ifndef _QX_NO_JSON + + template <> + struct QxConvert_ToString + { + static inline QString toString(const QJsonValue &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(index); + Q_UNUSED(ctx); + QJsonDocument::JsonFormat jsonFormat = QJsonDocument::Compact; + if (!format.isEmpty()) + { + jsonFormat = ((format == "indented") ? QJsonDocument::Indented : jsonFormat); + } + QJsonDocument doc = (t.isArray() ? QJsonDocument(t.toArray()) : QJsonDocument(t.toObject())); + return QString::fromUtf8(doc.toJson(jsonFormat)); + } + }; + +#endif // _QX_NO_JSON + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_string((*t), format, index, ctx); + }; + return QString(); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::pair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_ToString> + { + static inline QString toString(const QPair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::vector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::list &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_ToString> + { + static inline QString toString(const QVector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_ToString> + { + static inline QString toString(const QList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct QxConvert_ToString> + { + static inline QString toString(const QLinkedList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct QxConvert_ToString> + { + static inline QString toString(const QFlags &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::number(static_cast(t)); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const QHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const QMultiHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const QMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const QMultiMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const qx::QxCollection &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + template + struct QxConvert_ToString> + { + static inline QString toString(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE::to_string(t); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx diff --git a/inl/QxConvert/QxConvert_ToVariant.inl b/inl/QxConvert/QxConvert_ToVariant.inl new file mode 100644 index 0000000..47b64f8 --- /dev/null +++ b/inl/QxConvert/QxConvert_ToVariant.inl @@ -0,0 +1,946 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION +#define QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT QX_CVT_DEFAULT_ARCHIVE::to_string(t) +#else // _QX_ENABLE_BOOST_SERIALIZATION +#define QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT QX_CVT_DEFAULT_ARCHIVE::to_byte_array(t) +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const qx::trait::no_type &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(t); + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const float &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const double &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const unsigned short &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const unsigned int &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const unsigned long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const unsigned long long &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(static_cast(t)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QDate &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QDateTime &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QByteArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QString &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QVariant &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (ctx != qx::cvt::context::e_database) + { + return t; + } + if (!qx::cvt::detail::helper::checkConvertQVariantToString(t)) + { + return t; + } + return QVariant(qx::cvt::detail::QxConvert_ToString::toString(t, format, index, ctx)); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QUuid &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t.toString()); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const qx::QxDateNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const qx::QxTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const qx::QxDateTimeNeutral &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QVariant(t.toNeutral()); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const std::string &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#ifndef QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromStdString(t); + } + }; +#else // QT_NO_STL + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromLatin1(t.data(), int(t.size())); + } + }; +#endif // QT_NO_STL + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const std::wstring &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) +#if ((!defined(QT_NO_STL)) && (!defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::fromStdWString(t); + } + }; +#else // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + Q_UNUSED(t); + qAssert(false); /* Need STL compatibility ! */ + return QVariant(); + } + }; +#endif // ((! defined(QT_NO_STL)) && (! defined(QT_NO_STL_WCHAR))) + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const qx_bool &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toString(); + } + }; + +#ifndef _QX_NO_JSON + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QJsonValue &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return t.toVariant(); + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QJsonArray &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + QVariant var(t); + return var; + } + }; + + template <> + struct QxConvert_ToVariant + { + static inline QVariant toVariant(const QJsonObject &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + QVariant var(t); + return var; + } + }; + +#endif // _QX_NO_JSON + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::optional &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + if (t) + { + return qx::cvt::to_variant((*t), format, index, ctx); + }; + return qx::trait::construct_null_qvariant::get(); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::pair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QPair &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::vector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::list &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::unordered_set &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::unordered_multiset &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QVector &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QLinkedList &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QFlags &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QString::number(static_cast(t)); + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::unordered_map &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::unordered_multimap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QMultiHash &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const QMultiMap &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const qx::QxCollection &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + template + struct QxConvert_ToVariant> + { + static inline QVariant toVariant(const std::tuple &t, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + Q_UNUSED(format); + Q_UNUSED(index); + Q_UNUSED(ctx); + return QX_CVT_DEFAULT_ARCHIVE_TO_VARIANT; + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx diff --git a/inl/QxConvert/QxConvert_WithIndex.inl b/inl/QxConvert/QxConvert_WithIndex.inl new file mode 100644 index 0000000..efd844b --- /dev/null +++ b/inl/QxConvert/QxConvert_WithIndex.inl @@ -0,0 +1,1015 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace cvt + { + namespace detail + { + + template + struct QxConvert_WithIndex_ToString + { + static inline QString toString(const T &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::detail::QxConvert_ToString::toString(data, format, index, ctx); } + }; + + template + struct QxConvert_WithIndex_FromString + { + static inline qx_bool fromString(T &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::detail::QxConvert_FromString::fromString(s, data, format, index, ctx); } + }; + + template + struct QxConvert_WithIndex_ToVariant + { + static inline QVariant toVariant(const T &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::detail::QxConvert_ToVariant::toVariant(data, format, index, ctx); } + }; + + template + struct QxConvert_WithIndex_FromVariant + { + static inline qx_bool fromVariant(T &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) { return qx::cvt::detail::QxConvert_FromVariant::fromVariant(v, data, format, index, ctx); } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::pair &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_string(data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::to_string(data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::pair &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_string(s, data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::from_string(s, data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::pair &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_variant(data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::to_variant(data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::pair &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_variant(v, data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::from_variant(v, data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const QPair &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_string(data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::to_string(data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(QPair &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_string(s, data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::from_string(s, data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const QPair &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_variant(data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::to_variant(data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(QPair &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_variant(v, data.second, format, -1, ctx) : ((index == 0) ? qx::cvt::from_variant(v, data.first, format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#ifdef _QX_ENABLE_BOOST + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::to_string(boost::tuples::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::from_string(s, boost::tuples::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::to_variant(boost::tuples::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::from_variant(v, boost::tuples::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::to_string(boost::tuples::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::to_string(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::from_string(s, boost::tuples::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::from_string(s, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::to_variant(boost::tuples::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::to_variant(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::from_variant(v, boost::tuples::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::from_variant(v, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::to_string(boost::tuples::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::to_string(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::from_string(s, boost::tuples::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::from_string(s, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::to_variant(boost::tuples::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::to_variant(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::from_variant(v, boost::tuples::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::from_variant(v, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::to_string(boost::tuples::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::to_string(boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_string(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::from_string(s, boost::tuples::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::from_string(s, boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_string(s, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::to_variant(boost::tuples::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::to_variant(boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_variant(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::from_variant(v, boost::tuples::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::from_variant(v, boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_variant(v, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::to_string(boost::tuples::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::to_string(boost::tuples::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::to_string(boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_string(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(boost::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::from_string(s, boost::tuples::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::from_string(s, boost::tuples::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::from_string(s, boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_string(s, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const boost::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::to_variant(boost::tuples::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::to_variant(boost::tuples::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::to_variant(boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_variant(boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(boost::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::from_variant(v, boost::tuples::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::from_variant(v, boost::tuples::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::from_variant(v, boost::tuples::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_variant(v, boost::tuples::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, boost::tuples::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, boost::tuples::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, boost::tuples::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, boost::tuples::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, boost::tuples::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + +#endif // _QX_ENABLE_BOOST + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 2)); + return ((index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 3)); + return ((index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 4)); + return ((index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::to_string(std::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::from_string(s, std::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::to_variant(std::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 5)); + return ((index == 4) ? qx::cvt::from_variant(v, std::get<4>(data), format, -1, ctx) : (index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::to_string(std::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::to_string(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::from_string(s, std::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::from_string(s, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::to_variant(std::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::to_variant(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 6)); + return ((index == 5) ? qx::cvt::from_variant(v, std::get<5>(data), format, -1, ctx) : (index == 4) ? qx::cvt::from_variant(v, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::to_string(std::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::to_string(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::from_string(s, std::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::from_string(s, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::to_variant(std::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::to_variant(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 7)); + return ((index == 6) ? qx::cvt::from_variant(v, std::get<6>(data), format, -1, ctx) : (index == 5) ? qx::cvt::from_variant(v, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::to_string(std::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::to_string(std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_string(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::from_string(s, std::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::from_string(s, std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_string(s, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::to_variant(std::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::to_variant(std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_variant(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 8)); + return ((index == 7) ? qx::cvt::from_variant(v, std::get<7>(data), format, -1, ctx) : (index == 6) ? qx::cvt::from_variant(v, std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_variant(v, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToString> + { + static inline QString toString(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::to_string(std::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::to_string(std::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::to_string(std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_string(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_string(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_string(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_string(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_string(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_string(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToString>::toString(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromString> + { + static inline qx_bool fromString(std::tuple &data, const QString &s, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::from_string(s, std::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::from_string(s, std::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::from_string(s, std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_string(s, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_string(s, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_string(s, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_string(s, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_string(s, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_string(s, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromString>::fromString(s, data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_ToVariant> + { + static inline QVariant toVariant(const std::tuple &data, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::to_variant(std::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::to_variant(std::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::to_variant(std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::to_variant(std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::to_variant(std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::to_variant(std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::to_variant(std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::to_variant(std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::to_variant(std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_ToVariant>::toVariant(data, format, -1, ctx))); + } + }; + + template + struct QxConvert_WithIndex_FromVariant> + { + static inline qx_bool fromVariant(std::tuple &data, const QVariant &v, const QString &format, int index, qx::cvt::context::ctx_type ctx) + { + qAssert((index >= -1) && (index < 9)); + return ((index == 8) ? qx::cvt::from_variant(v, std::get<8>(data), format, -1, ctx) : (index == 7) ? qx::cvt::from_variant(v, std::get<7>(data), format, -1, ctx) + : (index == 6) ? qx::cvt::from_variant(v, std::get<6>(data), format, -1, ctx) + : (index == 5) ? qx::cvt::from_variant(v, std::get<5>(data), format, -1, ctx) + : (index == 4) ? qx::cvt::from_variant(v, std::get<4>(data), format, -1, ctx) + : (index == 3) ? qx::cvt::from_variant(v, std::get<3>(data), format, -1, ctx) + : (index == 2) ? qx::cvt::from_variant(v, std::get<2>(data), format, -1, ctx) + : (index == 1) ? qx::cvt::from_variant(v, std::get<1>(data), format, -1, ctx) + : ((index == 0) ? qx::cvt::from_variant(v, std::get<0>(data), format, -1, ctx) : qx::cvt::detail::QxConvert_FromVariant>::fromVariant(v, data, format, -1, ctx))); + } + }; + + } // namespace detail + } // namespace cvt +} // namespace qx diff --git a/inl/QxDao/QxDao_Count.inl b/inl/QxDao/QxDao_Count.inl new file mode 100644 index 0000000..e2fe29d --- /dev/null +++ b/inl/QxDao/QxDao_Count.inl @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Count + { + + static long count(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase) + { + T t; + Q_UNUSED(t); + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "count", new qx::QxSqlQueryBuilder_Count(), (&query)); + if (!dao.isValid()) + { + return 0; + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + long cnt = 0; + qx::dao::mongodb::QxMongoDB_Helper::count((&dao), dao.getDataMemberX()->getClass(), cnt, (&query)); + if (!dao.isValid()) + { + return 0; + } + return cnt; + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + dao.errEmpty(); + return 0; + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + dao.errFailed(); + return 0; + } + if (!dao.nextRecord()) + { + dao.errNoData(); + return 0; + } + + return static_cast(dao.query().value(0).toLongLong()); + } + + static QSqlError count(long &lCount, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase) + { + T t; + Q_UNUSED(t); + lCount = 0; + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "count", new qx::QxSqlQueryBuilder_Count(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::mongodb::QxMongoDB_Helper::count((&dao), dao.getDataMemberX()->getClass(), lCount, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + if (!dao.nextRecord()) + { + return dao.errNoData(); + } + lCount = static_cast(dao.query().value(0).toLongLong()); + + return dao.error(); + } + }; + + template + struct QxDao_Count_WithRelation + { + + static QSqlError count(long &lCount, const QStringList &relation, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase) + { + T t; + Q_UNUSED(t); + lCount = 0; + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "count with relation", new qx::QxSqlQueryBuilder_Count_WithRelation(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::mongodb::QxMongoDB_Helper::count((&dao), dao.getDataMemberX()->getClass(), lCount, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QStringList columns; + QString sql = dao.builder().buildSql(columns, dao.getSqlRelationLinked()).getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + if (!dao.nextRecord()) + { + return dao.errNoData(); + } + lCount = static_cast(dao.query().value(0).toLongLong()); + + return dao.error(); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_CreateTable.inl b/inl/QxDao/QxDao_CreateTable.inl new file mode 100644 index 0000000..a6694d7 --- /dev/null +++ b/inl/QxDao/QxDao_CreateTable.inl @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_CreateTable + { + + static QSqlError createTable(QSqlDatabase *pDatabase) + { + T t; + Q_UNUSED(t); + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "create table", new qx::QxSqlQueryBuilder_CreateTable()); + if (!dao.isValid()) + { + return dao.error(); + } + + if (dao.database().driverName() != "QSQLITE") + { + QString sWarningMsg = "-- WARNING -- the function qx::dao::create_table() can be used only with a SQLite database to create examples or prototypes, for other databases, it is recommended :"; + sWarningMsg += "\n\t - to use QxEntityEditor application and its DDL SQL database schema export plugin ;"; + sWarningMsg += "\n\t - or to manage the database schema with an external tool provided by the SGBD (SQLite Manager for SQLite, pgAdmin for PostgreSQL, MySQL Workbench for MySQL, etc...) ;"; + sWarningMsg += "\n\t - or to generate database schema using the introspection engine of QxOrm library : go to 'https://www.qxorm.com/qxorm_en/faq.html#faq_230' web page for more details."; + qDebug("[QxOrm] %s", qPrintable(sWarningMsg)); + } + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.query().exec(sql)) + { + return dao.errFailed(); + } + + long index = 0; + qx::IxSqlRelation *pRelation = NULL; + while ((pRelation = dao.builder().nextRelation(index))) + { + QString sqlExtraTable = pRelation->createExtraTable(); + if (sqlExtraTable.isEmpty()) + { + continue; + } + QSqlQuery queryCreateTable(dao.database()); + bool bExtraTable = queryCreateTable.exec(sqlExtraTable); + if (!bExtraTable) + { + dao.updateError(queryCreateTable.lastError()); + break; + } + } + + return dao.error(); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_DeleteAll.inl b/inl/QxDao/QxDao_DeleteAll.inl new file mode 100644 index 0000000..4f4a287 --- /dev/null +++ b/inl/QxDao/QxDao_DeleteAll.inl @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_DeleteAll + { + + static QSqlError deleteAll(const qx::QxSqlQuery &query, QSqlDatabase *pDatabase, bool bVerifySoftDelete) + { + T t; + Q_UNUSED(t); + qx::IxSqlQueryBuilder *pBuilder = new qx::QxSqlQueryBuilder_DeleteAll(); + pBuilder->init(); + qx::QxSoftDelete oSoftDelete = pBuilder->getSoftDelete(); + if (bVerifySoftDelete && !oSoftDelete.isEmpty()) + { + delete pBuilder; + pBuilder = new qx::QxSqlQueryBuilder_SoftDeleteAll(); + } + + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "delete all", pBuilder, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::mongodb::QxMongoDB_Helper::deleteMany((&dao), dao.getDataMemberX()->getClass(), QStringList(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!pDatabase) + { + dao.transaction(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + + return dao.error(); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_DeleteById.inl b/inl/QxDao/QxDao_DeleteById.inl new file mode 100644 index 0000000..d45b4e8 --- /dev/null +++ b/inl/QxDao/QxDao_DeleteById.inl @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_DeleteById_Generic + { + + static QSqlError deleteById(T &t, QSqlDatabase *pDatabase, bool bVerifySoftDelete, bool bUseExecBatch) + { + Q_UNUSED(bUseExecBatch); // Useful only with containers + qx::IxSqlQueryBuilder *pBuilder = new qx::QxSqlQueryBuilder_DeleteById(); + pBuilder->init(); + qx::QxSoftDelete oSoftDelete = pBuilder->getSoftDelete(); + if (bVerifySoftDelete && !oSoftDelete.isEmpty()) + { + delete pBuilder; + pBuilder = new qx::QxSqlQueryBuilder_SoftDeleteById(); + } + + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "delete by id", pBuilder); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.isValidPrimaryKey(t)) + { + return dao.errInvalidId(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_delete((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::mongodb::QxMongoDB_Helper::deleteOne((&dao), dao.getDataMemberX()->getClass(), qx::serialization::json::to_string(t, 1, "mongodb:only_id"), NULL); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::on_after_delete((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + if (pSqlGenerator) + { + pSqlGenerator->onBeforeDelete((&dao), (&t)); + } + qx::dao::on_before_delete((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_DeleteById::resolveInput(t, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + return dao.errFailed(); + } + if (pSqlGenerator) + { + pSqlGenerator->onAfterDelete((&dao), (&t)); + } + qx::dao::on_after_delete((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_DeleteById_Container + { + + static QSqlError deleteById(T &t, QSqlDatabase *pDatabase, bool bVerifySoftDelete, bool bUseExecBatch) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + qx::IxSqlQueryBuilder *pBuilder = new qx::QxSqlQueryBuilder_DeleteById(); + pBuilder->init(); + qx::QxSoftDelete oSoftDelete = pBuilder->getSoftDelete(); + if (bVerifySoftDelete && !oSoftDelete.isEmpty()) + { + delete pBuilder; + pBuilder = new qx::QxSqlQueryBuilder_SoftDeleteById(); + } + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "delete by id", pBuilder); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + dao.setUseExecBatch(bUseExecBatch); + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!deleteItem((*it), dao)) + { + return dao.error(); + } + } + QStringList &itemsAsJson = dao.itemsAsJson(); + qx::dao::mongodb::QxMongoDB_Helper::deleteMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, NULL); + if (!dao.isValid()) + { + return dao.error(); + } + dao.qxQuery().queryAt(2, ""); + dao.itemsAsJson().clear(); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!deleteItem((*it), dao)) + { + return dao.error(); + } + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!deleteItem((*it), dao)) + { + return dao.error(); + } + } + + if (bUseExecBatch && (!dao.exec())) + { + return dao.errFailed(); + } + return dao.error(); + } + + private: + template + static inline bool deleteItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return deleteItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::deleteById(item, dao); + } + + template + struct deleteItem_Helper + { + static inline bool deleteById(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_DeleteById_Container::deleteItem((*item), dao) : true); + } + }; + + template + struct deleteItem_Helper, false> + { + static inline bool deleteById(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_DeleteById_Container::deleteItem(item.second, dao); + } + }; + + template + struct deleteItem_Helper, false> + { + static inline bool deleteById(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_DeleteById_Container::deleteItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct deleteItem_Helper, false> + { + static inline bool deleteById(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_DeleteById_Container::deleteItem(item.second, dao); + } + }; + + template + struct deleteItem_Helper, false> + { + static inline bool deleteById(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_DeleteById_Container::deleteItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct deleteItem_Helper + { + static bool deleteById(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + if (!dao.isValidPrimaryKey(item)) + { + dao.errInvalidId(); + return false; + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + if (dao.qxQuery().queryAt(2) == "") + { + qx::dao::on_after_delete((&item), (&dao)); + return dao.isValid(); + } + qx::dao::on_before_delete((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + QVariant id = (dao.getDataId() ? dao.getDataId()->toVariant(&item) : QVariant()); + if (!id.isNull() && !id.toString().isEmpty()) + { + dao.itemsAsJson().append(id.toString()); + } + return dao.isValid(); + } +#endif // _QX_ENABLE_MONGODB + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + if (pSqlGenerator) + { + pSqlGenerator->onBeforeDelete((&dao), (&item)); + } + qx::dao::on_before_delete((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_DeleteById::resolveInput(item, dao.query(), dao.builder()); + } + + if (dao.getUseExecBatch()) + { + return dao.isValid(); + } + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + if (pSqlGenerator) + { + pSqlGenerator->onAfterDelete((&dao), (&item)); + } + qx::dao::on_after_delete((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_DeleteById_Ptr + { + + static inline QSqlError deleteById(T &t, QSqlDatabase *pDatabase, bool bVerifySoftDelete, bool bUseExecBatch) + { + if (!t) + { + return QSqlError(); + } + if (bVerifySoftDelete) + { + return qx::dao::delete_by_id((*t), pDatabase, bUseExecBatch); + } + return qx::dao::destroy_by_id((*t), pDatabase, bUseExecBatch); + } + }; + + template + struct QxDao_DeleteById + { + + static inline QSqlError deleteById(T &t, QSqlDatabase *pDatabase, bool bVerifySoftDelete, bool bUseExecBatch = false) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_DeleteById_Ptr, qx::dao::detail::QxDao_DeleteById_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_DeleteById_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_DeleteById_Container, type_dao_2>::type type_dao_3; + return type_dao_3::deleteById(t, pDatabase, bVerifySoftDelete, bUseExecBatch); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_ExecuteQuery.inl b/inl/QxDao/QxDao_ExecuteQuery.inl new file mode 100644 index 0000000..ebb202e --- /dev/null +++ b/inl/QxDao/QxDao_ExecuteQuery.inl @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_ExecuteQuery_Generic + { + + static QSqlError executeQuery(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "execute custom sql query or stored procedure", new qx::QxSqlQueryBuilder_Count()); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::mongodb::QxMongoDB_Helper::executeCommand((&dao), dao.getDataMemberX()->getClass(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = query.response().toString(); + qx::serialization::json::from_string(t, json, 1, "mongodb"); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = query.query(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + dao.builder().setSqlQuery(sql); + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + query.resolve(dao.query()); + if (!dao.exec(true)) + { + return dao.errFailed(); + } + query.resolveOutput(dao.query(), false); + if (!dao.nextRecord()) + { + return dao.error(); + } + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + qx::IxDataMemberX *pDataMemberX = dao.builder().getDataMemberX(); + if (!pDataMemberX) + { + qAssert(false); + return dao.error(); + } + QSqlRecord record = dao.query().record(); + for (int i = 0; i < record.count(); i++) + { + if (!pDataMemberX->exist_WithDaoStrategy(record.fieldName(i))) + { + continue; + } + qx::IxDataMember *pDataMember = pDataMemberX->get_WithDaoStrategy(record.fieldName(i)); + if (pDataMember) + { + pDataMember->fromVariant((&t), record.value(i), -1, qx::cvt::context::e_database); + } + } + + qx::dao::on_after_fetch((&t), (&dao)); + return dao.error(); + } + }; + + template + struct QxDao_ExecuteQuery_Container + { + + static QSqlError executeQuery(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + qx::trait::generic_container::clear(t); + qx::IxSqlQueryBuilder *pBuilder = new qx::QxSqlQueryBuilder_Count(); + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "execute custom sql query or stored procedure", pBuilder); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::mongodb::QxMongoDB_Helper::executeCommand((&dao), dao.getDataMemberX()->getClass(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = query.response().toString(); + qx::serialization::json::from_string(t, json, 1, "mongodb"); + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = query.query(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + dao.builder().setSqlQuery(sql); + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + query.resolve(dao.query()); + if (!dao.exec(true)) + { + return dao.errFailed(); + } + query.resolveOutput(dao.query(), false); + + QVector> vColumnToFetch; + bool bSize = (dao.hasFeature(QSqlDriver::QuerySize) && (dao.query().size() > 0)); + if (bSize) + { + qx::trait::generic_container::reserve(t, dao.query().size()); + } + while (dao.nextRecord()) + { + insertNewItem(t, dao, vColumnToFetch); + if (!dao.isValid()) + { + return dao.error(); + } + } + if (bSize) + { + qAssert(qx::trait::generic_container::size(t) == static_cast(dao.query().size())); + } + + return dao.error(); + } + + private: + static void insertNewItem(T &t, qx::dao::detail::QxDao_Helper_Container &dao, QVector> &vColumnToFetch) + { + typedef typename qx::trait::generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + + type_item item = qx::trait::generic_container::createItem(); + type_value_qx &item_val = item.value_qx(); + qx::IxDataMember *pId = dao.getDataId(); + QVariant vId; + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + + if (vColumnToFetch.count() <= 0) + { + qx::IxDataMemberX *pDataMemberX = dao.builder().getDataMemberX(); + if (!pDataMemberX) + { + qAssert(false); + return; + } + QSqlRecord record = dao.query().record(); + vColumnToFetch.reserve(record.count()); + for (int i = 0; i < record.count(); i++) + { + if (!pDataMemberX->exist_WithDaoStrategy(record.fieldName(i))) + { + continue; + } + qx::IxDataMember *pDataMember = pDataMemberX->get_WithDaoStrategy(record.fieldName(i)); + if (pDataMember) + { + vColumnToFetch.append(qMakePair(i, pDataMember)); + } + } + } + + for (int j = 0; j < vColumnToFetch.count(); j++) + { + QVariant vValue = dao.query().value(vColumnToFetch[j].first); + vColumnToFetch[j].second->fromVariant((&item_val), vValue, -1, qx::cvt::context::e_database); + if (pId == vColumnToFetch[j].second) + { + vId = vValue; + } + } + + if (!vId.isValid()) + { + vId = QVariant(static_cast(qx::trait::generic_container::size(t))); + } + qx::cvt::from_variant(vId, item.key(), "", -1, qx::cvt::context::e_database); + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + qx::trait::generic_container::insertItem(t, item); + } + }; + + template + struct QxDao_ExecuteQuery_Ptr + { + + static inline QSqlError executeQuery(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + if (!t) + { + qx::trait::construct_ptr::get(t); + }; + return qx::dao::execute_query(query, (*t), pDatabase); + } + }; + + template + struct QxDao_ExecuteQuery + { + + static inline QSqlError executeQuery(qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_ExecuteQuery_Ptr, qx::dao::detail::QxDao_ExecuteQuery_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_ExecuteQuery_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_ExecuteQuery_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::executeQuery(query, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Exist.inl b/inl/QxDao/QxDao_Exist.inl new file mode 100644 index 0000000..5a7a98a --- /dev/null +++ b/inl/QxDao/QxDao_Exist.inl @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Exist_Generic + { + + static qx_bool exist(T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "exist", new qx::QxSqlQueryBuilder_Exist()); + if (!dao.isValid()) + { + return qx_bool(false); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + long cnt = 0; + QString json = qx::serialization::json::to_string(t, 1, "mongodb:only_id"); + qx_query query(json); + qx::dao::mongodb::QxMongoDB_Helper::count((&dao), dao.getDataMemberX()->getClass(), cnt, (&query)); + if (!dao.isValid()) + { + return qx_bool(false); + } + return qx_bool(cnt >= 1); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + dao.errEmpty(); + return qx_bool(false); + } + if (!dao.prepare(sql)) + { + dao.errFailed(true); + return qx_bool(false); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Exist::resolveInput(t, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + dao.errFailed(); + return qx_bool(false); + } + return qx_bool(dao.nextRecord()); + } + }; + + template + struct QxDao_Exist_Container + { + + static qx_bool exist(T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return qx_bool(false); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "exist", new qx::QxSqlQueryBuilder_Exist()); + if (!dao.isValid()) + { + return qx_bool(false); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!existItem((*it), dao)) + { + return qx_bool(false); + } + } + return qx_bool(true); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + dao.errEmpty(); + return qx_bool(false); + } + if (!dao.prepare(sql)) + { + dao.errFailed(true); + return qx_bool(false); + } + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!existItem((*it), dao)) + { + return qx_bool(false); + } + } + + return qx_bool(true); + } + + private: + template + static inline bool existItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return existItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::exist(item, dao); + } + + template + struct existItem_Helper + { + static inline bool exist(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Exist_Container::existItem((*item), dao) : false); + } + }; + + template + struct existItem_Helper, false> + { + static inline bool exist(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Exist_Container::existItem(item.second, dao); + } + }; + + template + struct existItem_Helper, false> + { + static inline bool exist(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Exist_Container::existItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct existItem_Helper, false> + { + static inline bool exist(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Exist_Container::existItem(item.second, dao); + } + }; + + template + struct existItem_Helper, false> + { + static inline bool exist(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Exist_Container::existItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct existItem_Helper + { + static bool exist(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + long cnt = 0; + QString json = qx::serialization::json::to_string(item, 1, "mongodb:only_id"); + qx_query query(json); + qx::dao::mongodb::QxMongoDB_Helper::count((&dao), dao.getDataMemberX()->getClass(), cnt, (&query)); + if (!dao.isValid()) + { + return false; + } + return (cnt >= 1); + } +#endif // _QX_ENABLE_MONGODB + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Exist::resolveInput(item, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + return dao.nextRecord(); + } + }; + }; + + template + struct QxDao_Exist_Ptr + { + + static inline qx_bool exist(T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::exist((*t), pDatabase) : qx_bool(false)); + } + }; + + template + struct QxDao_Exist + { + + static inline qx_bool exist(T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Exist_Ptr, qx::dao::detail::QxDao_Exist_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Exist_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Exist_Container, type_dao_2>::type type_dao_3; + return type_dao_3::exist(t, pDatabase); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_FetchAll.inl b/inl/QxDao/QxDao_FetchAll.inl new file mode 100644 index 0000000..503882c --- /dev/null +++ b/inl/QxDao/QxDao_FetchAll.inl @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_FetchAll_Generic + { + + static QSqlError fetchAll(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "fetch all", new qx::QxSqlQueryBuilder_FetchAll(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + dao.setSqlColumns(columns); + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = qx::serialization::json::to_string(t, 1, "mongodb:only_id"); + qx::dao::mongodb::QxMongoDB_Helper::findOne((&dao), dao.getDataMemberX()->getClass(), json, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + qx::serialization::json::from_string(t, json, 1, ctx); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + + if (dao.nextRecord()) + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::detail::QxSqlQueryHelper_FetchAll::resolveOutput(t, dao.query(), dao.builder(), columns); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + } + + return dao.error(); + } + }; + +#ifdef _QX_ENABLE_MONGODB + template + struct QxDao_FetchAll_MongoDB_Fetcher : public qx::dao::mongodb::QxMongoDB_Fetcher + { + + T &m_t; + qx::dao::detail::QxDao_Helper_Container &m_dao; + + QxDao_FetchAll_MongoDB_Fetcher(T &t, qx::dao::detail::QxDao_Helper_Container &dao) : qx::dao::mongodb::QxMongoDB_Fetcher(), m_t(t), m_dao(dao) { ; } + virtual ~QxDao_FetchAll_MongoDB_Fetcher() { ; } + + virtual void fetch(const QString &json) + { + typedef typename qx::trait::generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + type_item item = qx::trait::generic_container::createItem(); + type_value_qx &item_val = item.value_qx(); + qx::IxDataMember *pId = m_dao.getDataId(); + QStringList columns = m_dao.getSqlColumns(); + + if (json.isEmpty()) + { + return; + } + qx::dao::detail::IxDao_Timer timer((&m_dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::on_before_fetch((&item_val), (&m_dao)); + if (!m_dao.isValid()) + { + return; + } + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + qx::serialization::json::from_string(item_val, json, 1, ctx); + for (int i = 0; i < (pId ? pId->getNameCount() : 0); i++) + { + QVariant id = pId->toVariant((&item_val), "", i, qx::cvt::context::e_database); + qx::cvt::from_variant(id, item.key(), "", i, qx::cvt::context::e_database); + } + qx::dao::on_after_fetch((&item_val), (&m_dao)); + if (!m_dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + qx::trait::generic_container::insertItem(m_t, item); + } + }; +#endif // _QX_ENABLE_MONGODB + + template + struct QxDao_FetchAll_Container + { + + static QSqlError fetchAll(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + qx::trait::generic_container::clear(t); + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "fetch all", new qx::QxSqlQueryBuilder_FetchAll(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + dao.setSqlColumns(columns); + QStringList &itemsAsJson = dao.itemsAsJson(); + QxDao_FetchAll_MongoDB_Fetcher fetcher(t, dao); + qx::dao::mongodb::QxMongoDB_Helper::findMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, (&query), (&fetcher)); + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + dao.setSqlColumns(columns); + + bool bSize = (dao.hasFeature(QSqlDriver::QuerySize) && (dao.query().size() > 0)); + if (bSize) + { + qx::trait::generic_container::reserve(t, dao.query().size()); + } + while (dao.nextRecord()) + { + insertNewItem(t, dao); + if (!dao.isValid()) + { + return dao.error(); + } + } + if (bSize) + { + qAssert(qx::trait::generic_container::size(t) == static_cast(dao.query().size())); + } + + return dao.error(); + } + + private: + static void insertNewItem(T &t, qx::dao::detail::QxDao_Helper_Container &dao) + { + typedef typename qx::trait::generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + type_item item = qx::trait::generic_container::createItem(); + type_value_qx &item_val = item.value_qx(); + qx::IxDataMember *pId = dao.getDataId(); + QStringList columns = dao.getSqlColumns(); + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + if (pId) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = dao.getIdFromQuery(i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + } + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxSqlQueryHelper_FetchAll::resolveOutput(item_val, dao.query(), dao.builder(), columns); + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + qx::trait::generic_container::insertItem(t, item); + } + }; + + template + struct QxDao_FetchAll_Ptr + { + + static inline QSqlError fetchAll(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + return (t ? qx::dao::fetch_by_query(query, (*t), pDatabase, columns) : QSqlError()); + } + }; + + template + struct QxDao_FetchAll + { + + static inline QSqlError fetchAll(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_Ptr, qx::dao::detail::QxDao_FetchAll_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::fetchAll(query, t, pDatabase, columns); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_FetchAll_WithRelation.inl b/inl/QxDao/QxDao_FetchAll_WithRelation.inl new file mode 100644 index 0000000..5e27c3e --- /dev/null +++ b/inl/QxDao/QxDao_FetchAll_WithRelation.inl @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_FetchAll_WithRelation_Generic + { + + typedef qx::dao::detail::QxDao_Helper type_dao_helper; + typedef qx::dao::detail::QxSqlQueryHelper_FetchAll_WithRelation type_query_helper; + + static QSqlError fetchAll(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + type_dao_helper dao(t, pDatabase, "fetch all with relation", new qx::QxSqlQueryBuilder_FetchAll_WithRelation(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = qx::serialization::json::to_string(t, 1, "mongodb:only_id"); + qx::dao::mongodb::QxMongoDB_Helper::findOne((&dao), dao.getDataMemberX()->getClass(), json, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::serialization::json::from_string(t, json, 1, "mongodb"); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QStringList columns; + QString sql = dao.builder().buildSql(columns, dao.getSqlRelationLinked()).getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.getCartesianProduct()) + { + fetchAll_Complex(t, dao); + } + else + { + fetchAll_Simple(t, dao); + } + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::on_after_fetch((&t), (&dao)); + } + + return dao.error(); + } + + private: + static inline void fetchAll_Simple(T &t, type_dao_helper &dao) + { + if (!dao.nextRecord()) + { + return; + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), t, dao.query(), dao.builder()); + } + + static inline void fetchAll_Complex(T &t, type_dao_helper &dao) + { + while (dao.nextRecord()) + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), t, dao.query(), dao.builder()); + if (!dao.isValid()) + { + return; + } + } + } + }; + +#ifdef _QX_ENABLE_MONGODB + template + struct QxDao_FetchAll_WithRelation_MongoDB_Fetcher : public qx::dao::mongodb::QxMongoDB_Fetcher + { + + typedef qx::dao::detail::QxDao_Helper_Container type_dao_helper; + typedef qx::trait::generic_container type_generic_container; + typedef typename type_generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + typedef typename type_item::type_value type_value; + + T &m_t; + type_dao_helper &m_dao; + + QxDao_FetchAll_WithRelation_MongoDB_Fetcher(T &t, type_dao_helper &dao) : qx::dao::mongodb::QxMongoDB_Fetcher(), m_t(t), m_dao(dao) { ; } + virtual ~QxDao_FetchAll_WithRelation_MongoDB_Fetcher() { ; } + + virtual void fetch(const QString &json) + { + fetcherHelper::insertNewItem(m_t, m_dao, json); + } + + private: + template + struct fetcherHelper + { + static void insertNewItem(T &t, type_dao_helper &dao, const QString &json) + { + type_item item = type_generic_container::createItem(); + qx::IxDataMember *pId = dao.getDataId(); + qAssert(pId); + + if (json.isEmpty()) + { + return; + } + type_value_qx &item_val_tmp = item.value_qx(); + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::serialization::json::from_string(item_val_tmp, json, 1, "mongodb:columns{,_id," + pId->getKey() + ",}"); + for (int i = 0; i < (pId ? pId->getNameCount() : 0); i++) + { + QVariant id = pId->toVariant((&item_val_tmp), "", i, qx::cvt::context::e_database); + qx::cvt::from_variant(id, item.key(), "", i, qx::cvt::context::e_database); + } + type_value *pValue = type_generic_container::insertItem(t, item); + type_value_qx &item_val = (pValue ? (*static_cast(pValue)) : item.value_qx()); + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::serialization::json::from_string(item_val, json, 1, "mongodb"); + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + }; + + template + struct fetcherHelper + { + static void insertNewItem(T &t, type_dao_helper &dao, const QString &json) + { + type_item item = type_generic_container::createItem(); + type_value_qx &item_val = item.value_qx(); + qx::IxDataMember *pId = dao.getDataId(); + qAssert(pId); + + if (json.isEmpty()) + { + return; + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::serialization::json::from_string(item_val, json, 1, "mongodb"); + for (int i = 0; i < (pId ? pId->getNameCount() : 0); i++) + { + QVariant id = pId->toVariant((&item_val), "", i, qx::cvt::context::e_database); + qx::cvt::from_variant(id, item.key(), "", i, qx::cvt::context::e_database); + } + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + qx::trait::generic_container::insertItem(t, item); + } + }; + }; +#endif // _QX_ENABLE_MONGODB + + template + struct QxDao_FetchAll_WithRelation_Container + { + + typedef qx::dao::detail::QxDao_Helper_Container type_dao_helper; + typedef qx::dao::detail::QxDao_FetchAll_WithRelation_Container type_this; + typedef qx::trait::generic_container type_generic_container; + typedef typename type_generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + typedef typename type_item::type_value type_value; + typedef qx::dao::detail::QxSqlQueryHelper_FetchAll_WithRelation type_query_helper; + + static QSqlError fetchAll(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + type_generic_container::clear(t); + type_dao_helper dao(t, pDatabase, "fetch all with relation", new qx::QxSqlQueryBuilder_FetchAll_WithRelation(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + QStringList &itemsAsJson = dao.itemsAsJson(); + QxDao_FetchAll_WithRelation_MongoDB_Fetcher fetcher(t, dao); + qx::dao::mongodb::QxMongoDB_Helper::findMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, (&query), (&fetcher)); + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + bool bComplex = dao.getCartesianProduct(); + QVariant vId; + QStringList columns; + QString sql = dao.builder().buildSql(columns, dao.getSqlRelationLinked()).getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(true); + sql = dao.builder().getSqlQuery(); + } + if (!dao.exec()) + { + return dao.errFailed(); + } + bool bSize = (dao.hasFeature(QSqlDriver::QuerySize) && (dao.query().size() > 0)); + if (bSize) + { + type_generic_container::reserve(t, dao.query().size()); + } + + while (dao.nextRecord()) + { + if (!dao.isValid()) + { + return dao.error(); + } + vId = dao.getIdFromQuery(-1); + void *pItemTmp = (bComplex ? dao.builder().existIdX(0, vId, vId) : NULL); + if (!pItemTmp) + { + insertHelper::insertNewItem(t, dao); + continue; + } + type_value_qx *pItem = static_cast(pItemTmp); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), (*pItem), dao.query(), dao.builder()); + } + + if (bSize) + { + type_generic_container::reserve(t, type_generic_container::size(t)); + } + return dao.error(); + } + + private: + template + struct insertHelper + { + static void insertNewItem(T &t, type_dao_helper &dao) + { + type_item item = type_generic_container::createItem(); + qx::IxDataMember *pId = dao.getDataId(); + qAssert(pId); + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + if (pId) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = dao.getIdFromQuery(i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + } + type_value *pValue = type_generic_container::insertItem(t, item); + type_value_qx &item_val = (pValue ? (*static_cast(pValue)) : item.value_qx()); + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), item_val, dao.query(), dao.builder()); + if (!dao.isValid()) + { + return; + } + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + }; + + template + struct insertHelper + { + static void insertNewItem(T &t, type_dao_helper &dao) + { + type_item item = type_generic_container::createItem(); + type_value_qx &item_val = item.value_qx(); + qx::IxDataMember *pId = dao.getDataId(); + qAssert(pId); + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + if (pId) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + QVariant v = dao.getIdFromQuery(i); + qx::cvt::from_variant(v, item.key(), "", i, qx::cvt::context::e_database); + } + } + qx::dao::on_before_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), item_val, dao.query(), dao.builder()); + if (!dao.isValid()) + { + return; + } + qx::dao::on_after_fetch((&item_val), (&dao)); + if (!dao.isValid()) + { + return; + } + type_generic_container::insertItem(t, item); + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + }; + }; + + template + struct QxDao_FetchAll_WithRelation_Ptr + { + + static inline QSqlError fetchAll(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::fetch_by_query_with_relation(relation, query, (*t), pDatabase) : QSqlError()); + } + }; + + template + struct QxDao_FetchAll_WithRelation + { + + static inline QSqlError fetchAll(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + QStringList lst; + if (!relation.isEmpty()) + { + lst = relation.split("|"); + } + return QxDao_FetchAll_WithRelation::fetchAll(lst, query, t, pDatabase); + } + + static inline QSqlError fetchAll(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_WithRelation_Ptr, qx::dao::detail::QxDao_FetchAll_WithRelation_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_WithRelation_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchAll_WithRelation_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::fetchAll(relation, query, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_FetchById.inl b/inl/QxDao/QxDao_FetchById.inl new file mode 100644 index 0000000..6e5ec25 --- /dev/null +++ b/inl/QxDao/QxDao_FetchById.inl @@ -0,0 +1,363 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_FetchById_Generic + { + + static QSqlError fetchById(T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "fetch by id", new qx::QxSqlQueryBuilder_FetchById()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.isValidPrimaryKey(t)) + { + return dao.errInvalidId(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + dao.setSqlColumns(columns); + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = qx::serialization::json::to_string(t, 1, "mongodb:only_id"); + qx::dao::mongodb::QxMongoDB_Helper::findOne((&dao), dao.getDataMemberX()->getClass(), json, NULL); + if (!dao.isValid()) + { + return dao.error(); + } + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + qx::serialization::json::from_string(t, json, 1, ctx); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_FetchById::resolveInput(t, dao.query(), dao.builder(), columns); + } + + if (!dao.exec(true)) + { + return dao.errFailed(); + } + if (!dao.nextRecord()) + { + return dao.errNoData(); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::detail::QxSqlQueryHelper_FetchById::resolveOutput(t, dao.query(), dao.builder(), columns); + qx::dao::on_after_fetch((&t), (&dao)); + } + + return dao.error(); + } + }; + + template + struct QxDao_FetchById_Container + { + + static QSqlError fetchById(T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "fetch by id", new qx::QxSqlQueryBuilder_FetchById()); + if (!dao.isValid()) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + dao.setSqlColumns(columns); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + QStringList &itemsAsJson = dao.itemsAsJson(); + qx::dao::mongodb::QxMongoDB_Helper::findMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, NULL, NULL); + if (!dao.isValid()) + { + return dao.error(); + } + dao.qxQuery().queryAt(2, ""); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + dao.setSqlColumns(columns); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool fetchItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bFetchOk = fetchItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::fetch(item, dao); + if (bFetchOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bFetchOk; + } + + template + struct fetchItem_Helper + { + static inline bool fetch(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_FetchById_Container::fetchItem((*item), dao) : true); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_FetchById_Container::fetchItem(item.second, dao); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_FetchById_Container::fetchItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct fetchItem_Helper, false> + { + static inline bool fetch(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_FetchById_Container::fetchItem(item.second, dao); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_FetchById_Container::fetchItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct fetchItem_Helper + { + static bool fetch(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + QStringList columns = dao.getSqlColumns(); + if (!dao.isValidPrimaryKey(item)) + { + dao.errInvalidId(); + return false; + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + if (dao.qxQuery().queryAt(2) == "") + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + if (!dao.itemsAsJson().isEmpty()) + { + QString json = dao.itemsAsJson().takeFirst(); + if (!json.isEmpty()) + { + qx::serialization::json::from_string(item, json, 1, ctx); + } + } + qx::dao::on_after_fetch((&item), (&dao)); + return dao.isValid(); + } + { + qx::dao::on_before_fetch((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + QVariant id = (dao.getDataId() ? dao.getDataId()->toVariant(&item) : QVariant()); + if (!id.isNull() && !id.toString().isEmpty()) + { + dao.itemsAsJson().append(id.toString()); + } + } + return dao.isValid(); + } +#endif // _QX_ENABLE_MONGODB + + { + qx::dao::on_before_fetch((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_FetchById::resolveInput(item, dao.query(), dao.builder(), columns); + } + + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + if (!dao.nextRecord()) + { + dao.errNoData(); + return false; + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::detail::QxSqlQueryHelper_FetchById::resolveOutput(item, dao.query(), dao.builder(), columns); + qx::dao::on_after_fetch((&item), (&dao)); + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_FetchById_Ptr + { + + static inline QSqlError fetchById(T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + if (!t) + { + qx::trait::construct_ptr::get(t); + }; + return qx::dao::fetch_by_id((*t), pDatabase, columns); + } + }; + + template + struct QxDao_FetchById + { + + static inline QSqlError fetchById(T &t, QSqlDatabase *pDatabase, const QStringList &columns) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_Ptr, qx::dao::detail::QxDao_FetchById_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::fetchById(t, pDatabase, columns); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_FetchById_WithRelation.inl b/inl/QxDao/QxDao_FetchById_WithRelation.inl new file mode 100644 index 0000000..cfcca0c --- /dev/null +++ b/inl/QxDao/QxDao_FetchById_WithRelation.inl @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_FetchById_WithRelation_Generic + { + + typedef qx::dao::detail::QxDao_Helper type_dao_helper; + typedef qx::dao::detail::QxSqlQueryHelper_FetchById_WithRelation type_query_helper; + + static QSqlError fetchById(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + type_dao_helper dao(t, pDatabase, "fetch by id with relation", new qx::QxSqlQueryBuilder_FetchById_WithRelation()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.isValidPrimaryKey(t)) + { + return dao.errInvalidId(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString json = qx::serialization::json::to_string(t, 1, "mongodb:only_id"); + qx::dao::mongodb::QxMongoDB_Helper::findOne((&dao), dao.getDataMemberX()->getClass(), json, NULL); + if (!dao.isValid()) + { + return dao.error(); + } + + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::serialization::json::from_string(t, json, 1, "mongodb"); + qx::dao::on_after_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QStringList columns; + QString sql = dao.builder().buildSql(columns, dao.getSqlRelationLinked()).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + type_query_helper::resolveInput(dao.getSqlRelationLinked(), t, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + return dao.errFailed(); + } + + { + qx::dao::on_before_fetch((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.getCartesianProduct()) + { + fetchById_Complex(t, dao); + } + else + { + fetchById_Simple(t, dao); + } + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::on_after_fetch((&t), (&dao)); + } + + return dao.error(); + } + + private: + static inline void fetchById_Simple(T &t, type_dao_helper &dao) + { + if (!dao.nextRecord()) + { + dao.errNoData(); + return; + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), t, dao.query(), dao.builder()); + } + + static inline void fetchById_Complex(T &t, type_dao_helper &dao) + { + if (!dao.nextRecord()) + { + dao.errNoData(); + return; + } + do + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), t, dao.query(), dao.builder()); + if (!dao.isValid()) + { + return; + } + } while (dao.nextRecord()); + } + }; + + template + struct QxDao_FetchById_WithRelation_Container + { + + typedef qx::dao::detail::QxDao_Helper_Container type_dao_helper; + typedef qx::dao::detail::QxDao_FetchById_WithRelation_Container type_this; + typedef qx::trait::generic_container type_generic_container; + typedef typename type_generic_container::type_item type_item; + typedef typename type_item::type_value_qx type_value_qx; + typedef typename type_item::type_value type_value; + + static QSqlError fetchById(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + type_dao_helper dao(t, pDatabase, "fetch by id with relation", new qx::QxSqlQueryBuilder_FetchById_WithRelation()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + QStringList &itemsAsJson = dao.itemsAsJson(); + qx::dao::mongodb::QxMongoDB_Helper::findMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, NULL, NULL); + if (!dao.isValid()) + { + return dao.error(); + } + dao.qxQuery().queryAt(2, ""); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QStringList columns; + QString sql = dao.builder().buildSql(columns, dao.getSqlRelationLinked()).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!fetchItem((*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool fetchItem(U &item, type_dao_helper &dao) + { + bool bFetchOk = fetchItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::fetch(item, dao); + if (bFetchOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bFetchOk; + } + + template + struct fetchItem_Helper + { + static inline bool fetch(U &item, type_dao_helper &dao) + { + return (item ? type_this::fetchItem((*item), dao) : true); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(std::pair &item, type_dao_helper &dao) + { + return type_this::fetchItem(item.second, dao); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(const std::pair &item, type_dao_helper &dao) + { + return type_this::fetchItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct fetchItem_Helper, false> + { + static inline bool fetch(QPair &item, type_dao_helper &dao) + { + return type_this::fetchItem(item.second, dao); + } + }; + + template + struct fetchItem_Helper, false> + { + static inline bool fetch(const QPair &item, type_dao_helper &dao) + { + return type_this::fetchItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct fetchItem_Helper + { + + typedef qx::dao::detail::QxSqlQueryHelper_FetchById_WithRelation type_query_helper; + + static bool fetch(U &item, type_dao_helper &dao) + { + if (!dao.isValidPrimaryKey(item)) + { + dao.errInvalidId(); + return false; + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + if (dao.qxQuery().queryAt(2) == "") + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + if (!dao.itemsAsJson().isEmpty()) + { + QString json = dao.itemsAsJson().takeFirst(); + if (!json.isEmpty()) + { + qx::serialization::json::from_string(item, json, 1, "mongodb"); + } + } + qx::dao::on_after_fetch((&item), (&dao)); + return dao.isValid(); + } + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + qx::dao::on_before_fetch((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + QVariant id = (dao.getDataId() ? dao.getDataId()->toVariant(&item) : QVariant()); + if (!id.isNull() && !id.toString().isEmpty()) + { + dao.itemsAsJson().append(id.toString()); + } + } + return dao.isValid(); + } +#endif // _QX_ENABLE_MONGODB + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + type_query_helper::resolveInput(dao.getSqlRelationLinked(), item, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + + { + qx::dao::on_before_fetch((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + if (dao.getCartesianProduct()) + { + fetch_Complex(item, dao); + } + else + { + fetch_Simple(item, dao); + } + if (!dao.isValid()) + { + return false; + } + qx::dao::on_after_fetch((&item), (&dao)); + } + + return dao.isValid(); + } + + static inline void fetch_Simple(U &item, type_dao_helper &dao) + { + if (!dao.nextRecord()) + { + dao.errNoData(); + return; + } + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), item, dao.query(), dao.builder()); + } + + static inline void fetch_Complex(U &item, type_dao_helper &dao) + { + if (!dao.nextRecord()) + { + dao.errNoData(); + return; + } + do + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_build_instance); + type_query_helper::resolveOutput(dao.getSqlRelationLinked(), item, dao.query(), dao.builder()); + if (!dao.isValid()) + { + return; + } + } while (dao.nextRecord()); + } + }; + }; + + template + struct QxDao_FetchById_WithRelation_Ptr + { + + static inline QSqlError fetchById(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + if (!t) + { + qx::trait::construct_ptr::get(t); + }; + return qx::dao::fetch_by_id_with_relation(relation, (*t), pDatabase); + } + }; + + template + struct QxDao_FetchById_WithRelation + { + + static inline QSqlError fetchById(const QString &relation, T &t, QSqlDatabase *pDatabase) + { + QStringList lst; + if (!relation.isEmpty()) + { + lst = relation.split("|"); + } + return QxDao_FetchById_WithRelation::fetchById(lst, t, pDatabase); + } + + static inline QSqlError fetchById(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_WithRelation_Ptr, qx::dao::detail::QxDao_FetchById_WithRelation_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_WithRelation_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_FetchById_WithRelation_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::fetchById(relation, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Helper.inl b/inl/QxDao/QxDao_Helper.inl new file mode 100644 index 0000000..6330247 --- /dev/null +++ b/inl/QxDao/QxDao_Helper.inl @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + class QxDao_Helper : public IxDao_Helper + { + + public: + QxDao_Helper(T &t, QSqlDatabase *pDatabase, const QString &sContext, qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery = NULL) : IxDao_Helper(pBuilder, pQuery) + { + Q_UNUSED(t); + init(pDatabase, sContext); + } + virtual ~QxDao_Helper() { static_assert(qx::trait::is_qx_registered::type_sql>::value, "qx::trait::is_qx_registered::type_sql>::value"); } + }; + + template + struct QxDao_Keep_Original + { + static inline void backup(T &t) { Q_UNUSED(t); } + }; + + template + struct QxDao_Keep_Original> + { + static inline void backup(qx::dao::ptr &t) + { + if (t) + { + t.resetOriginal(qx::clone_to_qt_shared_ptr(*t)); + } + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx + +#include "../../inl/QxDao/QxDao_Helper_Container.inl" diff --git a/inl/QxDao/QxDao_Helper_Container.inl b/inl/QxDao/QxDao_Helper_Container.inl new file mode 100644 index 0000000..01b49c0 --- /dev/null +++ b/inl/QxDao/QxDao_Helper_Container.inl @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#define QX_DAO_HELPER_CONTAINER(className) \ + namespace qx \ + { \ + namespace dao \ + { \ + namespace detail \ + { \ + template \ + class QxDao_Helper_Container> : public IxDao_Helper \ + { \ + public: \ + QxDao_Helper_Container(className &t, QSqlDatabase *pDatabase, const QString &sContext, qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery = NULL) : IxDao_Helper(pBuilder, pQuery) \ + { \ + Q_UNUSED(t); \ + init(pDatabase, sContext); \ + } \ + virtual ~QxDao_Helper_Container() { static_assert(qx::trait::is_qx_registered::type_sql>::value, "qx::trait::is_qx_registered::type_sql>::value"); } \ + }; \ + } \ + } \ + } // namespace qx::dao::detail + +#define QX_DAO_HELPER_CONTAINER_KEY_VALUE(className) \ + namespace qx \ + { \ + namespace dao \ + { \ + namespace detail \ + { \ + template \ + class QxDao_Helper_Container> : public IxDao_Helper \ + { \ + public: \ + QxDao_Helper_Container(className &t, QSqlDatabase *pDatabase, const QString &sContext, qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery = NULL) : IxDao_Helper(pBuilder, pQuery) \ + { \ + Q_UNUSED(t); \ + init(pDatabase, sContext); \ + } \ + virtual ~QxDao_Helper_Container() { static_assert(qx::trait::is_qx_registered::type_sql>::value, "qx::trait::is_qx_registered::type_sql>::value"); } \ + }; \ + } \ + } \ + } // namespace qx::dao::detail + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Helper_Container + { + ; + }; + + } // namespace detail + } // namespace dao +} // namespace qx + +QX_DAO_HELPER_CONTAINER(std::vector) +QX_DAO_HELPER_CONTAINER(std::list) +QX_DAO_HELPER_CONTAINER(std::set) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(std::map) + +#ifdef _QX_ENABLE_BOOST + +QX_DAO_HELPER_CONTAINER(boost::unordered_set) +QX_DAO_HELPER_CONTAINER(boost::unordered_multiset) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(boost::unordered_map) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(boost::unordered_multimap) + +#endif // _QX_ENABLE_BOOST + +QX_DAO_HELPER_CONTAINER(std::unordered_set) +QX_DAO_HELPER_CONTAINER(std::unordered_multiset) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(std::unordered_map) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(std::unordered_multimap) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DAO_HELPER_CONTAINER(QVector) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DAO_HELPER_CONTAINER(QList) +QX_DAO_HELPER_CONTAINER(QSet) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(QMap) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(QMultiMap) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(QHash) +QX_DAO_HELPER_CONTAINER_KEY_VALUE(QMultiHash) + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +QX_DAO_HELPER_CONTAINER(QLinkedList) +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +QX_DAO_HELPER_CONTAINER_KEY_VALUE(qx::QxCollection) diff --git a/inl/QxDao/QxDao_Insert.inl b/inl/QxDao/QxDao_Insert.inl new file mode 100644 index 0000000..bc17cc0 --- /dev/null +++ b/inl/QxDao/QxDao_Insert.inl @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Insert_Generic + { + + static QSqlError insert(T &t, QSqlDatabase *pDatabase, bool bUseExecBatch) + { + Q_UNUSED(bUseExecBatch); // Useful only with containers + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "insert", new qx::QxSqlQueryBuilder_Insert()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.validateInstance(t)) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_insert((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString insertedId; + qx::dao::mongodb::QxMongoDB_Helper::insertOne((&dao), dao.getDataMemberX()->getClass(), qx::serialization::json::to_string(t, 1, "mongodb"), insertedId); + if (!dao.isValid()) + { + return dao.error(); + } + if (!insertedId.isEmpty() && dao.getDataId()) + { + dao.getDataId()->fromVariant((&t), insertedId, -1, qx::cvt::context::e_database); + } + qx::dao::on_after_insert((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!pDatabase) + { + dao.transaction(); + } + if (pSqlGenerator) + { + pSqlGenerator->checkSqlInsert((&dao), sql); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + if (pSqlGenerator) + { + pSqlGenerator->onBeforeInsert((&dao), (&t)); + } + qx::dao::on_before_insert((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Insert::resolveInput(t, dao.query(), dao.builder()); + } + + if (!dao.exec(true)) + { + return dao.errFailed(); + } + dao.updateLastInsertId(t); + if (pSqlGenerator) + { + pSqlGenerator->onAfterInsert((&dao), (&t)); + } + qx::dao::on_after_insert((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_Insert_Container + { + + static QSqlError insert(T &t, QSqlDatabase *pDatabase, bool bUseExecBatch) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "insert", new qx::QxSqlQueryBuilder_Insert()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.validateInstance(t)) + { + return dao.error(); + } + dao.setUseExecBatch(bUseExecBatch); + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!insertItem((*it), dao)) + { + return dao.error(); + } + } + QStringList &itemsAsJson = dao.itemsAsJson(); + QStringList insertedId; + qx::dao::mongodb::QxMongoDB_Helper::insertMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, insertedId); + if (!dao.isValid()) + { + return dao.error(); + } + dao.qxQuery().queryAt(2, ""); + dao.itemsAsJson().clear(); + dao.itemsAsJson().append(insertedId); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!insertItem((*it), dao)) + { + return dao.error(); + } + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + QString sql = dao.builder().buildSql().getSqlQuery(); + if (sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!pDatabase) + { + dao.transaction(); + } + if (pSqlGenerator) + { + pSqlGenerator->checkSqlInsert((&dao), sql); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!insertItem((*it), dao)) + { + return dao.error(); + } + } + + if (bUseExecBatch && (!dao.exec())) + { + return dao.errFailed(); + } + return dao.error(); + } + + private: + template + static inline bool insertItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bInsertOk = insertItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::insert(item, dao); + if (bInsertOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bInsertOk; + } + + template + struct insertItem_Helper + { + static inline bool insert(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Insert_Container::insertItem((*item), dao) : true); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_Container::insertItem(item.second, dao); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_Container::insertItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct insertItem_Helper, false> + { + static inline bool insert(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_Container::insertItem(item.second, dao); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_Container::insertItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct insertItem_Helper + { + static bool insert(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + if (dao.qxQuery().queryAt(2) == "") + { + if (!dao.itemsAsJson().isEmpty()) + { + QString oid = dao.itemsAsJson().takeFirst(); + if (!oid.isEmpty() && dao.getDataId()) + { + dao.getDataId()->fromVariant((&item), oid, -1, qx::cvt::context::e_database); + } + } + qx::dao::on_after_insert((&item), (&dao)); + return dao.isValid(); + } + qx::dao::on_before_insert((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + dao.itemsAsJson().append(qx::serialization::json::to_string(item, 1, "mongodb")); + return dao.isValid(); + } +#endif // _QX_ENABLE_MONGODB + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + if (pSqlGenerator) + { + pSqlGenerator->onBeforeInsert((&dao), (&item)); + } + qx::dao::on_before_insert((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Insert::resolveInput(item, dao.query(), dao.builder()); + } + + if (dao.getUseExecBatch()) + { + return dao.isValid(); + } + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + dao.updateLastInsertId(item); + if (pSqlGenerator) + { + pSqlGenerator->onAfterInsert((&dao), (&item)); + } + qx::dao::on_after_insert((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Insert_Ptr + { + + static inline QSqlError insert(T &t, QSqlDatabase *pDatabase, bool bUseExecBatch) + { + return (t ? qx::dao::insert((*t), pDatabase, bUseExecBatch) : QSqlError()); + } + }; + + template + struct QxDao_Insert + { + + static inline QSqlError insert(T &t, QSqlDatabase *pDatabase, bool bUseExecBatch = false) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_Ptr, qx::dao::detail::QxDao_Insert_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::insert(t, pDatabase, bUseExecBatch); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Insert_WithRelation.inl b/inl/QxDao/QxDao_Insert_WithRelation.inl new file mode 100644 index 0000000..9bbb9f3 --- /dev/null +++ b/inl/QxDao/QxDao_Insert_WithRelation.inl @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Insert_WithRelation_Generic + { + + static QSqlError insert(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "insert with relation", new qx::QxSqlQueryBuilder_Insert()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&t)); + params.setDatabase((&dao.database())); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + dao.updateError(qx::dao::insert(t, (&dao.database()))); + if (!dao.isValid()) + { + return dao.error(); + } + + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_Insert_WithRelation_Container + { + + static QSqlError insert(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "insert with relation", new qx::QxSqlQueryBuilder_Insert()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!insertItem((*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool insertItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bInsertOk = insertItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::insert(item, dao); + if (bInsertOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bInsertOk; + } + + template + struct insertItem_Helper + { + static inline bool insert(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Insert_WithRelation_Container::insertItem((*item), dao) : true); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_WithRelation_Container::insertItem(item.second, dao); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_WithRelation_Container::insertItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct insertItem_Helper, false> + { + static inline bool insert(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_WithRelation_Container::insertItem(item.second, dao); + } + }; + + template + struct insertItem_Helper, false> + { + static inline bool insert(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Insert_WithRelation_Container::insertItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct insertItem_Helper + { + static bool insert(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&item)); + params.setDatabase((&dao.database())); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + dao.updateError(qx::dao::insert(item, (&dao.database()))); + if (!dao.isValid()) + { + return false; + } + + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Insert_WithRelation_Ptr + { + + static inline QSqlError insert(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::insert_with_relation(relation, (*t), pDatabase) : QSqlError()); + } + }; + + template + struct QxDao_Insert_WithRelation + { + + static inline QSqlError insert(const QString &relation, T &t, QSqlDatabase *pDatabase) + { + QStringList lst; + if (!relation.isEmpty()) + { + lst = relation.split("|"); + } + return QxDao_Insert_WithRelation::insert(lst, t, pDatabase); + } + + static inline QSqlError insert(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_WithRelation_Ptr, qx::dao::detail::QxDao_Insert_WithRelation_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_WithRelation_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Insert_WithRelation_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::insert(relation, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Save.inl b/inl/QxDao/QxDao_Save.inl new file mode 100644 index 0000000..632d125 --- /dev/null +++ b/inl/QxDao/QxDao_Save.inl @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Save_Generic + { + + static QSqlError save(T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "save", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + qx_bool bExist = dao.isValidPrimaryKey(t); + if (bExist) + { + bExist = qx::dao::exist(t, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update(t, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert(t, (&dao.database()))); + } + + return dao.error(); + } + }; + + template + struct QxDao_Save_Container + { + + static QSqlError save(T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "save", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!saveItem((*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool saveItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bSaveOk = saveItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::save(item, dao); + if (bSaveOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bSaveOk; + } + + template + struct saveItem_Helper + { + static inline bool save(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Save_Container::saveItem((*item), dao) : false); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_Container::saveItem(item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_Container::saveItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct saveItem_Helper, false> + { + static inline bool save(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_Container::saveItem(item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_Container::saveItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct saveItem_Helper + { + static bool save(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx_bool bExist = dao.isValidPrimaryKey(item); + if (bExist) + { + bExist = qx::dao::exist(item, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update(item, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert(item, (&dao.database()))); + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Save_Ptr + { + + static inline QSqlError save(T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::save((*t), pDatabase) : QSqlError()); + } + }; + + template + struct QxDao_Save + { + + static inline QSqlError save(T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_Ptr, qx::dao::detail::QxDao_Save_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::save(t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Save_WithRelation.inl b/inl/QxDao/QxDao_Save_WithRelation.inl new file mode 100644 index 0000000..0909ce4 --- /dev/null +++ b/inl/QxDao/QxDao_Save_WithRelation.inl @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Save_WithRelation_Generic + { + + static QSqlError save(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "save with relation", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + qx_bool bExist = dao.isValidPrimaryKey(t); + if (bExist) + { + bExist = qx::dao::exist(t, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update_with_relation(relation, t, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert_with_relation(relation, t, (&dao.database()))); + } + + return dao.error(); + } + }; + + template + struct QxDao_Save_WithRelation_Container + { + + static QSqlError save(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "save with relation", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!saveItem(relation, (*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool saveItem(const QStringList &relation, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bSaveOk = saveItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::save(relation, item, dao); + if (bSaveOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bSaveOk; + } + + template + struct saveItem_Helper + { + static inline bool save(const QStringList &relation, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Save_WithRelation_Container::saveItem(relation, (*item), dao) : false); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(const QStringList &relation, std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Container::saveItem(relation, item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(const QStringList &relation, const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Container::saveItem(relation, item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct saveItem_Helper, false> + { + static inline bool save(const QStringList &relation, QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Container::saveItem(relation, item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(const QStringList &relation, const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Container::saveItem(relation, item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct saveItem_Helper + { + static bool save(const QStringList &relation, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx_bool bExist = dao.isValidPrimaryKey(item); + if (bExist) + { + bExist = qx::dao::exist(item, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update_with_relation(relation, item, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert_with_relation(relation, item, (&dao.database()))); + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Save_WithRelation_Ptr + { + + static inline QSqlError save(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::save_with_relation(relation, (*t), pDatabase) : QSqlError()); + } + }; + + template + struct QxDao_Save_WithRelation + { + + static inline QSqlError save(const QString &relation, T &t, QSqlDatabase *pDatabase) + { + QStringList lst; + if (!relation.isEmpty()) + { + lst = relation.split("|"); + } + return QxDao_Save_WithRelation::save(lst, t, pDatabase); + } + + static inline QSqlError save(const QStringList &relation, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Ptr, qx::dao::detail::QxDao_Save_WithRelation_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::save(relation, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Save_WithRelation_Recursive.inl b/inl/QxDao/QxDao_Save_WithRelation_Recursive.inl new file mode 100644 index 0000000..659519e --- /dev/null +++ b/inl/QxDao/QxDao_Save_WithRelation_Recursive.inl @@ -0,0 +1,516 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Save_WithRelation_Recursive_Generic + { + + static QSqlError save(T &t, qx::dao::save_mode::e_save_mode eSaveMode, QSqlDatabase *pDatabase, qx::QxSqlRelationParams *pRelationParams) + { + QStringList relation("*"); + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "save with relation recursive", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&t)); + if (!pRelationParams) + { + params.setDatabase((&dao.database())); + params.setSaveMode(eSaveMode); + params.setRecursiveMode(true); + } + else + { + params = (*pRelationParams); + params.setOwner(&t); + } + if (params.existRecursiveItem(&t)) + { + return dao.error(); + } + params.insertRecursiveItem(&t); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + if (eSaveMode == qx::dao::save_mode::e_check_insert_or_update) + { + qx_bool bExist = dao.isValidPrimaryKey(t); + if (bExist) + { + bExist = qx::dao::exist(t, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update(t, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert(t, (&dao.database()))); + } + } + else if (eSaveMode == qx::dao::save_mode::e_insert_only) + { + dao.updateError(qx::dao::insert(t, (&dao.database()))); + } + else if (eSaveMode == qx::dao::save_mode::e_update_only) + { + dao.updateError(qx::dao::update(t, (&dao.database()))); + } + else + { + qAssert(false); + } + + if (!dao.isValid()) + { + return dao.error(); + } + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_Save_WithRelation_Recursive_Container + { + + static QSqlError save(T &t, qx::dao::save_mode::e_save_mode eSaveMode, QSqlDatabase *pDatabase, qx::QxSqlRelationParams *pRelationParams) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + QStringList relation("*"); + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "save with relation recursive", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + if (eSaveMode == qx::dao::save_mode::e_check_insert_or_update) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!saveItem(eSaveMode, pRelationParams, (*it), dao)) + { + return dao.error(); + } + } + } + else if (eSaveMode == qx::dao::save_mode::e_insert_only) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!hierarchyOnBeforeSave(eSaveMode, pRelationParams, (*it), dao)) + { + return dao.error(); + } + } + dao.updateError(qx::dao::insert(t, (&dao.database()))); + if (!dao.isValid()) + { + return dao.error(); + } + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!hierarchyOnAfterSave(eSaveMode, pRelationParams, (*it), dao)) + { + return dao.error(); + } + } + } + else if (eSaveMode == qx::dao::save_mode::e_update_only) + { + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!hierarchyOnBeforeSave(eSaveMode, pRelationParams, (*it), dao)) + { + return dao.error(); + } + } + dao.updateError(qx::dao::update(t, (&dao.database()))); + if (!dao.isValid()) + { + return dao.error(); + } + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!hierarchyOnAfterSave(eSaveMode, pRelationParams, (*it), dao)) + { + return dao.error(); + } + } + } + else + { + qAssert(false); + } + + return dao.error(); + } + + private: + template + static inline bool saveItem(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bSaveOk = saveItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::save(eSaveMode, pRelationParams, item, dao); + if (bSaveOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bSaveOk; + } + + template + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bBeforeSaveOk = saveItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::hierarchyOnBeforeSave(eSaveMode, pRelationParams, item, dao); + if (bBeforeSaveOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bBeforeSaveOk; + } + + template + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bAfterSaveOk = saveItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::hierarchyOnAfterSave(eSaveMode, pRelationParams, item, dao); + if (bAfterSaveOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bAfterSaveOk; + } + + template + struct saveItem_Helper + { + static inline bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::saveItem(eSaveMode, pRelationParams, (*item), dao) : false); + } + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnBeforeSave(eSaveMode, pRelationParams, (*item), dao) : false); + } + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnAfterSave(eSaveMode, pRelationParams, (*item), dao) : false); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::saveItem(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnBeforeSave(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnAfterSave(eSaveMode, pRelationParams, item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::saveItem(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnBeforeSave(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnAfterSave(eSaveMode, pRelationParams, item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct saveItem_Helper, false> + { + static inline bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::saveItem(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnBeforeSave(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnAfterSave(eSaveMode, pRelationParams, item.second, dao); + } + }; + + template + struct saveItem_Helper, false> + { + static inline bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::saveItem(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnBeforeSave(eSaveMode, pRelationParams, item.second, dao); + } + static inline bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container::hierarchyOnAfterSave(eSaveMode, pRelationParams, item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct saveItem_Helper + { + static bool save(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&item)); + if (!pRelationParams) + { + params.setDatabase((&dao.database())); + params.setSaveMode(eSaveMode); + params.setRecursiveMode(true); + } + else + { + params = (*pRelationParams); + params.setOwner(&item); + } + if (params.existRecursiveItem(&item)) + { + return true; + } + params.insertRecursiveItem(&item); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + if (eSaveMode == qx::dao::save_mode::e_check_insert_or_update) + { + qx_bool bExist = dao.isValidPrimaryKey(item); + if (bExist) + { + bExist = qx::dao::exist(item, (&dao.database())); + } + if (bExist) + { + dao.updateError(qx::dao::update(item, (&dao.database()))); + } + else + { + dao.updateError(qx::dao::insert(item, (&dao.database()))); + } + } + else if (eSaveMode == qx::dao::save_mode::e_insert_only) + { + dao.updateError(qx::dao::insert(item, (&dao.database()))); + } + else if (eSaveMode == qx::dao::save_mode::e_update_only) + { + dao.updateError(qx::dao::update(item, (&dao.database()))); + } + else + { + qAssert(false); + } + + if (!dao.isValid()) + { + return false; + } + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + + static bool hierarchyOnBeforeSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&item)); + if (!pRelationParams) + { + params.setDatabase((&dao.database())); + params.setSaveMode(eSaveMode); + params.setRecursiveMode(true); + } + else + { + params = (*pRelationParams); + params.setOwner(&item); + } + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + return dao.isValid(); + } + + static bool hierarchyOnAfterSave(qx::dao::save_mode::e_save_mode eSaveMode, qx::QxSqlRelationParams *pRelationParams, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&item)); + if (!pRelationParams) + { + params.setDatabase((&dao.database())); + params.setSaveMode(eSaveMode); + params.setRecursiveMode(true); + } + else + { + params = (*pRelationParams); + params.setOwner(&item); + } + if (params.existRecursiveItem(&item)) + { + return true; + } + params.insertRecursiveItem(&item); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Save_WithRelation_Recursive_Ptr + { + + static inline QSqlError save(T &t, qx::dao::save_mode::e_save_mode eSaveMode, QSqlDatabase *pDatabase, qx::QxSqlRelationParams *pRelationParams) + { + return (t ? qx::dao::save_with_relation_recursive((*t), eSaveMode, pDatabase, pRelationParams) : QSqlError()); + } + }; + + template + struct QxDao_Save_WithRelation_Recursive + { + + static inline QSqlError save(T &t, qx::dao::save_mode::e_save_mode eSaveMode, QSqlDatabase *pDatabase, qx::QxSqlRelationParams *pRelationParams) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Recursive_Ptr, qx::dao::detail::QxDao_Save_WithRelation_Recursive_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Recursive_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Save_WithRelation_Recursive_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::save(t, eSaveMode, pDatabase, pRelationParams); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Trigger.inl b/inl/QxDao/QxDao_Trigger.inl new file mode 100644 index 0000000..cc27cb8 --- /dev/null +++ b/inl/QxDao/QxDao_Trigger.inl @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Trigger + { + + private: + typedef typename qx::trait::get_base_class::type type_base; + enum + { + is_valid_base_class = (!std::is_same::value) + }; + + public: + static inline void onBeforeInsert(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onBeforeInsert(t, dao); } + static inline void onBeforeUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onBeforeUpdate(t, dao); } + static inline void onBeforeDelete(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onBeforeDelete(t, dao); } + static inline void onBeforeFetch(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onBeforeFetch(t, dao); } + static inline void onAfterInsert(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onAfterInsert(t, dao); } + static inline void onAfterUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onAfterUpdate(t, dao); } + static inline void onAfterDelete(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onAfterDelete(t, dao); } + static inline void onAfterFetch(T *t, qx::dao::detail::IxDao_Helper *dao) { TriggerHelper::onAfterFetch(t, dao); } + + private: + template + struct TriggerHelper + { + static inline void onBeforeInsert(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onBeforeUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onBeforeDelete(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onBeforeFetch(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onAfterInsert(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onAfterUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onAfterDelete(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + static inline void onAfterFetch(T *t, qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(t); + Q_UNUSED(dao); + } + }; + + template + struct TriggerHelper + { + static inline void onBeforeInsert(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onBeforeInsert(static_cast(t), dao); } + static inline void onBeforeUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onBeforeUpdate(static_cast(t), dao); } + static inline void onBeforeDelete(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onBeforeDelete(static_cast(t), dao); } + static inline void onBeforeFetch(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onBeforeFetch(static_cast(t), dao); } + static inline void onAfterInsert(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onAfterInsert(static_cast(t), dao); } + static inline void onAfterUpdate(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onAfterUpdate(static_cast(t), dao); } + static inline void onAfterDelete(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onAfterDelete(static_cast(t), dao); } + static inline void onAfterFetch(T *t, qx::dao::detail::IxDao_Helper *dao) { qx::dao::detail::QxDao_Trigger::onAfterFetch(static_cast(t), dao); } + }; + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Update.inl b/inl/QxDao/QxDao_Update.inl new file mode 100644 index 0000000..89b419b --- /dev/null +++ b/inl/QxDao/QxDao_Update.inl @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Update_Generic + { + + static QSqlError update(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns, bool bUseExecBatch) + { + Q_UNUSED(bUseExecBatch); // Useful only with containers + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "update", new qx::QxSqlQueryBuilder_Update(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.isValidPrimaryKey(t)) + { + return dao.errInvalidId(); + } + if (!dao.validateInstance(t)) + { + return dao.error(); + } + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + qx::dao::on_before_update((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + qx::dao::mongodb::QxMongoDB_Helper::updateOne((&dao), dao.getDataMemberX()->getClass(), qx::serialization::json::to_string(t, 1, ctx), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + qx::dao::on_after_update((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(false); + sql = dao.builder().getSqlQuery(); + } + if (!pDatabase) + { + dao.transaction(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + if (pSqlGenerator) + { + pSqlGenerator->onBeforeUpdate((&dao), (&t)); + } + qx::dao::on_before_update((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Update::resolveInput(t, dao.query(), dao.builder(), columns); + } + + if (!query.isEmpty()) + { + query.resolve(dao.query()); + } + if (!dao.exec(true)) + { + return dao.errFailed(); + } + if (pSqlGenerator) + { + pSqlGenerator->onAfterUpdate((&dao), (&t)); + } + qx::dao::on_after_update((&t), (&dao)); + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_Update_Container + { + + static QSqlError update(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns, bool bUseExecBatch) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "update", new qx::QxSqlQueryBuilder_Update(), (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.validateInstance(t)) + { + return dao.error(); + } + dao.setUseExecBatch(bUseExecBatch); + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + dao.setSqlColumns(columns); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!updateItem((*it), dao)) + { + return dao.error(); + } + } + QStringList &itemsAsJson = dao.itemsAsJson(); + qx::dao::mongodb::QxMongoDB_Helper::updateMany((&dao), dao.getDataMemberX()->getClass(), itemsAsJson, (&query)); + if (!dao.isValid()) + { + return dao.error(); + } + dao.qxQuery().queryAt(2, ""); + dao.itemsAsJson().clear(); + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!updateItem((*it), dao)) + { + return dao.error(); + } + } + return dao.error(); + } +#endif // _QX_ENABLE_MONGODB + + QString sql = dao.builder().buildSql(columns).getSqlQuery(); + if (!dao.getDataId() || sql.isEmpty()) + { + return dao.errEmpty(); + } + if (!query.isEmpty()) + { + dao.addQuery(false); + sql = dao.builder().getSqlQuery(); + } + if (!pDatabase) + { + dao.transaction(); + } + if (!dao.prepare(sql)) + { + return dao.errFailed(true); + } + dao.setSqlColumns(columns); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!updateItem((*it), dao)) + { + return dao.error(); + } + } + + if (bUseExecBatch && (!dao.exec())) + { + return dao.errFailed(); + } + return dao.error(); + } + + private: + template + static inline bool updateItem(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bUpdateOk = updateItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::update(item, dao); + if (bUpdateOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bUpdateOk; + } + + template + struct updateItem_Helper + { + static inline bool update(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Update_Container::updateItem((*item), dao) : true); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_Container::updateItem(item.second, dao); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_Container::updateItem(item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct updateItem_Helper, false> + { + static inline bool update(QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_Container::updateItem(item.second, dao); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_Container::updateItem(item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct updateItem_Helper + { + static bool update(U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + QStringList columns = dao.getSqlColumns(); + +#ifdef _QX_ENABLE_MONGODB + if (dao.isMongoDB()) + { + if (dao.qxQuery().queryAt(2) == "") + { + qx::dao::on_after_update((&item), (&dao)); + return dao.isValid(); + } + QString ctx = QString("mongodb") + ((columns.count() > 0) ? (QString(":columns{,") + columns.join(",") + QString(",}")) : QString()); + qx::dao::on_before_update((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + dao.itemsAsJson().append(qx::serialization::json::to_string(item, 1, ctx)); + return dao.isValid(); + } +#endif // _QX_ENABLE_MONGODB + + if (!dao.isValidPrimaryKey(item)) + { + dao.errInvalidId(); + return false; + } + IxSqlGenerator *pSqlGenerator = dao.getSqlGenerator(); + if (pSqlGenerator) + { + pSqlGenerator->onBeforeUpdate((&dao), (&item)); + } + qx::dao::on_before_update((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + { + qx::dao::detail::IxDao_Timer timer((&dao), qx::dao::detail::IxDao_Helper::timer_cpp_read_instance); + qx::dao::detail::QxSqlQueryHelper_Update::resolveInput(item, dao.query(), dao.builder(), columns); + } + + dao.resolveQuery(); + if (dao.getUseExecBatch()) + { + return dao.isValid(); + } + if (!dao.exec(true)) + { + dao.errFailed(); + return false; + } + if (pSqlGenerator) + { + pSqlGenerator->onAfterUpdate((&dao), (&item)); + } + qx::dao::on_after_update((&item), (&dao)); + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Update_Ptr + { + + static inline QSqlError update(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns, bool bUseExecBatch) + { + return (t ? qx::dao::update_by_query(query, (*t), pDatabase, columns, bUseExecBatch) : QSqlError()); + } + }; + + template + struct QxDao_Update + { + + static inline QSqlError update(const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase, const QStringList &columns, bool bUseExecBatch = false) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_Ptr, qx::dao::detail::QxDao_Update_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::update(query, t, pDatabase, columns, bUseExecBatch); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Update_Optimized.inl b/inl/QxDao/QxDao_Update_Optimized.inl new file mode 100644 index 0000000..a4e28ad --- /dev/null +++ b/inl/QxDao/QxDao_Update_Optimized.inl @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Update_Optimized_Generic + { + + static inline QSqlError update_optimized(const qx::QxSqlQuery &query, qx::dao::ptr &ptr, QSqlDatabase *pDatabase, bool bUseExecBatch) + { + Q_UNUSED(bUseExecBatch); // Useful only with containers + QStringList lstDiff; + if (ptr.isNull() || !ptr.isDirty(lstDiff)) + { + return QSqlError(); + } + return qx::dao::update_by_query(query, (*ptr), pDatabase, lstDiff); + } + }; + + template + struct QxDao_Update_Optimized_Container + { + + static inline QSqlError update_optimized(const qx::QxSqlQuery &query, qx::dao::ptr &ptr, QSqlDatabase *pDatabase, bool bUseExecBatch) + { + if (ptr.isNull() || (qx::trait::generic_container::size(*ptr) <= 0)) + { + return QSqlError(); + } + if (!ptr.getOriginal() || (qx::trait::generic_container::size(*ptr) != qx::trait::generic_container::size(*ptr.getOriginal()))) + { + return qx::dao::update_by_query(query, (*ptr), pDatabase); + } + + QStringList lstDiffItem; + QSqlError errorItem; + QSqlDatabase db; + bool bCheckDatabaseTransaction = true; + +#ifdef _QX_ENABLE_MONGODB + if (qx::QxSqlDatabase::getSingleton()->getDriverName() == "QXMONGODB") + { + bCheckDatabaseTransaction = false; + } +#endif // _QX_ENABLE_MONGODB + + if (bCheckDatabaseTransaction) + { + db = (pDatabase ? (*pDatabase) : qx::QxSqlDatabase::getDatabase(errorItem)); + if (errorItem.isValid()) + { + return errorItem; + } + if (!pDatabase) + { + db.transaction(); + } + } + + typename T::const_iterator it2 = ptr.getOriginal()->begin(); + for (typename T::const_iterator it1 = ptr->begin(); it1 != ptr->end(); ++it1) + { + lstDiffItem.clear(); + qx::dao::detail::is_dirty((*it1), (*it2), lstDiffItem); + if (lstDiffItem.count() > 0) + { + errorItem = qx::dao::update_by_query(query, (*it1), (&db), lstDiffItem, bUseExecBatch); + } + if (errorItem.isValid()) + { + break; + } + else + { + ++it2; + } + } + + if (bCheckDatabaseTransaction) + { + if (!pDatabase && !errorItem.isValid()) + { + db.commit(); + } + else if (!pDatabase) + { + db.rollback(); + } + } + + return errorItem; + } + }; + + template + struct QxDao_Update_Optimized + { + + static inline QSqlError update_optimized(const qx::QxSqlQuery &query, qx::dao::ptr &ptr, QSqlDatabase *pDatabase, bool bUseExecBatch = false) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_Optimized_Container, qx::dao::detail::QxDao_Update_Optimized_Generic>::type type_dao_1; + + QSqlError error = type_dao_1::update_optimized(query, ptr, pDatabase, bUseExecBatch); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original>::backup(ptr); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxDao_Update_WithRelation.inl b/inl/QxDao/QxDao_Update_WithRelation.inl new file mode 100644 index 0000000..7667dc3 --- /dev/null +++ b/inl/QxDao/QxDao_Update_WithRelation.inl @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxDao_Update_WithRelation_Generic + { + + static QSqlError update(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + qx::dao::detail::QxDao_Helper dao(t, pDatabase, "update with relation", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.isValidPrimaryKey(t)) + { + return dao.errInvalidId(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&t)); + params.setDatabase((&dao.database())); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + dao.updateError(qx::dao::update_by_query(query, t, (&dao.database()))); + if (!dao.isValid()) + { + return dao.error(); + } + + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return dao.error(); + } + + return dao.error(); + } + }; + + template + struct QxDao_Update_WithRelation_Container + { + + static QSqlError update(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + typedef typename qx::trait::generic_container::type_value_qx type_item; + + if (qx::trait::generic_container::size(t) <= 0) + { + return QSqlError(); + } + qx::dao::detail::QxDao_Helper_Container dao(t, pDatabase, "update with relation", new qx::QxSqlQueryBuilder_Update()); + if (!dao.isValid()) + { + return dao.error(); + } + if (dao.isReadOnly()) + { + return dao.errReadOnly(); + } + if (!dao.updateSqlRelationX(relation)) + { + return dao.errInvalidRelation(); + } + if (!pDatabase) + { + dao.transaction(); + } + dao.quiet(); + + for (typename T::iterator it = t.begin(); it != t.end(); ++it) + { + if (!updateItem(query, (*it), dao)) + { + return dao.error(); + } + } + + return dao.error(); + } + + private: + template + static inline bool updateItem(const qx::QxSqlQuery &query, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + bool bUpdateOk = updateItem_Helper < U, std::is_pointer::value || qx::trait::is_smart_ptr::value > ::update(query, item, dao); + if (bUpdateOk) + { + qx::dao::detail::QxDao_Keep_Original::backup(item); + } + return bUpdateOk; + } + + template + struct updateItem_Helper + { + static inline bool update(const qx::QxSqlQuery &query, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return (item ? qx::dao::detail::QxDao_Update_WithRelation_Container::updateItem(query, (*item), dao) : true); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(const qx::QxSqlQuery &query, std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_WithRelation_Container::updateItem(query, item.second, dao); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(const qx::QxSqlQuery &query, const std::pair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_WithRelation_Container::updateItem(query, item.second, dao); + } + }; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + template + struct updateItem_Helper, false> + { + static inline bool update(const qx::QxSqlQuery &query, QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_WithRelation_Container::updateItem(query, item.second, dao); + } + }; + + template + struct updateItem_Helper, false> + { + static inline bool update(const qx::QxSqlQuery &query, const QPair &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + return qx::dao::detail::QxDao_Update_WithRelation_Container::updateItem(query, item.second, dao); + } + }; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + template + struct updateItem_Helper + { + static bool update(const qx::QxSqlQuery &query, U &item, qx::dao::detail::QxDao_Helper_Container &dao) + { + qx::QxSqlRelationParams params(0, 0, NULL, (&dao.builder()), (&dao.query()), (&item)); + params.setDatabase((&dao.database())); + + qx::QxSqlRelationLinked *pRelationLinked = dao.getSqlRelationLinked(); + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnBeforeSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + dao.updateError(qx::dao::update_by_query(query, item, (&dao.database()))); + if (!dao.isValid()) + { + return false; + } + + if (pRelationLinked) + { + dao.updateError(pRelationLinked->hierarchyOnAfterSave(params)); + } + if (!dao.isValid()) + { + return false; + } + + return dao.isValid(); + } + }; + }; + + template + struct QxDao_Update_WithRelation_Ptr + { + + static inline QSqlError update(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + return (t ? qx::dao::update_by_query_with_relation(relation, query, (*t), pDatabase) : QSqlError()); + } + }; + + template + struct QxDao_Update_WithRelation + { + + static inline QSqlError update(const QString &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + QStringList lst; + if (!relation.isEmpty()) + { + lst = relation.split("|"); + } + return QxDao_Update_WithRelation::update(lst, query, t, pDatabase); + } + + static inline QSqlError update(const QStringList &relation, const qx::QxSqlQuery &query, T &t, QSqlDatabase *pDatabase) + { + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_WithRelation_Ptr, qx::dao::detail::QxDao_Update_WithRelation_Generic>::type type_dao_1; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_WithRelation_Ptr, type_dao_1>::type type_dao_2; + typedef typename std::conditional::value, qx::dao::detail::QxDao_Update_WithRelation_Container, type_dao_2>::type type_dao_3; + + QSqlError error = type_dao_3::update(relation, query, t, pDatabase); + if (!error.isValid()) + { + qx::dao::detail::QxDao_Keep_Original::backup(t); + } + return error; + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_CreateTable.inl b/inl/QxDao/QxSqlQueryHelper_CreateTable.inl new file mode 100644 index 0000000..c066bf5 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_CreateTable.inl @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_CreateTable + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_CreateTable(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_DeleteById.inl b/inl/QxDao/QxSqlQueryHelper_DeleteById.inl new file mode 100644 index 0000000..1a3b082 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_DeleteById.inl @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_DeleteById + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder, bool bSoftDelete) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_DeleteById(sql, builder, bSoftDelete); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveInput_DeleteById((&t), query, builder); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_Exist.inl b/inl/QxDao/QxSqlQueryHelper_Exist.inl new file mode 100644 index 0000000..6eb21c3 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_Exist.inl @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_Exist + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_Exist(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + pId->setSqlPlaceHolder(query, (&t)); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_FetchAll.inl b/inl/QxDao/QxSqlQueryHelper_FetchAll.inl new file mode 100644 index 0000000..16e8598 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_FetchAll.inl @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_FetchAll + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_FetchAll(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveOutput_FetchAll((&t), query, builder); + } + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_FetchAll::sql(sql, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_FetchAll(sql, builder, columns); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_FetchAll::resolveInput(t, query, builder); + return; + } + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_FetchAll::resolveOutput(t, query, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveOutput_FetchAll((&t), query, builder, columns); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_FetchAll_WithRelation.inl b/inl/QxDao/QxSqlQueryHelper_FetchAll_WithRelation.inl new file mode 100644 index 0000000..72d5034 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_FetchAll_WithRelation.inl @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_FetchAll_WithRelation + { + + static void sql(qx::QxSqlRelationLinked *pRelationX, QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + if (!pRelationX) + { + qAssert(false); + QxSqlQueryHelper_FetchAll::sql(sql, builder); + return; + } + qx::IxSqlQueryBuilder::sql_FetchAll_WithRelation(pRelationX, sql, builder); + } + + static void resolveInput(qx::QxSqlRelationLinked *pRelationX, T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(pRelationX); + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + + static void resolveOutput(qx::QxSqlRelationLinked *pRelationX, T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + if (!pRelationX) + { + qAssert(false); + QxSqlQueryHelper_FetchAll::resolveOutput(t, query, builder); + return; + } + qx::IxSqlQueryBuilder::resolveOutput_FetchAll_WithRelation(pRelationX, (&t), query, builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_FetchById.inl b/inl/QxDao/QxSqlQueryHelper_FetchById.inl new file mode 100644 index 0000000..1efd288 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_FetchById.inl @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_FetchById + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_FetchById(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + pId->setSqlPlaceHolder(query, (&t)); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + QxSqlQueryHelper_FetchAll::resolveOutput(t, query, builder); + } + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_FetchById::sql(sql, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_FetchById(sql, builder, columns); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_FetchById::resolveInput(t, query, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + pId->setSqlPlaceHolder(query, (&t)); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + QxSqlQueryHelper_FetchAll::resolveOutput(t, query, builder, columns); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_FetchById_WithRelation.inl b/inl/QxDao/QxSqlQueryHelper_FetchById_WithRelation.inl new file mode 100644 index 0000000..f231b58 --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_FetchById_WithRelation.inl @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_FetchById_WithRelation + { + + static void sql(qx::QxSqlRelationLinked *pRelationX, QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + if (!pRelationX) + { + qAssert(false); + QxSqlQueryHelper_FetchById::sql(sql, builder); + return; + } + qx::IxSqlQueryBuilder::sql_FetchById_WithRelation(pRelationX, sql, builder); + } + + static void resolveInput(qx::QxSqlRelationLinked *pRelationX, T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + if (!pRelationX) + { + qAssert(false); + QxSqlQueryHelper_FetchById::resolveInput(t, query, builder); + return; + } + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + pId->setSqlPlaceHolder(query, (&t)); + } + + static void resolveOutput(qx::QxSqlRelationLinked *pRelationX, T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + QxSqlQueryHelper_FetchAll_WithRelation::resolveOutput(pRelationX, t, query, builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_Insert.inl b/inl/QxDao/QxSqlQueryHelper_Insert.inl new file mode 100644 index 0000000..015507c --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_Insert.inl @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_Insert + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_Insert(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveInput_Insert((&t), query, builder); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDao/QxSqlQueryHelper_Update.inl b/inl/QxDao/QxSqlQueryHelper_Update.inl new file mode 100644 index 0000000..c5f2fec --- /dev/null +++ b/inl/QxDao/QxSqlQueryHelper_Update.inl @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + namespace dao + { + namespace detail + { + + template + struct QxSqlQueryHelper_Update + { + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_Update(sql, builder); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveInput_Update((&t), query, builder); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder) + { + Q_UNUSED(t); + Q_UNUSED(query); + Q_UNUSED(builder); + } + + static void sql(QString &sql, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_Update::sql(sql, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::sql_Update(sql, builder, columns); + } + + static void resolveInput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_Update::resolveInput(t, query, builder); + return; + } + static_assert(qx::trait::is_qx_registered::value, "qx::trait::is_qx_registered::value"); + qx::IxSqlQueryBuilder::resolveInput_Update((&t), query, builder, columns); + } + + static void resolveOutput(T &t, QSqlQuery &query, qx::IxSqlQueryBuilder &builder, const QStringList &columns) + { + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + QxSqlQueryHelper_Update::resolveOutput(t, query, builder); + return; + } + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/inl/QxDataMember/QxDataMember.inl b/inl/QxDataMember/QxDataMember.inl new file mode 100644 index 0000000..b9484b7 --- /dev/null +++ b/inl/QxDataMember/QxDataMember.inl @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + +} // namespace qx diff --git a/inl/QxDataMember/QxDataMemberX.inl b/inl/QxDataMember/QxDataMemberX.inl new file mode 100644 index 0000000..6c638ec --- /dev/null +++ b/inl/QxDataMember/QxDataMemberX.inl @@ -0,0 +1,463 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + + template + IxDataMember *QxDataMemberX::initId(IxDataMember *pId, long lVersion) + { + if (!pId) + { + qAssert(false); + return NULL; + } + qAssert(lVersion <= getVersion()); + QString sKey = pId->getKey(); + + pId->setSqlType(qx::trait::get_sql_type::type_primary_key>::get()); + pId->setAutoIncrement(std::is_integral::type_primary_key>::value); + pId->setNameParent(getName()); + pId->setIsPrimaryKey(true); + pId->setNotNull(true); + pId->setVersion(lVersion); + pId->setParent(this); + this->setId(pId); + this->getListDataMemberRef().insert(sKey, pId); + + return pId; + } + + template + IxDataMember *QxDataMemberX::initData(IxDataMember *pData, long lVersion) + { + if (!pData) + { + qAssert(false); + return NULL; + } + qAssert(lVersion <= getVersion()); + QString sKey = pData->getKey(); + + pData->setVersion(lVersion); + pData->setNameParent(getName()); + pData->setParent(this); + this->getListDataMemberRef().insert(sKey, pData); + + return pData; + } + + template + IxDataMember *QxDataMemberX::initPImpl(IxDataMember *pImpl) + { + if (!pImpl) + { + qAssert(false); + return NULL; + } + QString sKey = pImpl->getKey(); + if (this->getListPImplRef().exist(sKey)) + { + qAssert(false); + return NULL; + } + + pImpl->setNameParent(getName()); + pImpl->setParent(this); + this->getListPImplRef().insert(sKey, pImpl); + + return pImpl; + } + + template + template + IxDataMember *QxDataMemberX::add(V U::*pData, const QString &sKey, long lVersion /* = 0 */, bool bSerialize /* = true */, bool bDao /* = true */) + { + typedef std::is_base_of is_valid_class_tmp; + static_assert(is_valid_class_tmp::value, "is_valid_class_tmp::value"); + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pNewDataMember = new QxDataMember(pData, sKey, lVersion, bSerialize, bDao); + pNewDataMember->setSqlType(qx::trait::get_sql_type::get()); + return this->initData(pNewDataMember, lVersion); + } + + template + IxDataMember *QxDataMemberX::add(const QString &sKey, long lVersion) + { + if (!qx::trait::qt_meta_object::is_valid) + { + qDebug("[QxOrm] qx::QxDataMemberX::add() : '%s'", "Qt introspection engine works only with QObject class"); + qAssert(false); + return NULL; + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + return this->initData(new QxDataMember_QObject(qx::trait::qt_meta_object::get(), sKey), lVersion); + } + + template + IxDataMember *QxDataMemberX::id(typename QxDataMemberX::type_primary_key T::*pDataMemberId, const QString &sKey, long lVersion /* = 0 */) + { + if (getId_WithDaoStrategy()) + { + qDebug("[QxOrm] qx::QxDataMemberX id (primary key) already defined '%s'", qPrintable(getId_WithDaoStrategy()->getName())); + } + if (exist_WithDaoStrategy(sKey) || getId_WithDaoStrategy()) + { + qAssert(false); + return getId_WithDaoStrategy(); + } + return this->initId(new QxDataMember::type_primary_key, T>(pDataMemberId, sKey, lVersion, true, true), lVersion); + } + + template + IxDataMember *QxDataMemberX::id(const QString &sKey, long lVersion) + { + if (!qx::trait::qt_meta_object::is_valid) + { + qDebug("[QxOrm] qx::QxDataMemberX::id() : '%s'", "Qt introspection engine works only with QObject class"); + qAssert(false); + return NULL; + } + if (getId_WithDaoStrategy()) + { + qDebug("[QxOrm] qx::QxDataMemberX id (primary key) already defined '%s'", qPrintable(getId_WithDaoStrategy()->getName())); + } + if (exist_WithDaoStrategy(sKey) || getId_WithDaoStrategy()) + { + qAssert(false); + return getId_WithDaoStrategy(); + } + return this->initId(new QxDataMember_QObject(qx::trait::qt_meta_object::get(), sKey), lVersion); + } + + template + template + IxSqlRelation *QxDataMemberX::relationOneToOne(V U::*pData, const QString &sKey, long lVersion /* = 0 */) + { + typedef std::is_base_of is_valid_class_tmp; + static_assert(is_valid_class_tmp::value, "is_valid_class_tmp::value"); + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion); + IxSqlRelation *pSqlRelation = new QxSqlRelation_OneToOne(pDataMember); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationManyToOne(V U::*pData, const QString &sKey, long lVersion /* = 0 */) + { + typedef std::is_base_of is_valid_class_tmp; + static_assert(is_valid_class_tmp::value, "is_valid_class_tmp::value"); + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion); + IxSqlRelation *pSqlRelation = new QxSqlRelation_ManyToOne(pDataMember); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion /* = 0 */) + { + typedef std::is_base_of is_valid_class_tmp; + static_assert(is_valid_class_tmp::value, "is_valid_class_tmp::value"); + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion); + IxSqlRelation *pSqlRelation = new QxSqlRelation_OneToMany(pDataMember, sForeignKey); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion /* = 0 */) + { + typedef std::is_base_of is_valid_class_tmp; + static_assert(is_valid_class_tmp::value, "is_valid_class_tmp::value"); + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion); + IxSqlRelation *pSqlRelation = new QxSqlRelation_ManyToMany(pDataMember, sExtraTable, sForeignKeyOwner, sForeignKeyDataType); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxDataMember *QxDataMemberX::pimpl(V U::*pData, const QString &sKey) + { + IxDataMember *pNewDataMember = new QxDataMember_PImpl(pData, sKey); + return this->initPImpl(pNewDataMember); + } + + template + template + IxDataMember *QxDataMemberX::id(typename QxDataMemberX::type_primary_key U::*pDataMemberId, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (getId_WithDaoStrategy()) + { + qDebug("[QxOrm] qx::QxDataMemberX id (primary key) already defined '%s'", qPrintable(getId_WithDaoStrategy()->getName())); + } + if (exist_WithDaoStrategy(sKey) || getId_WithDaoStrategy()) + { + qAssert(false); + return getId_WithDaoStrategy(); + } + return this->initId(new QxDataMember::type_primary_key, U>(pDataMemberId, sKey, lVersion, true, true, pImpl), lVersion); + } + + template + template + IxDataMember *QxDataMemberX::add(V U::*pData, const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pNewDataMember = new QxDataMember(pData, sKey, lVersion, bSerialize, bDao, pImpl); + pNewDataMember->setSqlType(qx::trait::get_sql_type::get()); + return this->initData(pNewDataMember, lVersion); + } + + template + template + IxSqlRelation *QxDataMemberX::relationOneToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion, true, true, pImpl); + IxSqlRelation *pSqlRelation = new QxSqlRelation_OneToOne(pDataMember); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationManyToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion, true, true, pImpl); + IxSqlRelation *pSqlRelation = new QxSqlRelation_ManyToOne(pDataMember); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion, true, true, pImpl); + IxSqlRelation *pSqlRelation = new QxSqlRelation_OneToMany(pDataMember, sForeignKey); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + + template + template + IxSqlRelation *QxDataMemberX::relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion, IxDataMember *pImpl) + { + if (pImpl) + { + qAssert((pImpl->getParent()) && (pImpl->getParent()->getClass() == this->getClass())); + } + if (exist_WithDaoStrategy(sKey)) + { + qAssert(false); + return NULL; + } + + IxDataMember *pDataMember = this->add(pData, sKey, lVersion, true, true, pImpl); + IxSqlRelation *pSqlRelation = new QxSqlRelation_ManyToMany(pDataMember, sExtraTable, sForeignKeyOwner, sForeignKeyDataType); + pDataMember->setSqlRelation(pSqlRelation); + + return pSqlRelation; + } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + + template + template + inline void QxDataMemberX::toArchive(const T *pOwner, Archive &ar, const unsigned int file_version) const + { + Q_UNUSED(file_version); + const QxCollection &lstDataMember = this->getListDataMemberRef(); + _foreach_if(IxDataMember * pDataMember, lstDataMember, (pDataMember->getSerialize())) + pDataMember->toArchive(pOwner, ar); + } + + template + template + inline void QxDataMemberX::fromArchive(T *pOwner, Archive &ar, const unsigned int file_version) + { + Q_UNUSED(file_version); + QxCollection &lstDataMember = this->getListDataMemberRef(); + _foreach_if(IxDataMember * pDataMember, lstDataMember, (pDataMember->getSerialize() && (pDataMember->getVersion() <= static_cast(file_version)))) + pDataMember->fromArchive(pOwner, ar); + } + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE + QxDataMemberX::QxDataMemberX() : IxDataMemberX(), QxSingleton>("qx::QxDataMemberX_no_base_class_defined") { ; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE + QxDataMemberX::QxDataMemberX() : IxDataMemberX(), QxSingleton>("qx::QxDataMemberX_QObject") { ; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE long QxDataMemberX::count_WithDaoStrategy_Helper() const { return 0; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE bool QxDataMemberX::exist_WithDaoStrategy_Helper(const QString &sKey) const + { + Q_UNUSED(sKey); + return false; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::get_WithDaoStrategy_Helper(long lIndex) const + { + Q_UNUSED(lIndex); + return NULL; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::get_WithDaoStrategy_Helper(const QString &sKey) const + { + Q_UNUSED(sKey); + return NULL; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::getId_WithDaoStrategy_Helper() const { return NULL; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE long QxDataMemberX::count_WithDaoStrategy_Helper() const { return 0; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE bool QxDataMemberX::exist_WithDaoStrategy_Helper(const QString &sKey) const + { + Q_UNUSED(sKey); + return false; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::get_WithDaoStrategy_Helper(long lIndex) const + { + Q_UNUSED(lIndex); + return NULL; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::get_WithDaoStrategy_Helper(const QString &sKey) const + { + Q_UNUSED(sKey); + return NULL; + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE IxDataMember *QxDataMemberX::getId_WithDaoStrategy_Helper() const { return NULL; } + +} // namespace qx diff --git a/inl/QxFactory/QxFactory.inl b/inl/QxFactory/QxFactory.inl new file mode 100644 index 0000000..0ae7c67 --- /dev/null +++ b/inl/QxFactory/QxFactory.inl @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4094) +#endif // _MSC_VER + +#include + +#ifndef QX_REGISTER_FACTORY_HPP +#define QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_HPP(className, classNameFormatted) \ + extern qx::QxFactory G_QX_REGISTER_FACTORY_##classNameFormatted; +#define QX_REGISTER_FACTORY_HPP(className) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_HPP(className, className) +#endif // QX_REGISTER_FACTORY_HPP + +#ifndef QX_REGISTER_FACTORY_CPP +#define QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_CPP(className, classNameFormatted) \ + qx::QxFactory G_QX_REGISTER_FACTORY_##classNameFormatted(QString(#className)); +#define QX_REGISTER_FACTORY_CPP(className) \ + QX_REGISTER_FACTORY_COMPLEX_CLASS_NAME_CPP(className, className) +#endif // QX_REGISTER_FACTORY_CPP + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER diff --git a/inl/QxRegister/QxClass.inl b/inl/QxRegister/QxClass.inl new file mode 100644 index 0000000..4c85f1c --- /dev/null +++ b/inl/QxRegister/QxClass.inl @@ -0,0 +1,361 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +namespace qx +{ + + template + void QxClass::init() + { + this->setDataMemberX(QxDataMemberX::getSingleton()); + this->getDataMemberX()->setClass(this); + this->setFctMemberX(new IxFunctionX()); + this->setFctStaticX(new IxFunctionX()); + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + this->setVersion(boost::serialization::version::value); +#else // _QX_ENABLE_BOOST_SERIALIZATION + this->setVersion(qx::version::value); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + this->setKey(qx::trait::get_class_name::get()); + this->setDaoStrategy(QxClass::type_base_class>::getSingleton()->getDaoStrategy()); + this->setName(qx::trait::get_class_name::get_xml_tag()); + this->updateClassX(); + beforeRegisterClass(); + } + + template + IxDataMember *QxClass::data(const QString &sKey, long lVersion) + { + return this->dataMemberX()->add(sKey, lVersion); + } + + template + template + IxDataMember *QxClass::data(V U::*pData, const QString &sKey, long lVersion /* = 0 */, bool bSerialize /* = true */, bool bDao /* = true */) + { + return this->dataMemberX()->add(pData, sKey, lVersion, bSerialize, bDao); + } + + template + IxDataMember *QxClass::id(const QString &sKey, long lVersion) + { + return this->dataMemberX()->id(sKey, lVersion); + } + + template + IxDataMember *QxClass::id(typename QxClass::type_primary_key T::*pDataMemberId, const QString &sKey, long lVersion /* = 0 */) + { + return this->dataMemberX()->id(pDataMemberId, sKey, lVersion); + } + + template + template + IxSqlRelation *QxClass::relationOneToOne(V U::*pData, const QString &sKey, long lVersion /* = 0 */) + { + return this->dataMemberX()->relationOneToOne(pData, sKey, lVersion); + } + + template + template + IxSqlRelation *QxClass::relationManyToOne(V U::*pData, const QString &sKey, long lVersion /* = 0 */) + { + return this->dataMemberX()->relationManyToOne(pData, sKey, lVersion); + } + + template + template + IxSqlRelation *QxClass::relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion /* = 0 */) + { + return this->dataMemberX()->relationOneToMany(pData, sKey, sForeignKey, lVersion); + } + + template + template + IxSqlRelation *QxClass::relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion /* = 0 */) + { + return this->dataMemberX()->relationManyToMany(pData, sKey, sExtraTable, sForeignKeyOwner, sForeignKeyDataType, lVersion); + } + + template + template + IxDataMember *QxClass::pimpl(V U::*pData, const QString &sKey /* = QString("_PIMPL_") */) + { + return this->dataMemberX()->pimpl(pData, sKey); + } + + template + template + IxDataMember *QxClass::id(typename QxClass::type_primary_key U::*pDataMemberId, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + return this->dataMemberX()->id(pDataMemberId, sKey, lVersion, pImpl); + } + + template + template + IxDataMember *QxClass::data(V U::*pData, const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl) + { + return this->dataMemberX()->add(pData, sKey, lVersion, bSerialize, bDao, pImpl); + } + + template + template + IxSqlRelation *QxClass::relationOneToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + return this->dataMemberX()->relationOneToOne(pData, sKey, lVersion, pImpl); + } + + template + template + IxSqlRelation *QxClass::relationManyToOne(V U::*pData, const QString &sKey, long lVersion, IxDataMember *pImpl) + { + return this->dataMemberX()->relationManyToOne(pData, sKey, lVersion, pImpl); + } + + template + template + IxSqlRelation *QxClass::relationOneToMany(V U::*pData, const QString &sKey, const QString &sForeignKey, long lVersion, IxDataMember *pImpl) + { + return this->dataMemberX()->relationOneToMany(pData, sKey, sForeignKey, lVersion, pImpl); + } + + template + template + IxSqlRelation *QxClass::relationManyToMany(V U::*pData, const QString &sKey, const QString &sExtraTable, const QString &sForeignKeyOwner, const QString &sForeignKeyDataType, long lVersion, IxDataMember *pImpl) + { + return this->dataMemberX()->relationManyToMany(pData, sKey, sExtraTable, sForeignKeyOwner, sForeignKeyDataType, lVersion, pImpl); + } + + template + IxFunction *QxClass::insertFct(IxFunction_ptr pFct, const QString &sKey) + { + if (!this->getFctMemberX() || sKey.isEmpty() || this->getFctMemberX()->exist(sKey)) + { + qAssert(false); + return NULL; + } + bool bInsertOk = this->getFctMemberX()->insert(sKey, pFct); + if (bInsertOk) + { + pFct->setKey(sKey); + } + return (bInsertOk ? pFct.get() : NULL); + } + + template + IxFunction *QxClass::insertFctStatic(IxFunction_ptr pFct, const QString &sKey) + { + if (!this->getFctStaticX() || sKey.isEmpty() || this->getFctStaticX()->exist(sKey)) + { + qAssert(false); + return NULL; + } + bool bInsertOk = this->getFctStaticX()->insert(sKey, pFct); + if (bInsertOk) + { + pFct->setKey(sKey); + } + return (bInsertOk ? pFct.get() : NULL); + } + + template + template + IxFunction *QxClass::fct_0(const typename QxFunction_0::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_0(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_1(const typename QxFunction_1::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_1(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_2(const typename QxFunction_2::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_2(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_3(const typename QxFunction_3::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_3(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_4(const typename QxFunction_4::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_4(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_5(const typename QxFunction_5::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_5(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_6(const typename QxFunction_6::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_6(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_7(const typename QxFunction_7::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_7(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_8(const typename QxFunction_8::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_8(fct), sKey); + } + + template + template + IxFunction *QxClass::fct_9(const typename QxFunction_9::type_fct &fct, const QString &sKey) + { + return this->insertFct(qx::function::bind_member_fct_9(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_0(const typename QxFunction_0::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_0(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_1(const typename QxFunction_1::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_1(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_2(const typename QxFunction_2::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_2(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_3(const typename QxFunction_3::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_3(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_4(const typename QxFunction_4::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_4(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_5(const typename QxFunction_5::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_5(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_6(const typename QxFunction_6::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_6(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_7(const typename QxFunction_7::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_7(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_8(const typename QxFunction_8::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_8(fct), sKey); + } + + template + template + IxFunction *QxClass::fctStatic_9(const typename QxFunction_9::type_fct &fct, const QString &sKey) + { + return this->insertFctStatic(qx::function::bind_fct_9(fct), sKey); + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE + QxClass::QxClass() : IxClass(), QxSingleton>("qx::QxClass_no_base_class_defined") + { + setName("qx::trait::no_base_class_defined"); + setFinalClass(true); + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE + QxClass::QxClass() : IxClass(), QxSingleton>("qx::QxClass_QObject") + { + setKey("QObject"); + setName("QObject"); + setFinalClass(true); + } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE void QxClass::registerClass() { ; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE void QxClass::registerClass() { ; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE void QxClass::beforeRegisterClass() { ; } + + template <> + QX_GCC_WORKAROUND_TEMPLATE_SPEC_INLINE void QxClass::beforeRegisterClass() { ; } + +} // namespace qx diff --git a/inl/QxSerialize/QxArchive.inl b/inl/QxSerialize/QxArchive.inl new file mode 100644 index 0000000..cb5a529 --- /dev/null +++ b/inl/QxSerialize/QxArchive.inl @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace qx +{ + + template + qx_bool QxArchive_ToFile::toFile(const T &obj, const QString &sFileName, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_ofstream qx_type_ofstream; + qx_type_ofstream ofile(qPrintable(sFileName), (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc)); + if (!ofile.is_open()) + { + return qx_bool(false, 0, QString("Cannot create or open file '") + sFileName + QString("'")); + } + ArchiveOutput oar(ofile, flags); + qx_bool bSerializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(oar); + + try + { + oar << boost::serialization::make_nvp(sTag, obj); + bSerializeOk = ofile.good(); + } + catch (const boost::archive::archive_exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + ofile.close(); + if (!bSerializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_ToFile::toFile() -> ") + bSerializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bSerializeOk); + + return bSerializeOk; + } + + template + qx_bool QxArchive_FromFile::fromFile(T &obj, const QString &sFileName, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_ifstream qx_type_ifstream; + qx_type_ifstream ifile(qPrintable(sFileName), (std::ios_base::binary | std::ios_base::in)); + if (!ifile.is_open()) + { + return qx_bool(false, 0, QString("Cannot open file '") + sFileName + QString("'")); + } + ArchiveInput iar(ifile, flags); + qx_bool bDeserializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(iar); + + try + { + iar >> boost::serialization::make_nvp(sTag, obj); + bDeserializeOk = true; + } + catch (const boost::archive::archive_exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + ifile.close(); + if (!bDeserializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_FromFile::fromFile() -> ") + bDeserializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bDeserializeOk); + + return bDeserializeOk; + } + + template + qx_bool QxArchive_ToFileCompressed::toFileCompressed(const T &obj, const QString &sFileName, unsigned int flags /* = boost::archive::no_header */, int iCompressionLevel /* = -1 */) + { + typedef typename qx::trait::archive_wide_traits::type_ostringstream qx_type_ostringstream; + qx_type_ostringstream oss(std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + ArchiveOutput oar(oss, flags); + qx_bool bSerializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(oar); + + try + { + oar << boost::serialization::make_nvp(sTag, obj); + bSerializeOk = oss.good(); + } + catch (const boost::archive::archive_exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + qAssert(bSerializeOk); + if (!bSerializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_ToFileCompressed::toFileCompressed() -> ") + bSerializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + if (!bSerializeOk) + { + return false; + } + + oss.seekp(0, std::ios::end); + QByteArray compressed = qCompress((unsigned char *)(oss.str().c_str()), static_cast(oss.tellp()), iCompressionLevel); + if (compressed.isEmpty()) + { + qAssert(false); + return qx_bool(false, 0, QString("Cannot compress archive")); + } + + typedef typename qx::trait::archive_wide_traits::type_ofstream qx_type_ofstream; + qx_type_ofstream ofile(qPrintable(sFileName), (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc)); + if (!ofile.is_open()) + { + return qx_bool(false, 0, QString("Cannot create or open compressed file '") + sFileName + QString("'")); + } + ofile.write(compressed.constData(), compressed.size()); + ofile.close(); + + return true; + } + + template + qx_bool QxArchive_FromFileCompressed::fromFileCompressed(T &obj, const QString &sFileName, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_ifstream qx_type_ifstream; + typedef typename qx::trait::archive_wide_traits::type_char qx_type_char; + typedef typename qx::trait::archive_wide_traits::type_string qx_type_string; + typedef typename qx::trait::archive_wide_traits::type_istringstream qx_type_istringstream; + + qx_type_ifstream ifile(qPrintable(sFileName), (std::ios_base::binary | std::ios_base::in)); + if (!ifile.is_open()) + { + return qx_bool(false, 0, QString("Cannot open compressed file '") + sFileName + QString("'")); + } + ifile.seekg(0, std::ios::end); + int iSize = ifile.tellg(); + ifile.seekg(0, std::ios::beg); + qx_type_char *buffer = new qx_type_char[iSize]; + ifile.read(buffer, iSize); + ifile.close(); + + QByteArray uncompressed = qUncompress((unsigned char *)(buffer), iSize); + if (uncompressed.isEmpty()) + { + delete[] buffer; + qAssert(false); + return qx_bool(false, 0, QString("Cannot uncompress archive")); + } + delete[] buffer; + + qx_type_string str(uncompressed.constData(), uncompressed.count()); + qx_type_istringstream iss(str, (std::ios_base::binary | std::ios_base::in)); + ArchiveInput iar(iss, flags); + qx_bool bDeserializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(iar); + + try + { + iar >> boost::serialization::make_nvp(sTag, obj); + bDeserializeOk = true; + } + catch (const boost::archive::archive_exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + if (!bDeserializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_FromFileCompressed::fromFileCompressed() -> ") + bDeserializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bDeserializeOk); + + return bDeserializeOk; + } + + template + QString QxArchive_ToString::toString(const T &obj, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_ostringstream qx_type_ostringstream; + qx_type_ostringstream oss(std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + ArchiveOutput oar(oss, flags); + qx_bool bSerializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(oar); + + try + { + oar << boost::serialization::make_nvp(sTag, obj); + bSerializeOk = oss.good(); + } + catch (const boost::archive::archive_exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + if (!bSerializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_ToString::toString() -> ") + bSerializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bSerializeOk); + + return (bSerializeOk ? qx::trait::archive_wide_traits::toQString(oss.str()) : QString()); + } + + template + qx_bool QxArchive_FromString::fromString(T &obj, const QString &sString, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_string qx_type_string; + typedef typename qx::trait::archive_wide_traits::type_istringstream qx_type_istringstream; + + qx_type_string str; + if (sString.isEmpty()) + { + return false; + } + qx::trait::archive_wide_traits::fromQString(sString, str); + qx_type_istringstream iss(str, (std::ios_base::binary | std::ios_base::in)); + ArchiveInput iar(iss, flags); + qx_bool bDeserializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(iar); + + try + { + iar >> boost::serialization::make_nvp(sTag, obj); + bDeserializeOk = true; + } + catch (const boost::archive::archive_exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + if (!bDeserializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_FromString::fromString() -> ") + bDeserializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bDeserializeOk); + + return bDeserializeOk; + } + + template + QByteArray QxArchive_ToByteArray::toByteArray(const T &obj, type_string *owner /* = NULL */, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_ostringstream qx_type_ostringstream; + qx_type_ostringstream oss(std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + ArchiveOutput oar(oss, flags); + qx_bool bSerializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(oar); + + try + { + oar << boost::serialization::make_nvp(sTag, obj); + bSerializeOk = oss.good(); + } + catch (const boost::archive::archive_exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bSerializeOk.setDesc(QString(QX_STR_SERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + if (!bSerializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_ToByteArray::toByteArray() -> ") + bSerializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bSerializeOk); + + return (bSerializeOk ? qx::trait::archive_wide_traits::toQByteArray(oss.str(), owner) : QByteArray()); + } + + template + qx_bool QxArchive_FromByteArray::fromByteArray(T &obj, const QByteArray &data, unsigned int flags /* = boost::archive::no_header */) + { + typedef typename qx::trait::archive_wide_traits::type_string qx_type_string; + typedef typename qx::trait::archive_wide_traits::type_istringstream qx_type_istringstream; + + qx_type_string str; + if (data.size() <= 0) + { + return false; + } + qx::trait::archive_wide_traits::fromQByteArray(data, str); + qx_type_istringstream iss(str, (std::ios_base::binary | std::ios_base::in)); + ArchiveInput iar(iss, flags); + qx_bool bDeserializeOk = false; + const char *sTag = QxClassName::get_xml_tag(); + QxBoostSerializeRegisterHelperX::helper(iar); + + try + { + iar >> boost::serialization::make_nvp(sTag, obj); + bDeserializeOk = true; + } + catch (const boost::archive::archive_exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (const std::exception &e) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", e.what())); + } + catch (...) + { + bDeserializeOk.setDesc(QString(QX_STR_DESERIALIZATION_ERROR).replace("%ERR%", "unknown error")); + } + + if (!bDeserializeOk.getDesc().isEmpty()) + { + QString sMsg = QString("qx::QxArchive_FromByteArray::fromByteArray() -> ") + bDeserializeOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + qAssert(bDeserializeOk); + + return bDeserializeOk; + } + +} // namespace qx + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/inl/QxSerialize/QxSerializeInvoker.inl b/inl/QxSerialize/QxSerializeInvoker.inl new file mode 100644 index 0000000..ce97208 --- /dev/null +++ b/inl/QxSerialize/QxSerializeInvoker.inl @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace boost +{ + namespace serialization + { + + template + inline void serialize(Archive &ar, qx::trait::no_base_class_defined &t, const unsigned int file_version) + { + Q_UNUSED(ar); + Q_UNUSED(t); + Q_UNUSED(file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/inl/QxSingleton/QxSingleton.inl b/inl/QxSingleton/QxSingleton.inl new file mode 100644 index 0000000..67db5f6 --- /dev/null +++ b/inl/QxSingleton/QxSingleton.inl @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +namespace qx +{ + + template + T *QxSingleton::m_pSingleton = NULL; + template + QMutex QxSingleton::m_oMutexSingleton; + + template + T *QxSingleton::getSingleton() + { + if (m_pSingleton) + return m_pSingleton; + + IxSingleton::initQxSingletonX(); + QMutexLocker locker(QCoreApplication::instance() ? (&m_oMutexSingleton) : NULL); + if (!m_pSingleton) + { + m_pSingleton = new T(); + } + + return m_pSingleton; + } + + template + void QxSingleton::deleteSingleton() + { + QMutexLocker locker(QCoreApplication::instance() ? (&m_oMutexSingleton) : NULL); + if (!m_pSingleton) + { + return; + } + + delete m_pSingleton; + m_pSingleton = NULL; + } + +} // namespace qx diff --git a/inl/QxXml/QxXml.inl b/inl/QxXml/QxXml.inl new file mode 100644 index 0000000..1353d84 --- /dev/null +++ b/inl/QxXml/QxXml.inl @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +template +QString QxXml::toXml(T *pOwner) +{ + if (!pOwner) + { + return ""; + } + + QxXmlWriter xmlWriter; + QxDataMemberX::toXml(pOwner, &xmlWriter); + + return xmlWriter.getXml(); +} + +template +bool QxXml::fromXml(T *pOwner, const QString &sXml) +{ + if (!pOwner || sXml.isEmpty()) + { + return false; + } + + QxXmlReader xmlReader(sXml); + QxDataMemberX::fromXml(pOwner, &xmlReader); + + return true; +} + +template +std::shared_ptr QxXml::toXmlWriter(T *pOwner) +{ + if (!pOwner) + { + return std::shared_ptr(); + } + + std::shared_ptr pXmlWriter; + pXmlWriter.reset(new QxXmlWriter()); + QxDataMemberX::toXml(pOwner, pXmlWriter.get()); + + return pXmlWriter; +} + +template +bool QxXml::fromXmlReader(T *pOwner, QxXmlReader *pXmlReader) +{ + if (!pOwner || !pXmlReader) + { + return false; + } + QxDataMemberX::fromXml(pOwner, pXmlReader); + + return true; +} diff --git a/install-deps-debug.bat b/install-deps-debug.bat new file mode 100644 index 0000000..fb99ae4 --- /dev/null +++ b/install-deps-debug.bat @@ -0,0 +1,13 @@ +@echo off +echo ======================================== +echo Installing Debug dependencies +echo ======================================== +conan install . --build=missing -s build_type=Debug +if %errorlevel% neq 0 ( + echo. + echo [ERROR] Conan install failed! + exit /b %errorlevel% +) +echo. +echo [SUCCESS] Debug dependencies installed! +echo. diff --git a/install-deps-release.bat b/install-deps-release.bat new file mode 100644 index 0000000..30fc345 --- /dev/null +++ b/install-deps-release.bat @@ -0,0 +1,13 @@ +@echo off +echo ======================================== +echo Installing Release dependencies +echo ======================================== +conan install . --build=missing -s build_type=Release +if %errorlevel% neq 0 ( + echo. + echo [ERROR] Conan install failed! + exit /b %errorlevel% +) +echo. +echo [SUCCESS] Release dependencies installed! +echo. diff --git a/qt/moc/.gitignore b/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/qt/rcc/src/.gitignore b/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/qt/ui/include/.gitignore b/qt/ui/include/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/qt/ui/include/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/qt/ui/src/.gitignore b/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/src/QxCollection/QxCollection.cpp b/src/QxCollection/QxCollection.cpp new file mode 100644 index 0000000..ccb0205 --- /dev/null +++ b/src/QxCollection/QxCollection.cpp @@ -0,0 +1,93 @@ + +#include + +#include +#include +#include + +namespace qx +{ + + IxCollection::~IxCollection() = default; + + namespace unit_test + { + + // Compilation option '_QX_HASH_NO_STD_NAMESPACE' + // Try to avoid compilation error, something like : error: no matching function for call to 'qHash(const std::tuple<...>&)' + // This is due to C++ ADL to resolve specialized functions : qHash(T) should be implemented in the same namespace as T + // For 'std' classes, it should be NOT allowed : the behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std + // More details here : https://www.kdab.com/how-to-declare-a-qhash-overload/ + // And here : https://stackoverflow.com/questions/47460098/using-standard-library-types-as-keys-in-qhash-or-qset + void qx_collection_unit_test() + { + // Test basic functionality with simple types + { + QxCollection coll; + QxCollectionIterator itr(coll); + coll.sortByKey(); + coll.sortByValue(); + itr.toFirst(); + } + + // Test with std::tuple as key + { + using type_std_tuple = std::tuple; + QxCollection> coll; + coll.begin(); + coll.reserve(10); + coll.clear(); + coll.count(); + coll.empty(); + + type_std_tuple item = std::make_tuple(QString(), std::string(), 1); + coll.contains(item); + } + + // Test with std::pair as key + { + using type_std_pair = std::pair; + QxCollection> coll; + coll.begin(); + coll.reserve(10); + coll.clear(); + coll.count(); + coll.empty(); + + type_std_pair item = std::make_pair(QString(), std::string("1")); + coll.contains(item); + } + + // Test with QPair as key + { + using type_qt_pair = QPair; + QxCollection> coll; + coll.begin(); + coll.reserve(10); + coll.clear(); + coll.count(); + coll.empty(); + + type_qt_pair item = qMakePair(QDateTime(), std::string("1")); + coll.contains(item); + } + +#ifdef _QX_ENABLE_BOOST + // Test with boost::tuple as key + { + using type_boost_tuple = boost::tuple; + QxCollection> coll; + coll.begin(); + coll.reserve(10); + coll.clear(); + coll.count(); + coll.empty(); + + type_boost_tuple item = boost::make_tuple(QString(), std::string(), 1); + coll.contains(item); + } +#endif // _QX_ENABLE_BOOST + } + + } // namespace unit_test +} // namespace qx diff --git a/src/QxCommon/QxBool.cpp b/src/QxCommon/QxBool.cpp new file mode 100644 index 0000000..9978815 --- /dev/null +++ b/src/QxCommon/QxBool.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const qx::QxBool &t) +{ + stream << t.m_bValue; + stream << t.m_lCode; + stream << t.m_sDesc; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxBool &t) +{ + stream >> t.m_bValue; + stream >> t.m_lCode; + stream >> t.m_sDesc; + return stream; +} diff --git a/src/QxCommon/QxCache.cpp b/src/QxCommon/QxCache.cpp new file mode 100644 index 0000000..1d29fc2 --- /dev/null +++ b/src/QxCommon/QxCache.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::cache::detail::QxCache) + +namespace qx +{ + namespace cache + { + namespace detail + { + + QxCache::QxCache() : qx::QxSingleton("qx::cache::detail::QxCache"), m_lMaxCost(999999999), m_lCurrCost(0) { ; } + + QxCache::~QxCache() { ; } + + long QxCache::getCurrCost() const { return m_lCurrCost; } + + long QxCache::getMaxCost() const { return m_lMaxCost; } + + long QxCache::count() const { return m_cache.count(); } + + long QxCache::size() const { return this->count(); } + + bool QxCache::isEmpty() const { return (this->count() == 0); } + + bool QxCache::exist(const QString &sKey) const { return m_cache.exist(sKey); } + + bool QxCache::contains(const QString &sKey) const { return this->exist(sKey); } + + void QxCache::setMaxCost(long l) + { + QMutexLocker locker(&m_oMutexCache); + m_lMaxCost = ((l < 0) ? 0 : l); + updateCost(); + } + + qx::any QxCache::at(const QString &sKey) + { + QMutexLocker locker(&m_oMutexCache); + if (!this->exist(sKey)) + { + return qx::any(); + } + return std::get<2>(m_cache.getByKey(sKey)); + } + + long QxCache::insertionCost(const QString &sKey) + { + QMutexLocker locker(&m_oMutexCache); + if (!this->exist(sKey)) + { + return -1; + } + return std::get<0>(m_cache.getByKey(sKey)); + } + + QDateTime QxCache::insertionDateTime(const QString &sKey) + { + QMutexLocker locker(&m_oMutexCache); + if (!this->exist(sKey)) + { + return QDateTime(); + } + return std::get<1>(m_cache.getByKey(sKey)); + } + + void QxCache::clear() + { + QMutexLocker locker(&m_oMutexCache); + m_cache.clear(); + m_lCurrCost = 0; + } + + bool QxCache::insert(const QString &sKey, const qx::any &anyObj, long lCost /* = 1 */, const QDateTime &dt /* = QDateTime() */) + { + if (sKey.isEmpty()) + { + qAssert(false); + return false; + } + this->remove(sKey); + + QMutexLocker locker(&m_oMutexCache); + lCost = ((lCost < 0) ? 0 : lCost); + QDateTime dtTemp(dt); + if (!dtTemp.isValid()) + { + dtTemp = QDateTime::currentDateTime(); + } + QxCache::type_qx_cache item = std::make_tuple(lCost, dtTemp, anyObj); + bool bInsertOk = m_cache.insert(sKey, item); + if (bInsertOk) + { + m_lCurrCost += lCost; + updateCost(); + } + + return bInsertOk; + } + + bool QxCache::remove(const QString &sKey) + { + QMutexLocker locker(&m_oMutexCache); + if (!this->exist(sKey)) + { + return false; + } + long lCost = std::get<0>(m_cache.getByKey(sKey)); + bool bRemoveOk = m_cache.removeByKey(sKey); + if (bRemoveOk) + { + m_lCurrCost -= lCost; + } + + return bRemoveOk; + } + + void QxCache::updateCost() + { + while ((m_lCurrCost > m_lMaxCost) && (m_cache.count() > 0)) + { + QString sKey = m_cache.getKeyByIndex(0); + long lCost = std::get<0>(m_cache.getByIndex(0)); + m_cache.removeByIndex(0); + m_lCurrCost -= lCost; + QString sMsg = QString("qx::cache : auto remove object in cache '") + sKey + QString("'"); + qDebug("[QxOrm] %s", qPrintable(sMsg)); + } + } + + } // namespace detail + } // namespace cache +} // namespace qx diff --git a/src/QxCommon/QxSimpleCrypt.cpp b/src/QxCommon/QxSimpleCrypt.cpp new file mode 100644 index 0000000..249f45e --- /dev/null +++ b/src/QxCommon/QxSimpleCrypt.cpp @@ -0,0 +1,254 @@ +#include + +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + +#include + +#include + +namespace qx +{ + + QxSimpleCrypt::QxSimpleCrypt() : m_key(0), + m_compressionMode(CompressionAuto), + m_protectionMode(ProtectionChecksum), + m_lastError(ErrorNoError) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + qsrand(uint((qint64)(QDateTime::currentDateTime().toTime_t()) & 0xFFFF)); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + } + + QxSimpleCrypt::QxSimpleCrypt(quint64 key) : m_key(key), + m_compressionMode(CompressionAuto), + m_protectionMode(ProtectionChecksum), + m_lastError(ErrorNoError) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + qsrand(uint((qint64)(QDateTime::currentDateTime().toTime_t()) & 0xFFFF)); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + splitKey(); + } + + void QxSimpleCrypt::setKey(quint64 key) + { + m_key = key; + splitKey(); + } + + void QxSimpleCrypt::splitKey() + { + m_keyParts.clear(); + m_keyParts.resize(8); + for (int i = 0; i < 8; ++i) + { + quint64 part = m_key; + for (int j = i; j > 0; --j) + part = part >> 8; + part = part & 0xff; + m_keyParts[i] = static_cast(part); + } + } + + QByteArray QxSimpleCrypt::encryptToByteArray(const QString &plaintext) + { + QByteArray plaintextArray = plaintext.toUtf8(); + return encryptToByteArray(plaintextArray); + } + + QByteArray QxSimpleCrypt::encryptToByteArray(QByteArray plaintext) + { + if (m_keyParts.isEmpty()) + { + // qWarning() << "No key set."; + m_lastError = ErrorNoKeySet; + return QByteArray(); + } + + QByteArray ba = plaintext; + + CryptoFlags flags = CryptoFlagNone; + if (m_compressionMode == CompressionAlways) + { + ba = qCompress(ba, 9); // maximum compression + flags |= CryptoFlagCompression; + } + else if (m_compressionMode == CompressionAuto) + { + QByteArray compressed = qCompress(ba, 9); + if (compressed.count() < ba.count()) + { + ba = compressed; + flags |= CryptoFlagCompression; + } + } + + QByteArray integrityProtection; + if (m_protectionMode == ProtectionChecksum) + { + flags |= CryptoFlagChecksum; + QDataStream s(&integrityProtection, QIODevice::WriteOnly); + s << qChecksum(ba.constData(), ba.length()); + } + else if (m_protectionMode == ProtectionHash) + { + flags |= CryptoFlagHash; + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(ba); + integrityProtection += hash.result(); + } + + // prepend a random char to the string +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + QRandomGenerator randomGen = QRandomGenerator::securelySeeded(); + char randomChar = char(randomGen.generate() & 0xFF); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + char randomChar = char(qrand() & 0xFF); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + ba = randomChar + integrityProtection + ba; + + int pos(0); + char lastChar(0); + int cnt = ba.count(); + + while (pos < cnt) + { + ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar; + lastChar = ba.at(pos); + ++pos; + } + + QByteArray resultArray; + resultArray.append(char(0x03)); // version for future updates to algorithm + resultArray.append(char(flags)); // encryption flags + resultArray.append(ba); + + m_lastError = ErrorNoError; + return resultArray; + } + + QString QxSimpleCrypt::encryptToString(const QString &plaintext) + { + QByteArray plaintextArray = plaintext.toUtf8(); + QByteArray cypher = encryptToByteArray(plaintextArray); + QString cypherString = QString::fromLatin1(cypher.toBase64()); + return cypherString; + } + + QString QxSimpleCrypt::encryptToString(QByteArray plaintext) + { + QByteArray cypher = encryptToByteArray(plaintext); + QString cypherString = QString::fromLatin1(cypher.toBase64()); + return cypherString; + } + + QString QxSimpleCrypt::decryptToString(const QString &cyphertext) + { + QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); + QByteArray plaintextArray = decryptToByteArray(cyphertextArray); + QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size()); + return plaintext; + } + + QString QxSimpleCrypt::decryptToString(QByteArray cypher) + { + QByteArray ba = decryptToByteArray(cypher); + QString plaintext = QString::fromUtf8(ba, ba.size()); + return plaintext; + } + + QByteArray QxSimpleCrypt::decryptToByteArray(const QString &cyphertext) + { + QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); + QByteArray ba = decryptToByteArray(cyphertextArray); + return ba; + } + + QByteArray QxSimpleCrypt::decryptToByteArray(QByteArray cypher) + { + if (m_keyParts.isEmpty()) + { + qWarning() << "No key set."; + m_lastError = ErrorNoKeySet; + return QByteArray(); + } + + QByteArray ba = cypher; + char version = ba.at(0); + + if (version != 3) + { // we only work with version 3 + m_lastError = ErrorUnknownVersion; + qWarning() << "Invalid version or not a cyphertext."; + return QByteArray(); + } + + CryptoFlags flags = CryptoFlags(ba.at(1)); + ba = ba.mid(2); + int pos(0); + int cnt(ba.count()); + char lastChar = 0; + + while (pos < cnt) + { + char currentChar = ba[pos]; + ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8); + lastChar = currentChar; + ++pos; + } + + ba = ba.mid(1); // chop off the random number at the start + + bool integrityOk(true); + if (flags.testFlag(CryptoFlagChecksum)) + { + if (ba.length() < 2) + { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + quint16 storedChecksum; + { + QDataStream s(&ba, QIODevice::ReadOnly); + s >> storedChecksum; + } + ba = ba.mid(2); + quint16 checksum = qChecksum(ba.constData(), ba.length()); + integrityOk = (checksum == storedChecksum); + } + else if (flags.testFlag(CryptoFlagHash)) + { + if (ba.length() < 20) + { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + QByteArray storedHash = ba.left(20); + ba = ba.mid(20); + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(ba); + integrityOk = (hash.result() == storedHash); + } + + if (!integrityOk) + { + m_lastError = ErrorIntegrityFailed; + return QByteArray(); + } + + if (flags.testFlag(CryptoFlagCompression)) + ba = qUncompress(ba); + + m_lastError = ErrorNoError; + return ba; + } + +} // namespace qx diff --git a/src/QxConvert/QxConvert_Export.cpp b/src/QxConvert/QxConvert_Export.cpp new file mode 100644 index 0000000..d83c917 --- /dev/null +++ b/src/QxConvert/QxConvert_Export.cpp @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#if _QX_USE_QX_CONVERT_EXPORT + +#include + +#include + +#include + +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToString, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromString, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_ToVariant, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::trait::no_type) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QString) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QDate) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QDateTime) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QByteArray) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QVariant) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx_bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, bool) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, char) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, float) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, double) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned short) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned int) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, unsigned long long) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, std::string) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, std::wstring) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QBrush) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QColor) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QFont) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QObject) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPoint) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRect) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRegion) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QSize) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QStringList) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QUrl) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QImage) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPicture) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QPixmap) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QUuid) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxDateNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxTimeNeutral) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, qx::QxDateTimeNeutral) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QRegExp) +QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, qx::cvt::detail::QxConvert_FromVariant, QMatrix) +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#endif // _QX_USE_QX_CONVERT_EXPORT diff --git a/src/QxDao/IxDao_Helper.cpp b/src/QxDao/IxDao_Helper.cpp new file mode 100644 index 0000000..38ac1b1 --- /dev/null +++ b/src/QxDao/IxDao_Helper.cpp @@ -0,0 +1,907 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +#include + +#define QX_DAO_ERR_INTERNAL "[QxOrm] 'qx::dao' internal error" +#define QX_DAO_ERR_UNKNOWN_ERROR "[QxOrm] 'qx::dao' unknown error" +#define QX_DAO_ERR_NO_CONNECTION "[QxOrm] error retrieving valid sql connection to database" +#define QX_DAO_ERR_OPEN_CONNECTION "[QxOrm] unable to open connection to database" +#define QX_DAO_ERR_BUILD_SQL_QUERY "[QxOrm] error building sql query : %s" +#define QX_DAO_ERR_EXECUTE_SQL_QUERY "[QxOrm] execute sql query failed : %s" +#define QX_DAO_ERR_PREPARE_SQL_QUERY "[QxOrm] prepare sql query failed : %s" +#define QX_DAO_ERR_NO_DATA "[QxOrm] sql query returns no data" +#define QX_DAO_ERR_NO_QUERY_BUILDER "[QxOrm] unable to construct sql query builder" +#define QX_DAO_ERR_NO_ELEMENT_IN_CONTAINER "[QxOrm] no element in container" +#define QX_DAO_ERR_INVALID_PRIMARY_KEY "[QxOrm] invalid primary key" +#define QX_DAO_ERR_INVALID_SQL_RELATION "[QxOrm] invalid sql relation" +#define QX_DAO_ERR_INVALID_VALUES_DETECTED "[QxOrm] validator engine : invalid values detected" +#define QX_DAO_ERR_READ_ONLY "[QxOrm] cannot execute INSERT, UPDATE or DELETE query with a read only entity" + +#define QX_CONSTRUCT_IX_DAO_HELPER() \ + m_timeTotal(0), m_timeExec(0), m_timeNext(0), m_timePrepare(0), m_timeBuildHierarchy(0), m_timeBuildCppInstance(0), m_timeReadCppInstance(0), \ + m_timeBuildSql(0), m_timeOpen(0), m_timeTransaction(0), m_nextCount(0), m_lDataCount(0), m_bTransaction(false), m_bQuiet(false), m_bTraceQuery(true), \ + m_bTraceRecord(false), m_bCartesianProduct(false), m_bValidatorThrowable(false), m_bNeedToClearDatabaseByThread(false), \ + m_bMongoDB(false), m_bDisplayTimerDetails(false), m_bUseExecBatch(false), m_pDataMemberX(NULL), m_pDataId(NULL), m_pSqlGenerator(NULL), m_pSession(NULL) + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#define QX_DAO_TIMER_ELAPSED(timer) timer.nsecsElapsed() +#else // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) +#define QX_DAO_TIMER_ELAPSED(timer) (timer.elapsed() * 1000000) // convert milli-seconds to nano-seconds +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)) + +namespace qx +{ + namespace dao + { + namespace detail + { + + struct Q_DECL_HIDDEN IxDao_Helper::IxDao_HelperImpl + { + + QElapsedTimer m_timerTotal; //!< Timer to manage total elapsed time : build SQL query + all database operations + fetch C++ classes + QElapsedTimer m_timerExec; //!< Timer to manage database exec() elapsed time + QElapsedTimer m_timerNext; //!< Timer to manage database next() elapsed time + QElapsedTimer m_timerPrepare; //!< Timer to manage database prepare() elapsed time + QElapsedTimer m_timerBuildHierarchy; //!< Timer to manage build relationships hierarchy elapsed time + QElapsedTimer m_timerBuildCppInstance; //!< Timer to manage build C++ instance elapsed time + QElapsedTimer m_timerReadCppInstance; //!< Timer to manage read C++ instance elapsed time + QElapsedTimer m_timerBuildSql; //!< Timer to manage build SQL query elapsed time + QElapsedTimer m_timerOpen; //!< Timer to manage open database elapsed time + QElapsedTimer m_timerTransaction; //!< Timer to manage database transaction (commit/rollback) elapsed time + qint64 m_timeTotal; //!< Time (in nanoseconds) for total elapsed time : build SQL query + all database operations + fetch C++ classes + qint64 m_timeExec; //!< Time (in nanoseconds) to execute SQL query in database + qint64 m_timeNext; //!< Time (in nanoseconds) of all calls of QSqlQuery::next() method + qint64 m_timePrepare; //!< Time (in nanoseconds) of all calls of QSqlQuery::prepare() method + qint64 m_timeBuildHierarchy; //!< Time (in nanoseconds) to build relationships hierarchy + qint64 m_timeBuildCppInstance; //!< Time (in nanoseconds) to build C++ instance + qint64 m_timeReadCppInstance; //!< Time (in nanoseconds) to read C++ instance + qint64 m_timeBuildSql; //!< Time (in nanoseconds) to build SQL query + qint64 m_timeOpen; //!< Time (in nanoseconds) to open database + qint64 m_timeTransaction; //!< Time (in nanoseconds) for database transaction (commit/rollback) + int m_nextCount; //!< Number of calls of QSqlQuery::next() method + QSqlDatabase m_database; //!< Connection to database to execute query + QSqlQuery m_query; //!< Query to execute + QSqlError m_error; //!< Error executing query + QString m_context; //!< Description of context : fetch, insert, update, delete, etc... + long m_lDataCount; //!< Data member collection count + bool m_bTransaction; //!< Transaction in progress : commit if valid, rollback if error + bool m_bQuiet; //!< Display message and assert in debug mode + bool m_bTraceQuery; //!< Trace sql query + bool m_bTraceRecord; //!< Trace sql record + bool m_bCartesianProduct; //!< Recordset can return cartesian product => same id in multiple records + bool m_bValidatorThrowable; //!< An exception of type qx::validator_error is thrown when invalid values are detected inserting or updating an element into database + QStringList m_lstColumns; //!< List of columns to execute sql query (if empty => all columns) + bool m_bNeedToClearDatabaseByThread; //!< Internal purpose only to clear current database context by thread in destructor + bool m_bMongoDB; //!< Current database context is a MongoDB database + QStringList m_lstItemsAsJson; //!< List of items to insert/update/delete as JSON (used for MongoDB database) + bool m_bDisplayTimerDetails; //!< Display in logs all timers details (exec(), next(), prepare(), open(), etc...) + bool m_bUseExecBatch; //!< If true then use the QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + + qx::IxSqlQueryBuilder_ptr m_pQueryBuilder; //!< Sql query builder + qx::IxDataMemberX *m_pDataMemberX; //!< Collection of data member + qx::IxDataMember *m_pDataId; //!< Data member id + qx::QxSqlQuery m_qxQuery; //!< Query sql with place-holder + IxSqlGenerator *m_pSqlGenerator; //!< SQL generator to build SQL query specific for each database + qx::QxInvalidValueX m_lstInvalidValues; //!< List of invalid values using validator engine + qx::QxSqlRelationLinked_ptr m_pSqlRelationLinked; //!< List of relation linked to build a hierarchy of relationships + qx::QxSession *m_pSession; //!< Current active session + qx::QxCollection m_lstExecBatch; //!< List of data to send to database when QSqlQuery::execBatch() method is used + + IxDao_HelperImpl(qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery) : QX_CONSTRUCT_IX_DAO_HELPER() + { + m_pQueryBuilder.reset(pBuilder); + if (pQuery) + { + m_qxQuery = (*pQuery); + } + } + ~IxDao_HelperImpl() { ; } + + void displaySqlQuery(); + }; + + IxDao_Helper::IxDao_Helper(qx::IxSqlQueryBuilder *pBuilder, const qx::QxSqlQuery *pQuery /* = NULL */) : m_pImpl(new IxDao_HelperImpl(pBuilder, pQuery)) { ; } + + IxDao_Helper::~IxDao_Helper() + { + terminate(); + if (m_pImpl->m_bNeedToClearDatabaseByThread) + { + qx::QxSqlDatabase::getSingleton()->clearCurrentDatabaseByThread(); + } + } + + bool IxDao_Helper::isValid() const { return (!m_pImpl->m_error.isValid() && m_pImpl->m_pQueryBuilder); } + + bool IxDao_Helper::hasFeature(QSqlDriver::DriverFeature ft) const { return (m_pImpl->m_database.driver() ? m_pImpl->m_database.driver()->hasFeature(ft) : false); } + + QSqlDatabase &IxDao_Helper::database() { return m_pImpl->m_database; } + + const QSqlDatabase &IxDao_Helper::database() const { return m_pImpl->m_database; } + + QSqlQuery &IxDao_Helper::query() { return m_pImpl->m_query; } + + const QSqlQuery &IxDao_Helper::query() const { return m_pImpl->m_query; } + + QSqlError &IxDao_Helper::error() { return m_pImpl->m_error; } + + const QSqlError &IxDao_Helper::error() const { return m_pImpl->m_error; } + + qx::QxSqlQuery &IxDao_Helper::qxQuery() { return m_pImpl->m_qxQuery; } + + const qx::QxSqlQuery &IxDao_Helper::qxQuery() const { return m_pImpl->m_qxQuery; } + + qx::IxDataMemberX *IxDao_Helper::getDataMemberX() const { return m_pImpl->m_pDataMemberX; } + + long IxDao_Helper::getDataCount() const { return m_pImpl->m_lDataCount; } + + qx::IxDataMember *IxDao_Helper::getDataId() const { return m_pImpl->m_pDataId; } + + qx::IxDataMember *IxDao_Helper::nextData(long &l) const { return (m_pImpl->m_pQueryBuilder ? m_pImpl->m_pQueryBuilder->nextData(l) : NULL); } + + QString IxDao_Helper::sql() const { return (m_pImpl->m_pQueryBuilder ? m_pImpl->m_pQueryBuilder->getSqlQuery() : ""); } + + qx::QxSqlRelationLinked *IxDao_Helper::getSqlRelationLinked() const { return m_pImpl->m_pSqlRelationLinked.get(); } + + qx::QxSession *IxDao_Helper::getSession() const { return m_pImpl->m_pSession; } + + QString IxDao_Helper::getIgnoreSoftDeleteHash() const { return (m_pImpl->m_pSession ? m_pImpl->m_pSession->getIgnoreSoftDeleteHash() : QString()); } + + bool IxDao_Helper::getCartesianProduct() const { return m_pImpl->m_bCartesianProduct; } + + QStringList IxDao_Helper::getSqlColumns() const { return m_pImpl->m_lstColumns; } + + void IxDao_Helper::setSqlColumns(const QStringList &lst) { m_pImpl->m_lstColumns = lst; } + + bool IxDao_Helper::getUseExecBatch() const { return m_pImpl->m_bUseExecBatch; } + + void IxDao_Helper::setUseExecBatch(bool b) { m_pImpl->m_bUseExecBatch = b; } + + qx::QxCollection &IxDao_Helper::getListExecBatch() { return m_pImpl->m_lstExecBatch; } + + IxSqlGenerator *IxDao_Helper::getSqlGenerator() const { return m_pImpl->m_pSqlGenerator; } + + void IxDao_Helper::quiet() { m_pImpl->m_bQuiet = true; } + + bool IxDao_Helper::isReadOnly() const { return ((m_pImpl->m_pDataMemberX && m_pImpl->m_pDataMemberX->getClass()) ? m_pImpl->m_pDataMemberX->getClass()->isDaoReadOnly() : false); } + + bool IxDao_Helper::isMongoDB() const { return m_pImpl->m_bMongoDB; } + + bool IxDao_Helper::isDistinct() const { return m_pImpl->m_qxQuery.isDistinct(); } + + bool IxDao_Helper::getAddAutoIncrementIdToUpdateQuery() const { return qx::QxSqlDatabase::getSingleton()->getAddAutoIncrementIdToUpdateQuery(); } + + QStringList &IxDao_Helper::itemsAsJson() { return m_pImpl->m_lstItemsAsJson; } + + bool IxDao_Helper::exec(bool bForceEmptyExec /* = false */) + { + bool bExec = false; + IxDao_Timer timer(this, IxDao_Helper::timer_db_exec); + if (m_pImpl->m_bUseExecBatch) + { + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + for (long l = 0; l < m_pImpl->m_lstExecBatch.size(); ++l) + { + if (bQuestionMark) + { + this->query().addBindValue(m_pImpl->m_lstExecBatch.getByIndex(l)); + } + else + { + this->query().bindValue(m_pImpl->m_lstExecBatch.getKeyByIndex(l), m_pImpl->m_lstExecBatch.getByIndex(l)); + } + } + bExec = this->query().execBatch(); + } + else if ((m_pImpl->m_qxQuery.isEmpty()) && (!bForceEmptyExec)) + { + bExec = this->query().exec(this->builder().getSqlQuery()); + } + else + { + bExec = this->query().exec(); + } + return bExec; + } + + bool IxDao_Helper::prepare(QString &sql) + { + QString sqlTemp = sql; + IxDao_Timer timer(this, IxDao_Helper::timer_db_prepare); + if (m_pImpl->m_pSqlGenerator) + { + m_pImpl->m_pSqlGenerator->onBeforeSqlPrepare(this, sql); + } + if (sqlTemp != sql) + { + qDebug("[QxOrm] SQL query has been changed by SQL generator (onBeforeSqlPrepare) :\n - before : '%s'\n - after : '%s'", qPrintable(sqlTemp), qPrintable(sql)); + } + sqlTemp = sql; + m_pImpl->m_qxQuery.onBeforeSqlPrepare(sql); + if (sqlTemp != sql) + { + qDebug("[QxOrm] SQL query has been changed by qx::QxSqlQuery (onBeforeSqlPrepare) :\n - before : '%s'\n - after : '%s'", qPrintable(sqlTemp), qPrintable(sql)); + } + return this->query().prepare(sql); + } + + void IxDao_Helper::addInvalidValues(const qx::QxInvalidValueX &lst) + { + m_pImpl->m_lstInvalidValues.insert(lst); + if (m_pImpl->m_lstInvalidValues.count() > 0) + { + QString sInvalidValues = QX_DAO_ERR_INVALID_VALUES_DETECTED; + sInvalidValues += QString("\n") + m_pImpl->m_lstInvalidValues.text(); + updateError(sInvalidValues); + if (m_pImpl->m_bValidatorThrowable) + { + QString tmp = m_pImpl->m_lstInvalidValues.text(); + qDebug("[QxOrm] invalid values detected, throw 'qx::validator_error' exception : '%s'", qPrintable(tmp)); + } + if (m_pImpl->m_bValidatorThrowable) + { + throw qx::validator_error(m_pImpl->m_lstInvalidValues); + } + } + } + + qx::IxSqlQueryBuilder &IxDao_Helper::builder() + { + qAssert(m_pImpl->m_pQueryBuilder); + return (*m_pImpl->m_pQueryBuilder); + } + + const qx::IxSqlQueryBuilder &IxDao_Helper::builder() const + { + qAssert(m_pImpl->m_pQueryBuilder); + return (*m_pImpl->m_pQueryBuilder); + } + + QSqlError IxDao_Helper::errFailed(bool bPrepare /* = false */) + { + QString sql = this->sql(); + bool bFormatSql = qx::QxSqlDatabase::getSingleton()->getFormatSqlQueryBeforeLogging(); + if (bFormatSql && m_pImpl->m_pSqlGenerator) + { + m_pImpl->m_pSqlGenerator->formatSqlQuery(this, sql); + } + if (bPrepare) + { + qDebug(QX_DAO_ERR_PREPARE_SQL_QUERY, qPrintable(sql)); + } + else + { + qDebug(QX_DAO_ERR_EXECUTE_SQL_QUERY, qPrintable(sql)); + } + return updateError(m_pImpl->m_query.lastError()); + } + + QSqlError IxDao_Helper::errEmpty() + { + QString sql = this->sql(); + qDebug(QX_DAO_ERR_BUILD_SQL_QUERY, qPrintable(sql)); + return updateError(m_pImpl->m_query.lastError()); + } + + QSqlError IxDao_Helper::errNoData() { return updateError(QX_DAO_ERR_NO_DATA); } + + QSqlError IxDao_Helper::errInvalidId() { return updateError(QX_DAO_ERR_INVALID_PRIMARY_KEY); } + + QSqlError IxDao_Helper::errInvalidRelation() { return updateError(QX_DAO_ERR_INVALID_SQL_RELATION); } + + QSqlError IxDao_Helper::errReadOnly() { return updateError(QX_DAO_ERR_READ_ONLY); } + + bool IxDao_Helper::transaction() + { + if (m_pImpl->m_bMongoDB) + { + return false; + } + if (isValid() && hasFeature(QSqlDriver::Transactions)) + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_transaction); + m_pImpl->m_bTransaction = m_pImpl->m_database.transaction(); + } + return m_pImpl->m_bTransaction; + } + + bool IxDao_Helper::nextRecord() + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_next); + bool bNext = m_pImpl->m_query.next(); + if (bNext && m_pImpl->m_bTraceRecord) + { + dumpRecord(); + } + return bNext; + } + + QVariant IxDao_Helper::getIdFromQuery(int iNameIndex /* = -1 */) const + { + QVariant vId; + bool isDistinct = this->isDistinct(); + qx::IxDataMember *pId = m_pImpl->m_pDataId; + qAssert(pId); + if (!pId) + { + return vId; + } + bool bForceRootId = ((isDistinct && pId && m_pImpl->m_pSqlRelationLinked) ? m_pImpl->m_pSqlRelationLinked->checkRootColumns(pId->getKey()) : false); + if (((!isDistinct) || (bForceRootId)) && (iNameIndex < 0)) + { + QString sId; + for (int i = 0; i < pId->getNameCount(); i++) + { + sId += m_pImpl->m_query.value(i).toString() + "|"; + } + vId = sId; + } + else if (((!isDistinct) || (bForceRootId)) && (iNameIndex >= 0)) + { + qAssert(iNameIndex < pId->getNameCount()); + vId = m_pImpl->m_query.value(iNameIndex); + } + else if (isDistinct) + { + QString sId; + QStringList columns = this->getSqlColumns(); + if ((columns.count() <= 0) || (columns.at(0) == "*")) + { + long l = 0; + qx::IxDataMember *p = NULL; + while ((p = this->builder().nextData(l))) + { + sId += m_pImpl->m_query.value(l - 1).toString() + "|"; + } + } + else + { + for (int i = 0; i < columns.count(); i++) + { + qx::IxDataMember *p = m_pImpl->m_pDataMemberX->get_WithDaoStrategy(columns.at(i)); + if (p && (p != pId)) + { + sId += m_pImpl->m_query.value(i).toString() + "|"; + } + } + } + vId = static_cast(qHash(sId)); + } + return vId; + } + + bool IxDao_Helper::updateSqlRelationX(const QStringList &relation) + { + qx_bool bHierarchyOk(true); + m_pImpl->m_bCartesianProduct = false; + IxDao_Timer timer(this, IxDao_Helper::timer_cpp_build_hierarchy); + m_pImpl->m_pSqlRelationLinked = qx::QxSqlRelationLinked::getHierarchy((m_pImpl->m_pDataMemberX ? m_pImpl->m_pDataMemberX->getClass() : NULL), relation, bHierarchyOk, this); + if (!bHierarchyOk) + { + m_pImpl->m_pSqlRelationLinked.reset(); + } + if (!bHierarchyOk) + { + QString txt = bHierarchyOk.getDesc(); + qDebug("[QxOrm] %s", qPrintable(txt)); + return false; + } + m_pImpl->m_bCartesianProduct = m_pImpl->m_pSqlRelationLinked->getCartesianProduct(); + if (m_pImpl->m_pQueryBuilder) + { + m_pImpl->m_pQueryBuilder->setCartesianProduct(m_pImpl->m_bCartesianProduct); + } + if (m_pImpl->m_pQueryBuilder) + { + m_pImpl->m_pQueryBuilder->setHashRelation(relation.join("|")); + } + if (m_pImpl->m_bCartesianProduct) + { + m_pImpl->m_pQueryBuilder->initIdX(m_pImpl->m_pSqlRelationLinked->getAllRelationCount()); + } + return bHierarchyOk.getValue(); + } + + void IxDao_Helper::dumpRecord() const + { + if (!m_pImpl->m_query.isValid()) + { + return; + } + QString sDump; + QVariant v; + QSqlRecord record = m_pImpl->m_query.record(); + int iCount = record.count(); + if (iCount <= 0) + { + return; + } + for (int i = 0; i < iCount; ++i) + { + v = record.value(i); + sDump += (v.isNull() ? QString("NULL") : v.toString()) + QString("|"); + } + sDump = sDump.left(sDump.length() - 1); // Remove last "|" + qDebug("[QxOrm] dump sql record : %s", qPrintable(sDump)); + } + + void IxDao_Helper::resolveQuery() + { + if (m_pImpl->m_qxQuery.isEmpty()) + { + return; + } + m_pImpl->m_qxQuery.resolve(m_pImpl->m_query, (m_pImpl->m_bUseExecBatch ? (&m_pImpl->m_lstExecBatch) : NULL)); + } + + void IxDao_Helper::timerStart(IxDao_Helper::timer_type timer) + { + switch (timer) + { + case IxDao_Helper::timer_total: + m_pImpl->m_timerTotal.start(); + break; + case IxDao_Helper::timer_db_exec: + m_pImpl->m_timerExec.start(); + break; + case IxDao_Helper::timer_db_next: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerNext.start(); + break; + case IxDao_Helper::timer_db_prepare: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerPrepare.start(); + break; + case IxDao_Helper::timer_cpp_build_hierarchy: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerBuildHierarchy.start(); + break; + case IxDao_Helper::timer_cpp_build_instance: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerBuildCppInstance.start(); + break; + case IxDao_Helper::timer_cpp_read_instance: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerReadCppInstance.start(); + break; + case IxDao_Helper::timer_build_sql: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerBuildSql.start(); + break; + case IxDao_Helper::timer_db_open: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerOpen.start(); + break; + case IxDao_Helper::timer_db_transaction: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + m_pImpl->m_timerTransaction.start(); + break; + default: + break; + } + } + + qint64 IxDao_Helper::timerElapsed(IxDao_Helper::timer_type timer) + { + qint64 elapsed = 0; + switch (timer) + { + case IxDao_Helper::timer_total: + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerTotal); + m_pImpl->m_timeTotal += elapsed; + break; + case IxDao_Helper::timer_db_exec: + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerExec); + m_pImpl->m_timeExec += elapsed; + break; + case IxDao_Helper::timer_db_next: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerNext); + m_pImpl->m_timeNext += elapsed; + m_pImpl->m_nextCount++; + break; + case IxDao_Helper::timer_db_prepare: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerPrepare); + m_pImpl->m_timePrepare += elapsed; + break; + case IxDao_Helper::timer_cpp_build_hierarchy: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerBuildHierarchy); + m_pImpl->m_timeBuildHierarchy += elapsed; + break; + case IxDao_Helper::timer_cpp_build_instance: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerBuildCppInstance); + m_pImpl->m_timeBuildCppInstance += elapsed; + break; + case IxDao_Helper::timer_cpp_read_instance: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerReadCppInstance); + m_pImpl->m_timeReadCppInstance += elapsed; + break; + case IxDao_Helper::timer_build_sql: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerBuildSql); + m_pImpl->m_timeBuildSql += elapsed; + break; + case IxDao_Helper::timer_db_open: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerOpen); + m_pImpl->m_timeOpen += elapsed; + break; + case IxDao_Helper::timer_db_transaction: + if (!m_pImpl->m_bDisplayTimerDetails) + { + break; + } + elapsed = QX_DAO_TIMER_ELAPSED(m_pImpl->m_timerTransaction); + m_pImpl->m_timeTransaction += elapsed; + break; + default: + break; + } + return elapsed; + } + + void IxDao_Helper::addQuery(bool bResolve) + { + if (m_pImpl->m_qxQuery.isEmpty()) + { + return; + } + IxDao_Timer timer(this, IxDao_Helper::timer_build_sql); + QString sql = this->builder().getSqlQuery(); + QString sqlToAdd = m_pImpl->m_qxQuery.query().trimmed(); + bool bAddSqlCondition = false; + if (sqlToAdd.left(6).contains("WHERE ", Qt::CaseInsensitive)) + { + sqlToAdd = sqlToAdd.right(sqlToAdd.size() - 6); + bAddSqlCondition = true; + } + else if (sqlToAdd.left(4).contains("AND ", Qt::CaseInsensitive)) + { + sqlToAdd = sqlToAdd.right(sqlToAdd.size() - 4); + bAddSqlCondition = true; + } + this->builder().replaceSqlQueryAlias(sqlToAdd); + sql += (bAddSqlCondition ? qx::IxSqlQueryBuilder::addSqlCondition(sql) : QString(" ")) + sqlToAdd; + if (m_pImpl->m_qxQuery.isDistinct() && sql.left(7).contains("SELECT ", Qt::CaseInsensitive)) + { + sql = "SELECT DISTINCT " + sql.right(sql.size() - 7); + } + m_pImpl->m_qxQuery.postProcess(sql); + this->builder().setSqlQuery(sql); + + if (bResolve) + { + if (!this->prepare(sql)) + { + this->errFailed(true); + } + m_pImpl->m_qxQuery.resolve(this->query()); + } + } + + QSqlError IxDao_Helper::updateError(const QString &sError) + { + QString sDriverText = (QX_DAO_ERR_INTERNAL + QString(" <") + m_pImpl->m_context + QString(">")); + sDriverText += (sql().isEmpty() ? QString("") : (QString(" : ") + sql())); + QSqlError err = QSqlError(sDriverText, sError, QSqlError::UnknownError); + return updateError(err); + } + + QSqlError IxDao_Helper::updateError(const QSqlError &error) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString sDatabaseText = (((error.databaseText() != m_pImpl->m_error.databaseText()) && (!error.databaseText().isEmpty())) ? (m_pImpl->m_error.databaseText() + "\n" + error.databaseText()) : m_pImpl->m_error.databaseText()); + QString sDriverText = (((error.driverText() != m_pImpl->m_error.driverText()) && (!error.driverText().isEmpty())) ? (m_pImpl->m_error.driverText() + "\n" + error.driverText()) : m_pImpl->m_error.driverText()); + QString sNativeErrorCode = (((error.nativeErrorCode() != m_pImpl->m_error.nativeErrorCode()) && (!error.nativeErrorCode().isEmpty())) ? (m_pImpl->m_error.nativeErrorCode() + "\n" + error.nativeErrorCode()) : m_pImpl->m_error.nativeErrorCode()); + int iType = ((((m_pImpl->m_error.type() == QSqlError::NoError) || (m_pImpl->m_error.type() == QSqlError::UnknownError)) && (error.type() != QSqlError::NoError)) ? error.type() : m_pImpl->m_error.type()); + m_pImpl->m_error = QSqlError(sDriverText, sDatabaseText, static_cast(iType), sNativeErrorCode); + return m_pImpl->m_error; +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + if (!m_pImpl->m_error.isValid()) + { + m_pImpl->m_error = error; + return m_pImpl->m_error; + } + + if ((error.databaseText() != m_pImpl->m_error.databaseText()) && (!error.databaseText().isEmpty())) + { + m_pImpl->m_error.setDatabaseText(m_pImpl->m_error.databaseText() + "\n" + error.databaseText()); + } + if ((error.driverText() != m_pImpl->m_error.driverText()) && (!error.driverText().isEmpty())) + { + m_pImpl->m_error.setDriverText(m_pImpl->m_error.driverText() + "\n" + error.driverText()); + } + if (((m_pImpl->m_error.type() == QSqlError::NoError) || (m_pImpl->m_error.type() == QSqlError::UnknownError)) && (error.type() != QSqlError::NoError)) + { + m_pImpl->m_error.setType(error.type()); + } + if (m_pImpl->m_error.number() == -1) + { + m_pImpl->m_error.setNumber(error.number()); + } + + return m_pImpl->m_error; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + } + + void IxDao_Helper::init(QSqlDatabase *pDatabase, const QString &sContext) + { + timerStart(IxDao_Helper::timer_total); + m_pImpl->m_context = sContext; + m_pImpl->m_bTraceQuery = qx::QxSqlDatabase::getSingleton()->getTraceSqlQuery(); + m_pImpl->m_bTraceRecord = qx::QxSqlDatabase::getSingleton()->getTraceSqlRecord(); + m_pImpl->m_bMongoDB = (qx::QxSqlDatabase::getSingleton()->getDriverName() == "QXMONGODB"); + m_pImpl->m_bDisplayTimerDetails = qx::QxSqlDatabase::getSingleton()->getDisplayTimerDetails(); + qAssert(!m_pImpl->m_context.isEmpty()); + +#ifndef _QX_ENABLE_MONGODB + if (m_pImpl->m_bMongoDB) + { + qAssertMsg(false, "[QxOrm] QXMONGODB driver", "_QX_ENABLE_MONGODB compilation option is required to connect to MongoDB database"); + updateError("[QxOrm] QXMONGODB driver : _QX_ENABLE_MONGODB compilation option is required to connect to MongoDB database"); + return; + } +#endif // _QX_ENABLE_MONGODB + + if (!m_pImpl->m_bMongoDB) + { + QSqlError dbError; + IxDao_Timer timer(this, IxDao_Helper::timer_db_open); + if (pDatabase) + { + m_pImpl->m_bNeedToClearDatabaseByThread = qx::QxSqlDatabase::getSingleton()->setCurrentDatabaseByThread(pDatabase); + } + m_pImpl->m_database = (pDatabase ? (*pDatabase) : qx::QxSqlDatabase::getDatabase(dbError)); + if (dbError.isValid()) + { + updateError(dbError); + return; + } + if (!m_pImpl->m_database.isValid()) + { + updateError(QX_DAO_ERR_NO_CONNECTION); + return; + } + if (!m_pImpl->m_database.isOpen() && !m_pImpl->m_database.open()) + { + updateError(QX_DAO_ERR_OPEN_CONNECTION); + return; + } + if (!m_pImpl->m_pQueryBuilder) + { + updateError(QX_DAO_ERR_NO_QUERY_BUILDER); + return; + } + m_pImpl->m_pSession = qx::QxSession::getActiveSession(&m_pImpl->m_database); + m_pImpl->m_query = QSqlQuery(m_pImpl->m_database); + m_pImpl->m_query.setForwardOnly(true); + } + + m_pImpl->m_pQueryBuilder->init(); + m_pImpl->m_pQueryBuilder->setDaoHelper(this); + m_pImpl->m_pDataMemberX = (m_pImpl->m_pQueryBuilder ? m_pImpl->m_pQueryBuilder->getDataMemberX() : NULL); + m_pImpl->m_lDataCount = (m_pImpl->m_pQueryBuilder ? m_pImpl->m_pQueryBuilder->getDataCount() : 0); + m_pImpl->m_pDataId = (m_pImpl->m_pQueryBuilder ? m_pImpl->m_pQueryBuilder->getDataId() : NULL); + m_pImpl->m_pSqlGenerator = qx::QxSqlDatabase::getSingleton()->getSqlGenerator(); + m_pImpl->m_bValidatorThrowable = qx::QxSqlDatabase::getSingleton()->getValidatorThrowable(); + } + + void IxDao_Helper::terminate() + { + if ((m_pImpl->m_lstInvalidValues.count() > 0) && m_pImpl->m_bValidatorThrowable) + { + if (m_pImpl->m_bTransaction) + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_transaction); + m_pImpl->m_database.rollback(); + } + } + else if (!isValid()) + { + if (m_pImpl->m_bTransaction) + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_transaction); + m_pImpl->m_database.rollback(); + } + if (!m_pImpl->m_bQuiet) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString serr = m_pImpl->m_error.nativeErrorCode(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int ierr = m_pImpl->m_error.number(); + QString serr = QString::number(ierr); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString tmp = m_pImpl->m_error.driverText(); + qDebug("Database error number '%s' : %s", qPrintable(serr), qPrintable(tmp)); + tmp = m_pImpl->m_error.databaseText(); + qDebug("%s", qPrintable(tmp)); + if (m_pImpl->m_bMongoDB) + { + tmp = m_pImpl->m_qxQuery.queryAt(0); + qDebug("%s", qPrintable(tmp)); + } + } + } + else if (m_pImpl->m_pQueryBuilder) + { + if (m_pImpl->m_bTransaction) + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_transaction); + m_pImpl->m_database.commit(); + } + if (!m_pImpl->m_bQuiet && m_pImpl->m_bTraceQuery) + { + timerElapsed(IxDao_Helper::timer_total); + m_pImpl->displaySqlQuery(); + } + } + else + { + if (m_pImpl->m_bTransaction) + { + IxDao_Timer timer(this, IxDao_Helper::timer_db_transaction); + m_pImpl->m_database.rollback(); + } + if (!m_pImpl->m_bQuiet) + { + qDebug("%s", QX_DAO_ERR_UNKNOWN_ERROR); + qAssert(false); + } + } + + m_pImpl->m_bTransaction = false; + dumpBoundValues(); + } + + void IxDao_Helper::dumpBoundValues() const + { + if (m_pImpl->m_bMongoDB) + { + return; + } + qx::QxSqlDatabase *pDatabase = qx::QxSqlDatabase::getSingleton(); + if (!pDatabase) + { + return; + } + bool bBoundValues = pDatabase->getTraceSqlBoundValues(); + bool bBoundValuesOnError = pDatabase->getTraceSqlBoundValuesOnError(); + + if ((!isValid() && bBoundValuesOnError) || (bBoundValues)) + { + qx::QxSqlQuery::dumpBoundValues(m_pImpl->m_query); + } + } + + void IxDao_Helper::IxDao_HelperImpl::displaySqlQuery() + { + QString query = (m_bMongoDB ? m_qxQuery.queryAt(0) : QString()); + QString sql = ((query.isEmpty() && m_pQueryBuilder) ? m_pQueryBuilder->getSqlQuery() : query); + bool bFormatSql = qx::QxSqlDatabase::getSingleton()->getFormatSqlQueryBeforeLogging(); + qx::dao::detail::IxSqlGenerator *pSqlGenerator = qx::QxSqlDatabase::getSingleton()->getSqlGenerator(); + qint64 iTraceSqlOnlySlowQueriesDatabase = static_cast(qx::QxSqlDatabase::getSingleton()->getTraceSqlOnlySlowQueriesDatabase()); + qint64 iTraceSqlOnlySlowQueriesTotal = static_cast(qx::QxSqlDatabase::getSingleton()->getTraceSqlOnlySlowQueriesTotal()); + if ((iTraceSqlOnlySlowQueriesDatabase > 0) && (iTraceSqlOnlySlowQueriesTotal < 0)) + { + iTraceSqlOnlySlowQueriesTotal = 999999999; + } + else if ((iTraceSqlOnlySlowQueriesTotal > 0) && (iTraceSqlOnlySlowQueriesDatabase < 0)) + { + iTraceSqlOnlySlowQueriesDatabase = 999999999; + } + if (bFormatSql && pSqlGenerator) + { + pSqlGenerator->formatSqlQuery(NULL, sql); + } + + if ((m_timeTotal >= (iTraceSqlOnlySlowQueriesTotal * 1000000)) || (m_timeExec >= (iTraceSqlOnlySlowQueriesDatabase * 1000000))) // convert milli-seconds to nano-seconds + { + QString log = "sql query (total: " + ((m_timeTotal == 0) ? QString("0") : QString::number((static_cast(m_timeTotal) / 1000000.0), 'g', 3)) + " ms"; + log += ", db_exec: " + ((m_timeExec == 0) ? QString("0") : QString::number((static_cast(m_timeExec) / 1000000.0), 'g', 3)) + " ms"; + if (m_bDisplayTimerDetails) + { + log += ", db_prepare: " + ((m_timePrepare == 0) ? QString("0") : QString::number((static_cast(m_timePrepare) / 1000000.0), 'g', 3)) + " ms"; + log += ", db_next(" + QString::number(m_nextCount) + "): " + ((m_timeNext == 0) ? QString("0") : QString::number((static_cast(m_timeNext) / 1000000.0), 'g', 3)) + " ms"; + log += ", db_open: " + ((m_timeOpen == 0) ? QString("0") : QString::number((static_cast(m_timeOpen) / 1000000.0), 'g', 3)) + " ms"; + log += ", db_transaction: " + ((m_timeTransaction == 0) ? QString("0") : QString::number((static_cast(m_timeTransaction) / 1000000.0), 'g', 3)) + " ms"; + log += ", build_relations: " + ((m_timeBuildHierarchy == 0) ? QString("0") : QString::number((static_cast(m_timeBuildHierarchy) / 1000000.0), 'g', 3)) + " ms"; + log += ", build_sql: " + ((m_timeBuildSql == 0) ? QString("0") : QString::number((static_cast(m_timeBuildSql) / 1000000.0), 'g', 3)) + " ms"; + log += ", build_cpp: " + ((m_timeBuildCppInstance == 0) ? QString("0") : QString::number((static_cast(m_timeBuildCppInstance) / 1000000.0), 'g', 3)) + " ms"; + log += ", read_cpp: " + ((m_timeReadCppInstance == 0) ? QString("0") : QString::number((static_cast(m_timeReadCppInstance) / 1000000.0), 'g', 3)) + " ms"; + } + log += ") : " + sql; + qDebug("[QxOrm] %s", qPrintable(log)); + } + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/IxPersistable.cpp b/src/QxDao/IxPersistable.cpp new file mode 100644 index 0000000..09390c3 --- /dev/null +++ b/src/QxDao/IxPersistable.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +#include + +namespace qx +{ + + IxPersistable::IxPersistable() { ; } + + IxPersistable::~IxPersistable() { ; } + + std::shared_ptr IxPersistable::qxFetchAll(const QString &className, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */, bool bAsList /* = false */) + { + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return std::shared_ptr(); + } + qx::IxPersistable_ptr ptr = qx::IxPersistable_ptr(static_cast(qx::create_void_ptr(className))); + if (!ptr) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxFetchAll() : 'invalid classname, unable to create a new instance'", "", QSqlError::UnknownError)); + } + std::shared_ptr lst = ptr->qxNewPersistableCollection(bAsList); + if (!lst) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxFetchAll() : 'unable to create a new persistable collection'", "", QSqlError::UnknownError)); + } + QSqlError daoError = lst->qxFetchAll(NULL, columns, relation, pDatabase); + if (daoError.isValid()) + { + throw qx::dao::sql_error(daoError); + } + return lst; + } + + std::shared_ptr IxPersistable::qxFetchByQuery(const QString &className, const qx::QxSqlQuery &query, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */, bool bAsList /* = false */) + { + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return std::shared_ptr(); + } + qx::IxPersistable_ptr ptr = qx::IxPersistable_ptr(static_cast(qx::create_void_ptr(className))); + if (!ptr) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxFetchByQuery() : 'invalid classname, unable to create a new instance'", "", QSqlError::UnknownError)); + } + std::shared_ptr lst = ptr->qxNewPersistableCollection(bAsList); + if (!lst) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxFetchByQuery() : 'unable to create a new persistable collection'", "", QSqlError::UnknownError)); + } + QSqlError daoError = lst->qxFetchByQuery(query, NULL, columns, relation, pDatabase); + if (daoError.isValid()) + { + throw qx::dao::sql_error(daoError); + } + return lst; + } + + std::shared_ptr IxPersistable::qxExecuteQuery(const QString &className, qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */, bool bAsList /* = false */) + { + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return std::shared_ptr(); + } + qx::IxPersistable_ptr ptr = qx::IxPersistable_ptr(static_cast(qx::create_void_ptr(className))); + if (!ptr) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxExecuteQuery() : 'invalid classname, unable to create a new instance'", "", QSqlError::UnknownError)); + } + std::shared_ptr lst = ptr->qxNewPersistableCollection(bAsList); + if (!lst) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxPersistable::qxExecuteQuery() : 'unable to create a new persistable collection'", "", QSqlError::UnknownError)); + } + QSqlError daoError = lst->qxExecuteQuery(query, NULL, pDatabase); + if (daoError.isValid()) + { + throw qx::dao::sql_error(daoError); + } + return lst; + } + +} // namespace qx diff --git a/src/QxDao/IxPersistableCollection.cpp b/src/QxDao/IxPersistableCollection.cpp new file mode 100644 index 0000000..fe7a901 --- /dev/null +++ b/src/QxDao/IxPersistableCollection.cpp @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + + IxPersistableCollection::IxPersistableCollection() : qx::IxPersistable() { ; } + + IxPersistableCollection::~IxPersistableCollection() { ; } + +} // namespace qx diff --git a/src/QxDao/IxPersistableList.cpp b/src/QxDao/IxPersistableList.cpp new file mode 100644 index 0000000..d4c83b0 --- /dev/null +++ b/src/QxDao/IxPersistableList.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + +} // namespace qx diff --git a/src/QxDao/IxSqlQueryBuilder.cpp b/src/QxDao/IxSqlQueryBuilder.cpp new file mode 100644 index 0000000..a75c8cf --- /dev/null +++ b/src/QxDao/IxSqlQueryBuilder.cpp @@ -0,0 +1,953 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN IxSqlQueryBuilder::IxSqlQueryBuilderImpl + { + + typedef QPair type_id; + typedef QHash type_ptr_by_id; + typedef std::shared_ptr type_ptr_by_id_ptr; + typedef QList type_lst_ptr_by_id; + typedef std::shared_ptr type_lst_ptr_by_id_ptr; + typedef QxCollection type_lst_data_member; + typedef std::shared_ptr type_lst_data_member_ptr; + + type_lst_data_member_ptr m_lstDataMemberPtr; //!< Collection of 'IxDataMember' to build sql query + std::shared_ptr m_lstSqlRelationPtr; //!< Collection of 'IxSqlRelation' to build sql query + IxDataMember *m_pDataMemberId; //!< Data member id for sql query + QString m_sSqlQuery; //!< Current sql query + QString m_sTableName; //!< Sql table name of current object + QString m_sHashRelation; //!< Optimization : hash to retrieve sql query with relation + bool m_bCartesianProduct; //!< Recordset can return cartesian product => same id in multiple records + type_lst_ptr_by_id_ptr m_pIdX; //!< Collection of id (and pointer associated) to avoid multiple fetch on same id (cartesian product) + QxSoftDelete m_oSoftDelete; //!< Soft delete (or logical delete) behavior + QxSoftDelete m_oSoftDeleteEmpty; //!< Keep an empty soft delete instance (used with qx::QxSession::ignoreSoftDelete()) + QHash m_lstSqlQueryAlias; //!< List of sql alias to replace into sql query + qx::dao::detail::IxDao_Helper *m_pDaoHelper; //!< Pointer to the dao helper class associated to the builder + IxDataMemberX *m_pDataMemberX; //!< QxDataMemberX singleton reference + bool m_bInitDone; //!< Class initialisation finished + QString m_sCurrentBuildingSql; //!< Current building SQL query (not finished yet) + + static QHash m_lstSqlQuery; //!< Store here all SQL queries generated by child classes + static QHash> m_lstSqlAlias; //!< Store here all SQL aliases generated by child classes + static QMutex m_mutex; //!< Mutex => qx::IxSqlQueryBuilder is thread-safe + + IxSqlQueryBuilderImpl() : m_pDataMemberId(NULL), m_bCartesianProduct(false), m_pDaoHelper(NULL), m_pDataMemberX(NULL), m_bInitDone(false) { ; } + ~IxSqlQueryBuilderImpl() { ; } + + bool checkIgnoreSoftDelete() const + { + if ((!m_pDaoHelper) || (!m_pDataMemberX)) + { + return false; + } + qx::QxSession *pSession = m_pDaoHelper->getSession(); + if (!pSession) + { + return false; + } + qx::IxClass *pClass = m_pDataMemberX->getClass(); + if (!pClass) + { + return false; + } + return pSession->checkIgnoreSoftDelete(pClass->getKey()); + } + }; + + QHash IxSqlQueryBuilder::IxSqlQueryBuilderImpl::m_lstSqlQuery; + QHash> IxSqlQueryBuilder::IxSqlQueryBuilderImpl::m_lstSqlAlias; + QMutex IxSqlQueryBuilder::IxSqlQueryBuilderImpl::m_mutex; + + IxSqlQueryBuilder::IxSqlQueryBuilder() : m_pImpl(new IxSqlQueryBuilderImpl()) { ; } + + IxSqlQueryBuilder::~IxSqlQueryBuilder() { ; } + + IxDataMemberX *IxSqlQueryBuilder::getDataMemberX() const { return m_pImpl->m_pDataMemberX; } + + QxCollection *IxSqlQueryBuilder::getLstDataMember() const { return m_pImpl->m_lstDataMemberPtr.get(); } + + IxSqlRelationX *IxSqlQueryBuilder::getLstRelation() const { return m_pImpl->m_lstSqlRelationPtr.get(); } + + qx::dao::detail::IxDao_Helper *IxSqlQueryBuilder::getDaoHelper() const { return m_pImpl->m_pDaoHelper; } + + void IxSqlQueryBuilder::setDaoHelper(qx::dao::detail::IxDao_Helper *p) { m_pImpl->m_pDaoHelper = p; } + + void IxSqlQueryBuilder::setHashRelation(const QString &s) { m_pImpl->m_sHashRelation = s; } + + void IxSqlQueryBuilder::setCartesianProduct(bool b) { m_pImpl->m_bCartesianProduct = b; } + + QString IxSqlQueryBuilder::getSqlQuery() const { return m_pImpl->m_sSqlQuery; } + + QString IxSqlQueryBuilder::getHashRelation() const { return m_pImpl->m_sHashRelation; } + + QString IxSqlQueryBuilder::table() const { return m_pImpl->m_sTableName; } + + QxSoftDelete IxSqlQueryBuilder::getSoftDelete() const { return (m_pImpl->checkIgnoreSoftDelete() ? m_pImpl->m_oSoftDeleteEmpty : m_pImpl->m_oSoftDelete); } + + bool IxSqlQueryBuilder::getCartesianProduct() const { return m_pImpl->m_bCartesianProduct; } + + long IxSqlQueryBuilder::getDataCount() const { return (m_pImpl->m_lstDataMemberPtr ? m_pImpl->m_lstDataMemberPtr->count() : 0); } + + long IxSqlQueryBuilder::getRelationCount() const { return (m_pImpl->m_lstSqlRelationPtr ? m_pImpl->m_lstSqlRelationPtr->count() : 0); } + + IxDataMember *IxSqlQueryBuilder::getDataId() const { return m_pImpl->m_pDataMemberId; } + + IxDataMember *IxSqlQueryBuilder::nextData(long &l) const + { + if ((!m_pImpl->m_lstDataMemberPtr) || (l < 0) || (l >= m_pImpl->m_lstDataMemberPtr->count())) + { + return NULL; + }; + ++l; + return m_pImpl->m_lstDataMemberPtr->getByIndex(l - 1); + } + + IxSqlRelation *IxSqlQueryBuilder::nextRelation(long &l) const + { + if ((!m_pImpl->m_lstSqlRelationPtr) || (l < 0) || (l >= m_pImpl->m_lstSqlRelationPtr->count())) + { + return NULL; + }; + ++l; + return m_pImpl->m_lstSqlRelationPtr->getByIndex(l - 1); + } + + QString &IxSqlQueryBuilder::getCurrentBuildingSql() const { return m_pImpl->m_sCurrentBuildingSql; } + + bool IxSqlQueryBuilder::isInitDone() const { return m_pImpl->m_bInitDone; } + + QxSoftDelete &IxSqlQueryBuilder::softDelete() { return (m_pImpl->checkIgnoreSoftDelete() ? m_pImpl->m_oSoftDeleteEmpty : m_pImpl->m_oSoftDelete); } + + const QxSoftDelete &IxSqlQueryBuilder::softDelete() const { return (m_pImpl->checkIgnoreSoftDelete() ? m_pImpl->m_oSoftDeleteEmpty : m_pImpl->m_oSoftDelete); } + + void IxSqlQueryBuilder::setSoftDelete(const QxSoftDelete &o) { m_pImpl->m_oSoftDelete = o; } + + void IxSqlQueryBuilder::setDataMemberX(IxDataMemberX *p) { m_pImpl->m_pDataMemberX = p; } + + void IxSqlQueryBuilder::clone(const IxSqlQueryBuilder &other) + { + this->m_pImpl->m_lstDataMemberPtr = other.m_pImpl->m_lstDataMemberPtr; + this->m_pImpl->m_lstSqlRelationPtr = other.m_pImpl->m_lstSqlRelationPtr; + this->m_pImpl->m_pDataMemberId = other.m_pImpl->m_pDataMemberId; + this->m_pImpl->m_sSqlQuery = other.m_pImpl->m_sSqlQuery; + this->m_pImpl->m_sTableName = other.m_pImpl->m_sTableName; + this->m_pImpl->m_sHashRelation = other.m_pImpl->m_sHashRelation; + this->m_pImpl->m_bCartesianProduct = other.m_pImpl->m_bCartesianProduct; + this->m_pImpl->m_pIdX = other.m_pImpl->m_pIdX; + this->m_pImpl->m_oSoftDelete = other.m_pImpl->m_oSoftDelete; + this->m_pImpl->m_lstSqlQueryAlias = other.m_pImpl->m_lstSqlQueryAlias; + this->m_pImpl->m_pDaoHelper = other.m_pImpl->m_pDaoHelper; + this->m_pImpl->m_pDataMemberX = other.m_pImpl->m_pDataMemberX; + } + + void IxSqlQueryBuilder::init() + { + if (!m_pImpl->m_pDataMemberX || !m_pImpl->m_pDataMemberX->getClass() || m_pImpl->m_bInitDone) + { + return; + } + m_pImpl->m_pDataMemberId = m_pImpl->m_pDataMemberX->getId_WithDaoStrategy(); + m_pImpl->m_sTableName = m_pImpl->m_pDataMemberX->getName(); + m_pImpl->m_lstDataMemberPtr = m_pImpl->m_pDataMemberX->getClass()->getSqlDataMemberX(); + m_pImpl->m_lstSqlRelationPtr = m_pImpl->m_pDataMemberX->getClass()->getSqlRelationX(); + m_pImpl->m_bInitDone = true; + } + + void IxSqlQueryBuilder::setSqlQuery(const QString &sql, const QString &key /* = QString() */) + { + m_pImpl->m_sSqlQuery = sql; + if (!key.isEmpty()) + { + QMutexLocker locker(&IxSqlQueryBuilderImpl::m_mutex); + IxSqlQueryBuilderImpl::m_lstSqlQuery.insert(key, sql); + } + } + + bool IxSqlQueryBuilder::findSqlQuery(const QString &key) + { + if (key.isEmpty()) + { + return false; + } + QMutexLocker locker(&IxSqlQueryBuilderImpl::m_mutex); + QString sql = IxSqlQueryBuilderImpl::m_lstSqlQuery.value(key); + if (!sql.isEmpty()) + { + m_pImpl->m_sSqlQuery = sql; + } + return (!sql.isEmpty()); + } + + bool IxSqlQueryBuilder::findSqlAlias(const QString &key) + { + if (key.isEmpty()) + { + return false; + } + QMutexLocker locker(&IxSqlQueryBuilderImpl::m_mutex); + if (!IxSqlQueryBuilderImpl::m_lstSqlAlias.contains(key)) + { + return false; + } + m_pImpl->m_lstSqlQueryAlias = IxSqlQueryBuilderImpl::m_lstSqlAlias.value(key); + return true; + } + + void IxSqlQueryBuilder::insertSqlAlias(const QString &key) + { + if (key.isEmpty()) + { + return; + } + QMutexLocker locker(&IxSqlQueryBuilderImpl::m_mutex); + IxSqlQueryBuilderImpl::m_lstSqlAlias.insert(key, m_pImpl->m_lstSqlQueryAlias); + } + + void IxSqlQueryBuilder::initIdX(long lAllRelationCount) + { + if (!m_pImpl->m_bCartesianProduct) + { + qAssert(false); + return; + } + m_pImpl->m_pIdX = std::make_shared(); + for (long l = 0; l < (lAllRelationCount + 1); ++l) + { + IxSqlQueryBuilderImpl::type_ptr_by_id_ptr pItem = IxSqlQueryBuilderImpl::type_ptr_by_id_ptr(new IxSqlQueryBuilderImpl::type_ptr_by_id()); + m_pImpl->m_pIdX->append(pItem); + } + } + + bool IxSqlQueryBuilder::insertIdX(long lIndex, const QVariant &idOwner, const QVariant &idData, void *ptr) + { + QString sIdOwner = idOwner.toString(); + QString sIdData = idData.toString(); + if (!m_pImpl->m_pIdX || sIdOwner.isEmpty() || sIdData.isEmpty()) + { + qAssert(false); + return false; + } + if ((lIndex < 0) || (lIndex >= m_pImpl->m_pIdX->count())) + { + qAssert(false); + return false; + } + + IxSqlQueryBuilderImpl::type_id idX(sIdOwner, sIdData); + IxSqlQueryBuilderImpl::type_ptr_by_id_ptr pHash = m_pImpl->m_pIdX->at(lIndex); + if (!ptr || !pHash || pHash->contains(idX)) + { + qAssert(false); + return false; + } + pHash->insert(idX, ptr); + + return true; + } + + void *IxSqlQueryBuilder::existIdX(long lIndex, const QVariant &idOwner, const QVariant &idData) + { + QString sIdOwner = idOwner.toString(); + QString sIdData = idData.toString(); + if (!m_pImpl->m_pIdX || sIdOwner.isEmpty() || sIdData.isEmpty()) + { + qAssert(false); + return NULL; + } + if ((lIndex < 0) || (lIndex >= m_pImpl->m_pIdX->count())) + { + qAssert(false); + return NULL; + } + + IxSqlQueryBuilderImpl::type_id idX(sIdOwner, sIdData); + IxSqlQueryBuilderImpl::type_ptr_by_id_ptr pHash = m_pImpl->m_pIdX->at(lIndex); + if (!pHash || !pHash->contains(idX)) + { + return NULL; + } + + return pHash->value(idX); + } + + bool IxSqlQueryBuilder::getAddAutoIncrementIdToUpdateQuery() const + { + return qx::QxSqlDatabase::getSingleton()->getAddAutoIncrementIdToUpdateQuery(); + } + + void IxSqlQueryBuilder::addSqlQueryAlias(const QString &sql, const QString &sqlAlias) + { + m_pImpl->m_lstSqlQueryAlias.insert(sql, sqlAlias); + } + + void IxSqlQueryBuilder::replaceSqlQueryAlias(QString &sql) const + { + if (!qx::QxSqlDatabase::getSingleton()->getAutoReplaceSqlAliasIntoQuery()) + { + return; + } + if (m_pImpl->m_lstSqlQueryAlias.count() <= 0) + { + return; + } + QHashIterator itr(m_pImpl->m_lstSqlQueryAlias); + sql = (" " + sql); + while (itr.hasNext()) + { + itr.next(); + QString sBefore = (" " + itr.key() + "."); + QString sAfter = (" " + itr.value() + "."); + sql.replace(sBefore, sAfter); + } + sql = sql.trimmed(); + } + + bool IxSqlQueryBuilder::verifyColumns(const QStringList &columns) const + { +#ifdef _QX_MODE_DEBUG + if (!m_pImpl->m_pDataMemberX) + { + qAssert(false); + return false; + } + for (int i = 0; i < columns.count(); i++) + { + if (!m_pImpl->m_pDataMemberX->exist_WithDaoStrategy(columns.at(i))) + { + QString sErrorMsg = QString("column '%1' not found in table '%2'").arg(columns.at(i), m_pImpl->m_sTableName); + qDebug("[QxOrm] Error in qx::IxSqlQueryBuilder::verifyColumns() : %s", qPrintable(sErrorMsg)); + qAssertMsg(false, "[QxOrm] qx::IxSqlQueryBuilder::verifyColumns()", qPrintable(sErrorMsg)); + return false; + } + } + return true; +#else // _QX_MODE_DEBUG + Q_UNUSED(columns); + return true; +#endif // _QX_MODE_DEBUG + } + + void IxSqlQueryBuilder::sql_CreateTable(QString &sql, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxSqlRelation *pRelation = NULL; + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "CREATE TABLE " + qx::IxDataMember::getSqlTableName(table) + " ("; + int iSqlCountRef = sql.length(); + if (pId) + { + sql += pId->getSqlNameAndTypeAndParams(", ") + ", "; + qAssert(!pId->getSqlType().isEmpty()); + } + while ((p = builder.nextData(l1))) + { + sql += p->getSqlNameAndTypeAndParams(", ") + ", "; + qAssert(!p->getSqlType().isEmpty()); + } + if (!oSoftDelete.isEmpty()) + { + sql += oSoftDelete.buildSqlQueryToCreateTable() + ", "; + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->createTable(params); + } + bool bAddBracket = (sql.length() != iSqlCountRef); + sql = sql.left(sql.length() - 2); // Remove last ", " + if (bAddBracket) + { + sql += ")"; + } + } + + void IxSqlQueryBuilder::sql_DeleteById(QString &sql, IxSqlQueryBuilder &builder, bool bSoftDelete) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + if (bSoftDelete && !oSoftDelete.isEmpty()) + { + sql = "UPDATE " + qx::IxDataMember::getSqlTableName(table) + " SET " + oSoftDelete.buildSqlQueryToUpdate(); + } + else + { + sql = "DELETE FROM " + qx::IxDataMember::getSqlFromTable(table); + } + sql += IxSqlQueryBuilder::addSqlCondition(sql); + sql += pId->getSqlNameEqualToPlaceHolder("", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_Exist(QString &sql, IxSqlQueryBuilder &builder) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "SELECT "; + if (pId) + { + sql += pId->getSqlTablePointNameAsAlias(table, ", ", "", false, "", (&builder)); + } + if (!oSoftDelete.isEmpty()) + { + sql += ", " + oSoftDelete.buildSqlTablePointName(); + } + sql += " FROM " + qx::IxDataMember::getSqlFromTable(table); + sql += " WHERE " + pId->getSqlAliasEqualToPlaceHolder(table, true, "", " AND ", false, (&builder)); + if (!oSoftDelete.isEmpty()) + { + sql += " AND " + oSoftDelete.buildSqlQueryToFetch(); + } + } + + void IxSqlQueryBuilder::sql_FetchAll(QString &sql, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0), l3(0), l4(0), l5(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxSqlRelation *pRelation = NULL; + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "SELECT "; + bool isDistinct = (builder.getDaoHelper() ? builder.getDaoHelper()->isDistinct() : false); + if (pId && (!isDistinct)) + { + sql += (pId->getSqlTablePointNameAsAlias(table, ", ", "", false, "", (&builder)) + ", "); + } + while ((p = builder.nextData(l1))) + { + sql += (p->getSqlTablePointNameAsAlias(table, ", ", "", false, "", (&builder)) + ", "); + } + if (!oSoftDelete.isEmpty()) + { + l1++; + sql += (oSoftDelete.buildSqlTablePointName() + ", "); + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazySelect(params); + } + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += " FROM " + qx::IxDataMember::getSqlFromTable(table) + ", "; + while ((pRelation = builder.nextRelation(l3))) + { + params.setIndex(l3); + pRelation->lazyFrom(params); + } + sql = sql.left(sql.length() - 2); // Remove last ", " + while ((pRelation = builder.nextRelation(l4))) + { + params.setIndex(l4); + pRelation->lazyJoin(params); + } + if (!oSoftDelete.isEmpty()) + { + sql += " WHERE " + oSoftDelete.buildSqlQueryToFetch(); + } + while ((pRelation = builder.nextRelation(l5))) + { + params.setIndex(l5); + pRelation->lazyWhereSoftDelete(params); + } + } + + void IxSqlQueryBuilder::sql_FetchAll(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns) + { + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxDataMemberX *pDataMemberX = builder.getDataMemberX(); + qAssert(pDataMemberX); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "SELECT "; + bool isDistinct = (builder.getDaoHelper() ? builder.getDaoHelper()->isDistinct() : false); + if (pId && (!isDistinct)) + { + sql += (pId->getSqlTablePointNameAsAlias(table, ", ", "", false, "", (&builder)) + ", "); + } + for (int i = 0; i < columns.count(); i++) + { + p = pDataMemberX->get_WithDaoStrategy(columns.at(i)); + if (p && (p != pId)) + { + sql += (p->getSqlTablePointNameAsAlias(table, ", ", "", false, "", (&builder)) + ", "); + } + } + sql = sql.left(sql.length() - 2); // Remove last ", " + if (!oSoftDelete.isEmpty()) + { + sql += ", " + oSoftDelete.buildSqlTablePointName(); + } + sql += " FROM " + qx::IxDataMember::getSqlFromTable(table); + if (!oSoftDelete.isEmpty()) + { + sql += " WHERE " + oSoftDelete.buildSqlQueryToFetch(); + } + } + + void IxSqlQueryBuilder::sql_FetchAll_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder) + { + long l(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "SELECT "; + bool isDistinct = (builder.getDaoHelper() ? builder.getDaoHelper()->isDistinct() : false); + bool bForceRootId = ((isDistinct && pId) ? pRelationX->checkRootColumns(pId->getKey()) : false); + if (pId && ((!isDistinct) || (bForceRootId))) + { + sql += (pId->getSqlTablePointNameAsAlias(table, ", ", "", false, pRelationX->getRootCustomAlias(), (&builder)) + ", "); + } + while ((p = builder.nextData(l))) + { + if (pRelationX->checkRootColumns(p->getKey())) + { + sql += (p->getSqlTablePointNameAsAlias(table, ", ", "", false, pRelationX->getRootCustomAlias(), (&builder)) + ", "); + } + } + if (!oSoftDelete.isEmpty()) + { + l++; + sql += (oSoftDelete.buildSqlTablePointName(pRelationX->getRootCustomAlias()) + ", "); + } + pRelationX->hierarchySelect(params); + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += " FROM " + qx::IxDataMember::getSqlFromTable(table, pRelationX->getRootCustomAlias()) + ", "; + pRelationX->hierarchyFrom(params); + sql = sql.left(sql.length() - 2); // Remove last ", " + pRelationX->hierarchyJoin(params); + if (!oSoftDelete.isEmpty()) + { + sql += " WHERE " + oSoftDelete.buildSqlQueryToFetch(pRelationX->getRootCustomAlias()); + } + pRelationX->hierarchyWhereSoftDelete(params); + } + + void IxSqlQueryBuilder::sql_FetchById(QString &sql, IxSqlQueryBuilder &builder) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + QString table = builder.table(); + sql = builder.buildSql().getSqlQuery(); + sql += IxSqlQueryBuilder::addSqlCondition(sql); + sql += pId->getSqlAliasEqualToPlaceHolder(table, true, "", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_FetchById(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + QString table = builder.table(); + sql = builder.buildSql(columns).getSqlQuery(); + sql += IxSqlQueryBuilder::addSqlCondition(sql); + sql += pId->getSqlAliasEqualToPlaceHolder(table, true, "", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_FetchById_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + QString table = builder.table(); + QStringList columns; + sql = builder.buildSql(columns, pRelationX).getSqlQuery(); + QString tableAlias = (pRelationX ? pRelationX->getRootCustomAlias() : QString()); + if (tableAlias.isEmpty()) + { + tableAlias = table; + } + sql += IxSqlQueryBuilder::addSqlCondition(sql); + sql += pId->getSqlAliasEqualToPlaceHolder(tableAlias, true, "", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_Insert(QString &sql, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxSqlRelation *pRelation = NULL; + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + QString table = builder.table(); + QString tmp; + sql = "INSERT INTO " + qx::IxDataMember::getSqlTableName(table) + " ("; + if (pId && !pId->getAutoIncrement()) + { + tmp = pId->getSqlName(", ", "", true, (&builder)); + if (!tmp.isEmpty()) + { + sql += tmp + ", "; + } + } + while ((p = builder.nextData(l1))) + { + sql += p->getSqlName(", ", "", false, (&builder)) + ", "; + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyInsert(params); + } + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += ") VALUES ("; + l1 = 0; + l2 = 0; + p = NULL; + pRelation = NULL; + if (pId && !pId->getAutoIncrement()) + { + tmp = pId->getSqlPlaceHolder("", -1, ", ", "", true); + if (!tmp.isEmpty()) + { + sql += tmp + ", "; + } + } + while ((p = builder.nextData(l1))) + { + sql += p->getSqlPlaceHolder("", -1, ", ") + ", "; + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyInsert_Values(params); + } + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += ")"; + } + + void IxSqlQueryBuilder::sql_Update(QString &sql, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::IxSqlRelation *pRelation = NULL; + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + QString table = builder.table(); + QString tmp; + sql = "UPDATE " + qx::IxDataMember::getSqlTableName(table) + " SET "; + if (!pId->getAutoIncrement() || (pId->getAutoIncrement() && builder.getAddAutoIncrementIdToUpdateQuery())) + { + tmp = pId->getSqlNameEqualToPlaceHolder("", ", ", true, (&builder)); + if (!tmp.isEmpty()) + { + sql += tmp + ", "; + } + } + while ((p = builder.nextData(l1))) + { + sql += p->getSqlNameEqualToPlaceHolder("", ", ", false, (&builder)) + ", "; + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyUpdate(params); + } + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += " WHERE " + pId->getSqlNameEqualToPlaceHolder("_bis", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_Update(QString &sql, IxSqlQueryBuilder &builder, const QStringList &columns) + { + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::IxDataMemberX *pDataMemberX = builder.getDataMemberX(); + qAssert(pDataMemberX); + QString table = builder.table(); + sql = "UPDATE " + qx::IxDataMember::getSqlTableName(table) + " SET "; + if (!pId->getAutoIncrement() || (pId->getAutoIncrement() && builder.getAddAutoIncrementIdToUpdateQuery())) + { + sql += pId->getSqlNameEqualToPlaceHolder("", ", ", false, (&builder)) + ", "; + } + for (int i = 0; i < columns.count(); i++) + { + p = pDataMemberX->get_WithDaoStrategy(columns.at(i)); + if (p && (p != pId)) + { + sql += p->getSqlNameEqualToPlaceHolder("", ", ", false, (&builder)) + ", "; + } + } + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += " WHERE " + pId->getSqlNameEqualToPlaceHolder("_bis", " AND ", false, (&builder)); + } + + void IxSqlQueryBuilder::sql_Count_WithRelation(qx::QxSqlRelationLinked *pRelationX, QString &sql, IxSqlQueryBuilder &builder) + { + if (!pRelationX) + { + qAssert(false); + return; + } + qx::QxSqlRelationParams params(0, 0, (&sql), (&builder), NULL, NULL); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + QString table = builder.table(); + sql = "SELECT COUNT(*) FROM " + qx::IxDataMember::getSqlFromTable(table, pRelationX->getRootCustomAlias()) + ", "; + pRelationX->hierarchyFrom(params); + sql = sql.left(sql.length() - 2); // Remove last ", " + pRelationX->hierarchyJoin(params); + if (!oSoftDelete.isEmpty()) + { + sql += " WHERE " + oSoftDelete.buildSqlQueryToFetch(pRelationX->getRootCustomAlias()); + } + pRelationX->hierarchyWhereSoftDelete(params); + } + + void IxSqlQueryBuilder::resolveOutput_FetchAll(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxSqlRelation *pRelation = NULL; + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + bool isDistinct = (builder.getDaoHelper() ? builder.getDaoHelper()->isDistinct() : false); + short iOffset = ((pId && (!isDistinct)) ? pId->getNameCount() : 0); + if (pId && (!isDistinct)) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + pId->fromVariant(t, query.value(i), i, qx::cvt::context::e_database); + } + } + while ((p = builder.nextData(l1))) + { + p->fromVariant(t, query.value(l1 + iOffset - 1), -1, qx::cvt::context::e_database); + } + iOffset = (builder.getDataCount() + iOffset + (oSoftDelete.isEmpty() ? 0 : 1)); + qx::QxSqlRelationParams params(0, iOffset, NULL, (&builder), (&query), t); + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyFetch_ResolveOutput(params); + } + } + + void IxSqlQueryBuilder::resolveOutput_FetchAll(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder, const QStringList &columns) + { + qx::IxDataMember *p = NULL; + int idx = 0; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxDataMemberX *pDataMemberX = builder.getDataMemberX(); + qAssert(pDataMemberX); + bool isDistinct = (builder.getDaoHelper() ? builder.getDaoHelper()->isDistinct() : false); + short iOffset = ((pId && (!isDistinct)) ? pId->getNameCount() : 0); + if (pId && (!isDistinct)) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + pId->fromVariant(t, query.value(i), i, qx::cvt::context::e_database); + } + } + for (int i = 0; i < columns.count(); i++) + { + p = pDataMemberX->get_WithDaoStrategy(columns.at(i)); + if (p && (p != pId)) + { + p->fromVariant(t, query.value(idx + iOffset), -1, qx::cvt::context::e_database); + idx++; + } + } + } + + void IxSqlQueryBuilder::resolveOutput_FetchAll_WithRelation(qx::QxSqlRelationLinked *pRelationX, void *t, QSqlQuery &query, IxSqlQueryBuilder &builder) + { + long l(0); + long lCurrIndex(0); + QVariant vId; + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::QxSoftDelete oSoftDelete = builder.getSoftDelete(); + qx::dao::detail::IxDao_Helper *pDaoHelper = builder.getDaoHelper(); + bool isDistinct = (pDaoHelper ? pDaoHelper->isDistinct() : false); + bool bForceRootId = ((isDistinct && pId) ? pRelationX->checkRootColumns(pId->getKey()) : false); + short iOffsetId = ((pId && ((!isDistinct) || (bForceRootId))) ? pId->getNameCount() : 0); + vId = (pDaoHelper ? pDaoHelper->getIdFromQuery(-1) : QVariant()); + bool bComplex = builder.getCartesianProduct(); + bool bByPass = (bComplex && builder.existIdX(0, vId, vId)); + + if (!bByPass) + { + if (pId && ((!isDistinct) || (bForceRootId))) + { + for (int i = 0; i < pId->getNameCount(); i++) + { + pId->fromVariant(t, query.value(i), i, qx::cvt::context::e_database); + } + } + while ((p = builder.nextData(l))) + { + if (pRelationX->checkRootColumns(p->getKey())) + { + p->fromVariant(t, query.value(lCurrIndex + iOffsetId), -1, qx::cvt::context::e_database); + lCurrIndex++; + } + } + if (bComplex) + { + builder.insertIdX(0, vId, vId, t); + } + } + + short iOffset = (builder.getDataCount() + iOffsetId + (oSoftDelete.isEmpty() ? 0 : 1)); + if ((pRelationX->getRootColumnsCount() > 0) && (pRelationX->getRootColumnsOffset() > 0)) + { + iOffset = (iOffset - pRelationX->getRootColumnsOffset()); + } + else if (pRelationX->getRootColumnsCount() > 0) + { + l = 0; + p = NULL; + long lRootColumnsOffset = 0; + while ((p = builder.nextData(l))) + { + if (!pRelationX->checkRootColumns(p->getKey())) + { + iOffset = (iOffset - 1); + lRootColumnsOffset++; + } + } + pRelationX->setRootColumnsOffset(lRootColumnsOffset); + } + + qx::QxSqlRelationParams params(0, iOffset, NULL, (&builder), (&query), t, vId); + pRelationX->hierarchyResolveOutput(params); + } + + void IxSqlQueryBuilder::resolveInput_Insert(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qx::IxSqlRelation *pRelation = NULL; + bool bUseExecBatch = (builder.getDaoHelper() ? builder.getDaoHelper()->getUseExecBatch() : false); + qx::QxCollection *pLstExecBatch = (bUseExecBatch ? (&builder.getDaoHelper()->getListExecBatch()) : NULL); + qx::QxSqlRelationParams params(0, 0, NULL, (&builder), (&query), t, QVariant(), pLstExecBatch); + if (pId && !pId->getAutoIncrement()) + { + pId->setSqlPlaceHolder(query, t, "", "", true, pLstExecBatch); + } + while ((p = builder.nextData(l1))) + { + p->setSqlPlaceHolder(query, t, "", "", false, pLstExecBatch); + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyInsert_ResolveInput(params); + } + } + + void IxSqlQueryBuilder::resolveInput_Update(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder) + { + long l1(0), l2(0); + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::IxSqlRelation *pRelation = NULL; + bool bUseExecBatch = (builder.getDaoHelper() ? builder.getDaoHelper()->getUseExecBatch() : false); + qx::QxCollection *pLstExecBatch = (bUseExecBatch ? (&builder.getDaoHelper()->getListExecBatch()) : NULL); + qx::QxSqlRelationParams params(0, 0, NULL, (&builder), (&query), t, QVariant(), pLstExecBatch); + if (!pId->getAutoIncrement() || (pId->getAutoIncrement() && builder.getAddAutoIncrementIdToUpdateQuery())) + { + pId->setSqlPlaceHolder(query, t, "", "", true, pLstExecBatch); + } + while ((p = builder.nextData(l1))) + { + p->setSqlPlaceHolder(query, t, "", "", false, pLstExecBatch); + } + while ((pRelation = builder.nextRelation(l2))) + { + params.setIndex(l2); + pRelation->lazyUpdate_ResolveInput(params); + } + pId->setSqlPlaceHolder(query, t, "_bis", "", false, pLstExecBatch); + } + + void IxSqlQueryBuilder::resolveInput_Update(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder, const QStringList &columns) + { + qx::IxDataMember *p = NULL; + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + qx::IxDataMemberX *pDataMemberX = builder.getDataMemberX(); + qAssert(pDataMemberX); + bool bUseExecBatch = (builder.getDaoHelper() ? builder.getDaoHelper()->getUseExecBatch() : false); + qx::QxCollection *pLstExecBatch = (bUseExecBatch ? (&builder.getDaoHelper()->getListExecBatch()) : NULL); + if (!pId->getAutoIncrement() || (pId->getAutoIncrement() && builder.getAddAutoIncrementIdToUpdateQuery())) + { + pId->setSqlPlaceHolder(query, t, "", "", false, pLstExecBatch); + } + for (int i = 0; i < columns.count(); i++) + { + p = pDataMemberX->get_WithDaoStrategy(columns.at(i)); + if (p && (p != pId)) + { + p->setSqlPlaceHolder(query, t, "", "", false, pLstExecBatch); + } + } + pId->setSqlPlaceHolder(query, t, "_bis", "", false, pLstExecBatch); + } + + void IxSqlQueryBuilder::resolveInput_DeleteById(void *t, QSqlQuery &query, IxSqlQueryBuilder &builder) + { + qx::IxDataMember *pId = builder.getDataId(); + qAssert(pId); + bool bUseExecBatch = (builder.getDaoHelper() ? builder.getDaoHelper()->getUseExecBatch() : false); + qx::QxCollection *pLstExecBatch = (bUseExecBatch ? (&builder.getDaoHelper()->getListExecBatch()) : NULL); + pId->setSqlPlaceHolder(query, t, "", "", false, pLstExecBatch); + } + +} // namespace qx diff --git a/src/QxDao/IxSqlRelation.cpp b/src/QxDao/IxSqlRelation.cpp new file mode 100644 index 0000000..3376501 --- /dev/null +++ b/src/QxDao/IxSqlRelation.cpp @@ -0,0 +1,1486 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) +#define QX_CONSTRUCT_IX_RELATION_MUTEX() m_mutex() +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) +#define QX_CONSTRUCT_IX_RELATION_MUTEX() m_mutex(QMutex::Recursive) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + +#define QX_CONSTRUCT_IX_RELATION() \ + m_pClass(NULL), m_pClassOwner(NULL), m_pDataMember(p), m_pDataMemberX(NULL), \ + m_pDataMemberId(NULL), m_pDataMemberIdOwner(NULL), m_lOffsetRelation(100), \ + m_eJoinType(qx::dao::sql_join::left_outer_join), m_eRelationType(IxSqlRelation::no_relation), \ + m_bInitInEvent(false), m_bInitDone(false), m_iIsSameDataOwner(0), m_pLinkRelationKey(NULL), QX_CONSTRUCT_IX_RELATION_MUTEX() + +namespace qx +{ + + struct Q_DECL_HIDDEN IxSqlRelation::IxSqlRelationImpl + { + + typedef QxCollection type_lst_data_member; + typedef std::shared_ptr type_lst_data_member_ptr; + + IxClass *m_pClass; //!< 'IxClass' associated wth sql relation (relation target) + IxClass *m_pClassOwner; //!< 'IxClass' of the owner (relation source) + IxDataMember *m_pDataMember; //!< 'IxDataMember' associated wth sql relation + IxDataMemberX *m_pDataMemberX; //!< Collection of 'IxDataMember' : parent of 'm_pDataMember' + IxDataMember *m_pDataMemberId; //!< 'IxDataMember' id of 'm_pDataMemberX' + IxDataMember *m_pDataMemberIdOwner; //!< 'IxDataMember' id of the owner + long m_lOffsetRelation; //!< Generic offset for sql relation + qx::dao::sql_join::join_type m_eJoinType; //!< Join type to build sql query + IxSqlRelation::relation_type m_eRelationType; //!< Relation type : one-to-one, one-to-many, etc. + QxSoftDelete m_oSoftDelete; //!< Soft delete (or logical delete) behavior + QxSoftDelete m_oSoftDeleteEmpty; //!< Keep an empty soft delete instance (used with qx::QxSession::ignoreSoftDelete()) + QString m_sForeignKey; //!< SQL query foreign key (1-n) + QString m_sExtraTable; //!< Extra-table that holds the relationship (n-n) + QString m_sForeignKeyOwner; //!< SQL query foreign key for owner (n-n) + QString m_sForeignKeyDataType; //!< SQL query foreign key for data type (n-n) + bool m_bInitInEvent; //!< Class initialization in progress + bool m_bInitDone; //!< Class initialization finished + int m_iIsSameDataOwner; //!< Check if relationship source entity and target entity are equal + IxDataMember *m_pLinkRelationKey; //!< Link relation key to another data member (used by MongoDB to simulate lazy loading) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QRecursiveMutex m_mutex; //!< Mutex => 'qx::IxSqlRelation' is thread-safe (initialization process) +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QMutex m_mutex; //!< Mutex => 'qx::IxSqlRelation' is thread-safe (initialization process) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + + type_lst_data_member_ptr m_lstDataMemberPtr; //!< Optimization : handle to collection of 'IxDataMember' + std::shared_ptr m_lstSqlRelationPtr; //!< Optimization : handle to collection of 'IxSqlRelation' + + static bool m_bTraceRelationInit; //!< Can be useful to debug an issue with relationship initialization + + IxSqlRelationImpl(IxDataMember *p) : QX_CONSTRUCT_IX_RELATION() { ; } + ~IxSqlRelationImpl() { ; } + + IxDataMember *isValid_DataMember(long lIndex) const + { + if (!m_pDataMemberX) + { + return NULL; + } + IxDataMember *p = m_pDataMemberX->get_WithDaoStrategy(lIndex); + bool bValid = (p && p->getDao() && !p->hasSqlRelation()); + bValid = (bValid && (p != m_pDataMemberId)); + return (bValid ? p : NULL); + } + + IxDataMember *isValid_SqlRelation(long lIndex) const + { + if (!m_pDataMemberX) + { + return NULL; + } + IxDataMember *p = m_pDataMemberX->get_WithDaoStrategy(lIndex); + bool bIsValid = (p && p->getDao() && p->hasSqlRelation()); + if (bIsValid && (!m_iIsSameDataOwner) && (p != m_pDataMember)) + { + p->getSqlRelation()->init(); + } + return (bIsValid ? p : NULL); + } + + const QxSoftDelete &getSoftDelete(QxSqlRelationParams ¶ms) const + { + qx::IxSqlQueryBuilder &builder = params.builder(); + qx::dao::detail::IxDao_Helper *pDaoHelper = builder.getDaoHelper(); + qx::QxSession *pSession = (pDaoHelper ? pDaoHelper->getSession() : NULL); + if ((!pSession) || (!m_pClass)) + { + return m_oSoftDelete; + } + bool bIgnoreSoftDelete = pSession->checkIgnoreSoftDelete(m_pClass->getKey()); + return (bIgnoreSoftDelete ? m_oSoftDeleteEmpty : m_oSoftDelete); + } + }; + + bool IxSqlRelation::IxSqlRelationImpl::m_bTraceRelationInit = false; + + IxSqlRelation::IxSqlRelation(IxDataMember *p) : qx::QxPropertyBag(), m_pImpl(new IxSqlRelationImpl(p)) { ; } + + IxSqlRelation::~IxSqlRelation() { ; } + + QString IxSqlRelation::getForeignKey() const { return m_pImpl->m_sForeignKey; } + + QString IxSqlRelation::getForeignKeyOwner() const { return m_pImpl->m_sForeignKeyOwner; } + + QString IxSqlRelation::getForeignKeyDataType() const { return m_pImpl->m_sForeignKeyDataType; } + + QString IxSqlRelation::getExtraTable() const { return m_pImpl->m_sExtraTable; } + + QxCollection *IxSqlRelation::getLstDataMember() const { return m_pImpl->m_lstDataMemberPtr.get(); } + + IxSqlRelationX *IxSqlRelation::getLstRelation() const { return m_pImpl->m_lstSqlRelationPtr.get(); } + + void IxSqlRelation::setSqlJoinType(qx::dao::sql_join::join_type e) { m_pImpl->m_eJoinType = e; } + + qx::dao::sql_join::join_type IxSqlRelation::getSqlJoinType() const { return m_pImpl->m_eJoinType; } + + IxSqlRelation::relation_type IxSqlRelation::getRelationType() const { return m_pImpl->m_eRelationType; } + + IxClass *IxSqlRelation::getClass() const { return m_pImpl->m_pClass; } + + IxClass *IxSqlRelation::getClassOwner() const { return m_pImpl->m_pClassOwner; } + + IxDataMember *IxSqlRelation::getDataMember() const { return m_pImpl->m_pDataMember; } + + IxDataMemberX *IxSqlRelation::getDataMemberX() const { return m_pImpl->m_pDataMemberX; } + + IxDataMember *IxSqlRelation::getDataId() const { return m_pImpl->m_pDataMemberId; } + + IxDataMember *IxSqlRelation::getDataIdOwner() const { return m_pImpl->m_pDataMemberIdOwner; } + + void IxSqlRelation::linkRelationKeyTo(IxDataMember *p) { m_pImpl->m_pLinkRelationKey = p; } + + IxDataMember *IxSqlRelation::getLinkRelationKey() const { return m_pImpl->m_pLinkRelationKey; } + + void IxSqlRelation::setIsSameDataOwner(int i) { m_pImpl->m_iIsSameDataOwner = i; } + + bool IxSqlRelation::canInit() const + { + if (m_pImpl->m_bInitDone) + { + return false; + } + { + QMutexLocker locker(&m_pImpl->m_mutex); + return (!m_pImpl->m_bInitInEvent); + } + } + + void IxSqlRelation::setClass(IxClass *pClass, IxClass *pClassOwner) + { + m_pImpl->m_pClass = pClass; + m_pImpl->m_pClassOwner = pClassOwner; + } + + void IxSqlRelation::setRelationType(IxSqlRelation::relation_type e) { m_pImpl->m_eRelationType = e; } + + void IxSqlRelation::setForeignKey(const QString &s) const { m_pImpl->m_sForeignKey = s; } + + void IxSqlRelation::setForeignKeyOwner(const QString &s) const { m_pImpl->m_sForeignKeyOwner = s; } + + void IxSqlRelation::setForeignKeyDataType(const QString &s) const { m_pImpl->m_sForeignKeyDataType = s; } + + void IxSqlRelation::setExtraTable(const QString &s) const { m_pImpl->m_sExtraTable = s; } + + void IxSqlRelation::init() + { + QMutexLocker locker(&m_pImpl->m_mutex); + if (m_pImpl->m_bInitInEvent || m_pImpl->m_bInitDone) + { + return; + } + m_pImpl->m_bInitInEvent = true; + + m_pImpl->m_pDataMemberX = (m_pImpl->m_pClass ? m_pImpl->m_pClass->getDataMemberX() : NULL); + m_pImpl->m_pDataMemberId = (m_pImpl->m_pDataMemberX ? m_pImpl->m_pDataMemberX->getId_WithDaoStrategy() : NULL); + m_pImpl->m_pDataMemberIdOwner = ((m_pImpl->m_pClassOwner && m_pImpl->m_pClassOwner->getDataMemberX()) ? m_pImpl->m_pClassOwner->getDataMemberX()->getId_WithDaoStrategy() : NULL); + if (m_pImpl->m_pClass) + { + m_pImpl->m_oSoftDelete = m_pImpl->m_pClass->getSoftDelete(); + } + +#ifdef _QX_MODE_DEBUG + QString sCheckMsg = "Check relationship '" + this->getKey() + "' from '" + (m_pImpl->m_pClassOwner ? m_pImpl->m_pClassOwner->getKey() : QString()) + "' to '" + (m_pImpl->m_pClass ? m_pImpl->m_pClass->getKey() : QString()) + "'"; + if (!m_pImpl->m_pClass) + { + QString sAssertMsg = sCheckMsg + " : m_pImpl->m_pClass is equal to NULL"; + qAssertMsg(false, "[QxOrm] qx::IxSqlRelation::init()", qPrintable(sAssertMsg)); + } + if (!m_pImpl->m_pClassOwner) + { + QString sAssertMsg = sCheckMsg + " : m_pImpl->m_pClassOwner is equal to NULL"; + qAssertMsg(false, "[QxOrm] qx::IxSqlRelation::init()", qPrintable(sAssertMsg)); + } + if (!m_pImpl->m_pDataMember) + { + QString sAssertMsg = sCheckMsg + " : m_pImpl->m_pDataMember is equal to NULL"; + qAssertMsg(false, "[QxOrm] qx::IxSqlRelation::init()", qPrintable(sAssertMsg)); + } + if (!m_pImpl->m_pDataMemberX) + { + QString sAssertMsg = sCheckMsg + " : m_pImpl->m_pDataMemberX is equal to NULL"; + qAssertMsg(false, "[QxOrm] qx::IxSqlRelation::init()", qPrintable(sAssertMsg)); + } + if (!m_pImpl->m_pDataMemberId) + { + QString sAssertMsg = sCheckMsg + " : m_pImpl->m_pDataMemberId is equal to NULL"; + qAssertMsg(false, "[QxOrm] qx::IxSqlRelation::init()", qPrintable(sAssertMsg)); + } +#endif // _QX_MODE_DEBUG + + if (IxSqlRelation::IxSqlRelationImpl::m_bTraceRelationInit) + { + QString sTraceMsg = "[QxOrm] Init relationship '" + this->getKey() + "' from '" + (m_pImpl->m_pClassOwner ? m_pImpl->m_pClassOwner->getKey() : QString()) + "' to '" + (m_pImpl->m_pClass ? m_pImpl->m_pClass->getKey() : QString()) + "'"; + qDebug() << sTraceMsg; + } + + m_pImpl->m_lstSqlRelationPtr = std::make_shared(); + m_pImpl->m_lstDataMemberPtr = std::make_shared>(); + IxDataMember *p = NULL; + long lCount = m_pImpl->m_pDataMemberX->count_WithDaoStrategy(); + + for (long l = 0; l < lCount; ++l) + { + p = m_pImpl->isValid_DataMember(l); + if (!p) + { + continue; + } +#ifdef _QX_MODE_DEBUG + if (m_pImpl->m_lstDataMemberPtr->exist(p->getKey())) + { + QString sDebugMsg = "[QxOrm] Relationship '" + this->getKey() + "' from '" + (m_pImpl->m_pClassOwner ? m_pImpl->m_pClassOwner->getKey() : QString()) + "' to '" + (m_pImpl->m_pClass ? m_pImpl->m_pClass->getKey() : QString()) + "' : data member '" + p->getKey() + "' already exists in the collection"; + qDebug() << sDebugMsg; + } +#endif // _QX_MODE_DEBUG + m_pImpl->m_lstDataMemberPtr->insert(p->getKey(), p); + } + + for (long l = 0; l < lCount; ++l) + { + p = m_pImpl->isValid_SqlRelation(l); + if (!p) + { + continue; + } +#ifdef _QX_MODE_DEBUG + if (m_pImpl->m_lstSqlRelationPtr->exist(p->getKey())) + { + QString sDebugMsg = "[QxOrm] Relationship '" + this->getKey() + "' from '" + (m_pImpl->m_pClassOwner ? m_pImpl->m_pClassOwner->getKey() : QString()) + "' to '" + (m_pImpl->m_pClass ? m_pImpl->m_pClass->getKey() : QString()) + "' : relation '" + p->getKey() + "' already exists in the collection"; + qDebug() << sDebugMsg; + } +#endif // _QX_MODE_DEBUG + m_pImpl->m_lstSqlRelationPtr->insert(p->getKey(), p->getSqlRelation()); + } + + if (m_pImpl->m_eRelationType == qx::IxSqlRelation::many_to_one) + { + // Check if relationship (foreign key) is also a part of primary key + int iRelationNameCount = (m_pImpl->m_pDataMember ? m_pImpl->m_pDataMember->getNameCount() : 0); + int iIdOwnerNameCount = (m_pImpl->m_pDataMemberIdOwner ? m_pImpl->m_pDataMemberIdOwner->getNameCount() : 0); + for (int i = 0; i < iRelationNameCount; i++) + { + for (int j = 0; j < iIdOwnerNameCount; j++) + { + if (m_pImpl->m_pDataMember->getName(i) == m_pImpl->m_pDataMemberIdOwner->getName(j)) + { + m_pImpl->m_pDataMemberIdOwner->setRelationPartOfPrimaryKey(j, this, i); + m_pImpl->m_pDataMember->setPartOfPrimaryKey(i, m_pImpl->m_pDataMemberIdOwner, j); + } + } + } + } + + m_pImpl->m_bInitDone = true; + m_pImpl->m_bInitInEvent = false; + } + + void IxSqlRelation::setTraceRelationInit(bool bTrace) { IxSqlRelation::IxSqlRelationImpl::m_bTraceRelationInit = bTrace; } + + QString IxSqlRelation::getKey() const + { + return (m_pImpl->m_pDataMember ? m_pImpl->m_pDataMember->getKey() : ""); + } + + long IxSqlRelation::getDataCount() const + { + return (m_pImpl->m_lstDataMemberPtr ? m_pImpl->m_lstDataMemberPtr->count() : 0); + } + + long IxSqlRelation::getRelationCount() const + { + return (m_pImpl->m_lstSqlRelationPtr ? m_pImpl->m_lstSqlRelationPtr->count() : 0); + } + + QString IxSqlRelation::table() const + { + return (m_pImpl->m_pDataMemberX ? m_pImpl->m_pDataMemberX->getName() : ""); + } + + bool IxSqlRelation::traceSqlQuery() const + { + return qx::QxSqlDatabase::getSingleton()->getTraceSqlQuery(); + } + + IxDataMember *IxSqlRelation::getDataByKey(const QString &sKey) const + { + if (m_pImpl->m_lstDataMemberPtr && m_pImpl->m_lstDataMemberPtr->exist(sKey)) + { + return m_pImpl->m_lstDataMemberPtr->getByKey(sKey); + } + else if (m_pImpl->m_lstSqlRelationPtr && m_pImpl->m_lstSqlRelationPtr->exist(sKey)) + { + return m_pImpl->m_lstSqlRelationPtr->getByKey(sKey)->getDataMember(); + } + return NULL; + } + + IxDataMember *IxSqlRelation::nextData(long &lIndex) const + { + if ((!m_pImpl->m_lstDataMemberPtr) || (lIndex < 0) || (lIndex >= m_pImpl->m_lstDataMemberPtr->count())) + { + return NULL; + } + ++lIndex; + return m_pImpl->m_lstDataMemberPtr->getByIndex(lIndex - 1); + } + + IxSqlRelation *IxSqlRelation::nextRelation(long &lIndex) const + { + if ((!m_pImpl->m_lstSqlRelationPtr) || (lIndex < 0) || (lIndex >= m_pImpl->m_lstSqlRelationPtr->count())) + { + return NULL; + } + ++lIndex; + return m_pImpl->m_lstSqlRelationPtr->getByIndex(lIndex - 1); + } + + QString IxSqlRelation::tableAlias(QxSqlRelationParams ¶ms) const + { + if (!params.getCustomAlias().isEmpty()) + { + return params.getCustomAlias(); + } + QString sTableAlias = (m_pImpl->m_pDataMemberX ? (m_pImpl->m_pDataMemberX->getName() + "_" + QString::number(params.index())) : QString("")); + sTableAlias.replace(".", "_"); + return IxDataMember::getSqlTableNameAlias(sTableAlias); + } + + QString IxSqlRelation::tableAliasOwner(QxSqlRelationParams ¶ms) const + { + if (!m_pImpl->m_pClassOwner) + { + qAssert(false); + return ""; + } + if (!params.getCustomAliasOwner().isEmpty()) + { + return params.getCustomAliasOwner(); + } + QString sTableAliasOwner = (m_pImpl->m_pClassOwner->getName() + "_" + QString::number(params.indexOwner())); + if (params.indexOwner() <= 0) + { + sTableAliasOwner = params.builder().table(); + } + if (!params.getTableAlias().isEmpty()) + { + sTableAliasOwner = params.getTableAlias(); + } + sTableAliasOwner.replace(".", "_"); + return sTableAliasOwner; + } + + QString IxSqlRelation::getSqlJoin(qx::dao::sql_join::join_type e /* = qx::dao::sql_join::no_join */) const + { + QString sJoin; + if (e == qx::dao::sql_join::no_join) + { + e = m_pImpl->m_eJoinType; + } + + switch (e) + { + case qx::dao::sql_join::left_outer_join: + sJoin = " LEFT OUTER JOIN "; + break; + case qx::dao::sql_join::inner_join: + sJoin = " INNER JOIN "; + break; + default: + sJoin = " LEFT OUTER JOIN "; + break; + } + + return sJoin; + } + + bool IxSqlRelation::verifyOffset(QxSqlRelationParams ¶ms, bool bId) const + { +#ifdef _QX_MODE_DEBUG + if ((!qx::QxSqlDatabase::getSingleton()->getVerifyOffsetRelation()) || (params.isDistinct())) + { + return true; + } + IxDataMember *p = (bId ? this->getDataId() : this->getDataMember()); + QString table = (bId ? this->tableAlias(params) : this->tableAliasOwner(params)); + if (!p || table.isEmpty()) + { + return true; + } + QString sSuffixAlias = ((!bId && (params.indexOwner() > 0)) ? QString("_" + QString::number(params.indexOwner())) : QString()); + QString sRecordToFind = p->getSqlAlias(table, false, 0, (¶ms.builder())) + sSuffixAlias; + int index = params.query().record().indexOf(sRecordToFind); + qAssert(index == params.offset()); + return (index == params.offset()); +#else // _QX_MODE_DEBUG + Q_UNUSED(params); + Q_UNUSED(bId); + return true; +#endif // _QX_MODE_DEBUG + } + + QVariant IxSqlRelation::getIdFromQuery_ManyToMany(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + QVariant vId; + IxDataMember *pId = this->getDataId(); + if (!bEager || !pId) + { + return QVariant(); + } + iOffset = ((iOffset < 0) ? params.offset() : iOffset); + if ((!params.isDistinct()) && (iNameIndex < 0)) + { + QString sId; + for (int i = 0; i < pId->getNameCount(); i++) + { + sId += params.query().value(iOffset + i).toString() + "|"; + } + vId = sId; + } + else if ((!params.isDistinct()) && (iNameIndex >= 0)) + { + qAssert(iNameIndex < pId->getNameCount()); + return params.query().value(iOffset + iNameIndex); + } + else if (params.isDistinct()) + { + QString sId; + IxDataMember *p = NULL; + long lIndex = 0; + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + sId += params.query().value(iOffset + lCurrIndex).toString() + "|"; + lCurrIndex++; + } + } + vId = static_cast(qHash(sId)); + } + return vId; + } + + QVariant IxSqlRelation::getIdFromQuery_ManyToOne(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + Q_UNUSED(bEager); + QVariant vId; + IxDataMember *pId = this->getDataId(); + if (!pId) + { + return QVariant(); + } + iOffset = ((iOffset < 0) ? params.offset() : iOffset); + if ((!params.isDistinct()) && (iNameIndex < 0)) + { + QString sId; + for (int i = 0; i < pId->getNameCount(); i++) + { + sId += params.query().value(iOffset + i).toString() + "|"; + } + vId = sId; + } + else if ((!params.isDistinct()) && (iNameIndex >= 0)) + { + qAssert(iNameIndex < pId->getNameCount()); + return params.query().value(iOffset + iNameIndex); + } + else if (params.isDistinct()) + { + QString sId; + IxDataMember *p = NULL; + long lIndex = 0; + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + sId += params.query().value(iOffset + lCurrIndex).toString() + "|"; + lCurrIndex++; + } + } + vId = static_cast(qHash(sId)); + } + return vId; + } + + QVariant IxSqlRelation::getIdFromQuery_OneToMany(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + QVariant vId; + IxDataMember *pId = this->getDataId(); + if (!bEager || !pId) + { + return QVariant(); + } + iOffset = ((iOffset < 0) ? params.offset() : iOffset); + if ((!params.isDistinct()) && (iNameIndex < 0)) + { + QString sId; + for (int i = 0; i < pId->getNameCount(); i++) + { + sId += params.query().value(iOffset + i).toString() + "|"; + } + vId = sId; + } + else if ((!params.isDistinct()) && (iNameIndex >= 0)) + { + qAssert(iNameIndex < pId->getNameCount()); + return params.query().value(iOffset + iNameIndex); + } + else if (params.isDistinct()) + { + QString sId; + IxDataMember *p = NULL; + IxDataMember *pForeign = this->getDataByKey(this->getForeignKey()); + long lIndex = 0; + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if ((p != pForeign) && (params.checkColumns(p->getKey()))) + { + sId += params.query().value(iOffset + lCurrIndex).toString() + "|"; + lCurrIndex++; + } + } + vId = static_cast(qHash(sId)); + } + return vId; + } + + QVariant IxSqlRelation::getIdFromQuery_OneToOne(bool bEager, QxSqlRelationParams ¶ms, int iOffset, int iNameIndex) const + { + QVariant vId; + IxDataMember *pId = this->getDataId(); + if (!bEager || !pId) + { + return QVariant(); + } + iOffset = ((iOffset < 0) ? params.offset() : iOffset); + if ((!params.isDistinct()) && (iNameIndex < 0)) + { + QString sId; + for (int i = 0; i < pId->getNameCount(); i++) + { + sId += params.query().value(iOffset + i).toString() + "|"; + } + vId = sId; + } + else if ((!params.isDistinct()) && (iNameIndex >= 0)) + { + qAssert(iNameIndex < pId->getNameCount()); + return params.query().value(iOffset + iNameIndex); + } + else if (params.isDistinct()) + { + QString sId; + IxDataMember *p = NULL; + long lIndex = 0; + long lCurrIndex = 0; + while ((p = this->nextData(lIndex))) + { + if (params.checkColumns(p->getKey())) + { + sId += params.query().value(iOffset + lCurrIndex).toString() + "|"; + lCurrIndex++; + } + } + vId = static_cast(qHash(sId)); + } + return vId; + } + + void IxSqlRelation::updateOffset_ManyToMany(bool bEager, QxSqlRelationParams ¶ms) const + { + if (!bEager) + { + return; + } + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + long lOffsetNew = params.offset() + this->getDataCount(); + lOffsetNew += ((this->getDataId() && (!params.isDistinct())) ? this->getDataId()->getNameCount() : 0); + lOffsetNew += (oSoftDelete.isEmpty() ? 0 : 1); + params.setOffset(lOffsetNew); + + if (bEager && (params.getColumnsCount() > 0) && (params.getColumnsOffset() > 0)) + { + lOffsetNew = (lOffsetNew - params.getColumnsOffset()); + params.setOffset(lOffsetNew); + } + else if (bEager && (params.getColumnsCount() > 0)) + { + long l1 = 0; + IxDataMember *p = NULL; + long lColumnsOffset = 0; + while ((p = this->nextData(l1))) + { + if (!params.checkColumns(p->getKey())) + { + lOffsetNew = (lOffsetNew - 1); + lColumnsOffset++; + } + } + params.setOffset(lOffsetNew); + params.setColumnsOffset(lColumnsOffset); + } + + if (!params.relationX()) + { + return; + } + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->updateOffset(false, params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + void IxSqlRelation::updateOffset_ManyToOne(bool bEager, QxSqlRelationParams ¶ms) const + { + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + long lOffsetDataMember = ((this->getDataMember() && (!params.isDistinct())) ? this->getDataMember()->getNameCount() : 0); + long lOffsetDataId = (bEager ? ((this->getDataId() && (!params.isDistinct())) ? this->getDataId()->getNameCount() : 0) : 0); + long lOffsetDataCount = (bEager ? this->getDataCount() : 0); + long lOffsetSoftDelete = (bEager ? (oSoftDelete.isEmpty() ? 0 : 1) : 0); + long lOffsetNew = (params.offset() + lOffsetDataMember + lOffsetDataId + lOffsetDataCount + lOffsetSoftDelete); + params.setOffset(lOffsetNew); + + if (bEager && (params.getColumnsCount() > 0) && (params.getColumnsOffset() > 0)) + { + lOffsetNew = (lOffsetNew - params.getColumnsOffset()); + params.setOffset(lOffsetNew); + } + else if (bEager && (params.getColumnsCount() > 0)) + { + long l1 = 0; + IxDataMember *p = NULL; + long lColumnsOffset = 0; + while ((p = this->nextData(l1))) + { + if (!params.checkColumns(p->getKey())) + { + lOffsetNew = (lOffsetNew - 1); + lColumnsOffset++; + } + } + params.setOffset(lOffsetNew); + params.setColumnsOffset(lColumnsOffset); + } + + if (!bEager || !params.relationX()) + { + return; + } + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->updateOffset(false, params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + void IxSqlRelation::updateOffset_OneToMany(bool bEager, QxSqlRelationParams ¶ms) const + { + if (!bEager) + { + return; + } + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + IxDataMember *pForeign = this->getDataByKey(m_pImpl->m_sForeignKey); + bool bAddOffsetForeign = (pForeign && !this->getLstDataMember()->exist(m_pImpl->m_sForeignKey)); + long lOffsetId = ((this->getDataId() && (!params.isDistinct())) ? this->getDataId()->getNameCount() : 0); + long lOffsetNew = (params.offset() + this->getDataCount() + lOffsetId); + lOffsetNew = (lOffsetNew + ((bAddOffsetForeign && (!params.isDistinct())) ? pForeign->getNameCount() : 0)); + lOffsetNew = (lOffsetNew + (oSoftDelete.isEmpty() ? 0 : 1)); + params.setOffset(lOffsetNew); + + if (bEager && (params.getColumnsCount() > 0) && (params.getColumnsOffset() > 0)) + { + lOffsetNew = (lOffsetNew - params.getColumnsOffset()); + params.setOffset(lOffsetNew); + } + else if (bEager && (params.getColumnsCount() > 0)) + { + long l1 = 0; + IxDataMember *p = NULL; + long lColumnsOffset = 0; + while ((p = this->nextData(l1))) + { + if (!params.checkColumns(p->getKey())) + { + lOffsetNew = (lOffsetNew - 1); + lColumnsOffset++; + } + } + params.setOffset(lOffsetNew); + params.setColumnsOffset(lColumnsOffset); + } + + if (!params.relationX()) + { + return; + } + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->updateOffset(false, params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + void IxSqlRelation::updateOffset_OneToOne(bool bEager, QxSqlRelationParams ¶ms) const + { + if (!bEager) + { + return; + } + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + long lOffsetNew = params.offset() + this->getDataCount(); + lOffsetNew += ((this->getDataId() && (!params.isDistinct())) ? this->getDataId()->getNameCount() : 0); + lOffsetNew += (oSoftDelete.isEmpty() ? 0 : 1); + params.setOffset(lOffsetNew); + + if (bEager && (params.getColumnsCount() > 0) && (params.getColumnsOffset() > 0)) + { + lOffsetNew = (lOffsetNew - params.getColumnsOffset()); + params.setOffset(lOffsetNew); + } + else if (bEager && (params.getColumnsCount() > 0)) + { + long l1 = 0; + IxDataMember *p = NULL; + long lColumnsOffset = 0; + while ((p = this->nextData(l1))) + { + if (!params.checkColumns(p->getKey())) + { + lOffsetNew = (lOffsetNew - 1); + lColumnsOffset++; + } + } + params.setOffset(lOffsetNew); + params.setColumnsOffset(lColumnsOffset); + } + + if (!params.relationX()) + { + return; + } + long lRelation = 0; + IxSqlRelation *pRelation = NULL; + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(lRelation))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->updateOffset(false, params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + void IxSqlRelation::eagerSelect_ManyToMany(QxSqlRelationParams ¶ms) const + { + long l1(0), l2(0); + QString &sql = params.sql(); + IxSqlRelation *pRelation = NULL; + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + QString tableAlias = this->tableAlias(params); + if (pId && (!params.isDistinct())) + { + sql += (pId->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + while ((p = this->nextData(l1))) + { + if (params.checkColumns(p->getKey())) + { + sql += (p->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + } + + if (params.relationX()) + { + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sTableAliasOld = params.getTableAlias(); + params.setTableAlias(tableAlias); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(l2))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazySelect(params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setTableAlias(sTableAliasOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (!oSoftDelete.isEmpty()) + { + sql += (oSoftDelete.buildSqlTablePointName(tableAlias) + ", "); + } + } + + void IxSqlRelation::eagerSelect_ManyToOne(QxSqlRelationParams ¶ms) const + { + long l1(0), l2(0); + QString &sql = params.sql(); + IxSqlRelation *pRelation = NULL; + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + QString table = this->table(); + QString tableAlias = this->tableAlias(params); + QString tableRef = this->tableAliasOwner(params); + QString sSuffixAlias; + if (params.indexOwner() > 0) + { + sSuffixAlias = "_" + QString::number(params.indexOwner()); + } + if (pData && (!params.isDistinct())) + { + sql += (pData->getSqlTablePointNameAsAlias(tableRef, ", ", sSuffixAlias, false, "", (¶ms.builder())) + ", "); + } + if (pId && (!params.isDistinct())) + { + sql += (pId->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + while ((p = this->nextData(l1))) + { + if (params.checkColumns(p->getKey())) + { + sql += (p->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + } + + if (params.relationX()) + { + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sTableAliasOld = params.getTableAlias(); + params.setTableAlias(tableAlias); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(l2))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazySelect(params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setTableAlias(sTableAliasOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (!oSoftDelete.isEmpty()) + { + sql += (oSoftDelete.buildSqlTablePointName(tableAlias) + ", "); + } + } + + void IxSqlRelation::eagerSelect_OneToMany(QxSqlRelationParams ¶ms) const + { + long l1(0), l2(0); + QString &sql = params.sql(); + IxSqlRelation *pRelation = NULL; + IxDataMember *pForeign = this->getDataByKey(this->m_pImpl->m_sForeignKey); + qAssert(pForeign); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + QString tableAlias = this->tableAlias(params); + if (pId && (!params.isDistinct())) + { + sql += (pId->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + if (pForeign && (!params.isDistinct())) + { + sql += (pForeign->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + while ((p = this->nextData(l1))) + { + if ((p != pForeign) && (params.checkColumns(p->getKey()))) + { + sql += (p->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + } + + if (params.relationX()) + { + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sTableAliasOld = params.getTableAlias(); + params.setTableAlias(tableAlias); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(l2))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazySelect(params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setTableAlias(sTableAliasOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (!oSoftDelete.isEmpty()) + { + sql += (oSoftDelete.buildSqlTablePointName(tableAlias) + ", "); + } + } + + void IxSqlRelation::eagerSelect_OneToOne(QxSqlRelationParams ¶ms) const + { + long l1(0), l2(0); + QString &sql = params.sql(); + IxSqlRelation *pRelation = NULL; + QString tableAlias = this->tableAlias(params); + IxDataMember *p = NULL; + IxDataMember *pId = this->getDataId(); + qAssert(pId); + if (pId && (!params.isDistinct())) + { + sql += (pId->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + while ((p = this->nextData(l1))) + { + if (params.checkColumns(p->getKey())) + { + sql += (p->getSqlTablePointNameAsAlias(tableAlias, ", ", "", false, "", (¶ms.builder())) + ", "); + } + } + + if (params.relationX()) + { + long lIndexOwnerOld = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sTableAliasOld = params.getTableAlias(); + params.setTableAlias(tableAlias); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(params.getCustomAlias()); + while ((pRelation = this->nextRelation(l2))) + { + if (this->addLazyRelation(params, pRelation)) + { + pRelation->lazySelect(params); + } + } + params.setIndexOwner(lIndexOwnerOld); + params.setTableAlias(sTableAliasOld); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (!oSoftDelete.isEmpty()) + { + sql += (oSoftDelete.buildSqlTablePointName(tableAlias) + ", "); + } + } + + void IxSqlRelation::eagerJoin_ManyToMany(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pIdOwner = this->getDataIdOwner(); + qAssert(pIdOwner); + IxDataMember *pIdData = this->getDataId(); + qAssert(pIdData); + QString table = this->table(); + QString tableAlias = this->tableAlias(params); + QString tableOwner = this->tableAliasOwner(params); + if (!pIdOwner || !pIdData) + { + return; + } + QStringList lstForeignKeyOwner = m_pImpl->m_sForeignKeyOwner.split("|"); + QStringList lstForeignKeyDataType = m_pImpl->m_sForeignKeyDataType.split("|"); + qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count()); + qAssert(pIdData->getNameCount() == lstForeignKeyDataType.count()); + qx::dao::detail::IxDao_Helper *pDaoHelper = params.builder().getDaoHelper(); + QString sExtraTableAlias = m_pImpl->m_sExtraTable + "_" + QString::number(params.index()); + sql += this->getSqlJoin(params.joinType()) + qx::IxDataMember::getSqlTableName(m_pImpl->m_sExtraTable) + " " + sExtraTableAlias + " ON "; + for (int i = 0; i < pIdOwner->getNameCount(); i++) + { + sql += pIdOwner->getSqlAlias(tableOwner, true, i, (¶ms.builder())) + " = " + sExtraTableAlias + "." + lstForeignKeyOwner.at(i) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + + QString joinQuery; + if (pDaoHelper) + { + qx_query &query = pDaoHelper->qxQuery(); + joinQuery = query.getJoinQuery(this->getKey(), tableAlias); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + sql += this->getSqlJoin(params.joinType()) + qx::IxDataMember::getSqlTableName(table) + " " + tableAlias + " ON "; + if (!joinQuery.isEmpty()) + { + sql += "("; + } + params.builder().addSqlQueryAlias(table, tableAlias); + for (int i = 0; i < pIdData->getNameCount(); i++) + { + sql += sExtraTableAlias + "." + lstForeignKeyDataType.at(i) + " = " + pIdData->getSqlAlias(tableAlias, true, i, (¶ms.builder())) + " AND "; + } + if (!oSoftDelete.isEmpty() && oSoftDelete.getSqlFetchInJoin()) + { + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + if (!joinQuery.isEmpty()) + { + sql += " " + joinQuery + ")"; + } + } + + void IxSqlRelation::eagerJoin_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pId = this->getDataId(); + qAssert(pId); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + QString table = this->table(); + QString tableAlias = this->tableAlias(params); + QString tableRef = this->tableAliasOwner(params); + if (!pId || !pData) + { + return; + } + + QString joinQuery; + qx::dao::detail::IxDao_Helper *pDaoHelper = params.builder().getDaoHelper(); + if (pDaoHelper) + { + qx_query &query = pDaoHelper->qxQuery(); + joinQuery = query.getJoinQuery(this->getKey(), tableAlias); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + sql += this->getSqlJoin(params.joinType()) + qx::IxDataMember::getSqlTableName(table) + " " + tableAlias + " ON "; + if (!joinQuery.isEmpty()) + { + sql += "("; + } + params.builder().addSqlQueryAlias(table, tableAlias); + for (int i = 0; i < pId->getNameCount(); i++) + { + sql += pId->getSqlAlias(tableAlias, true, i, (¶ms.builder())) + " = " + pData->getSqlAlias(tableRef, true, i, (¶ms.builder())) + " AND "; + } + if (!oSoftDelete.isEmpty() && oSoftDelete.getSqlFetchInJoin()) + { + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + if (!joinQuery.isEmpty()) + { + sql += " " + joinQuery + ")"; + } + } + + void IxSqlRelation::eagerJoin_OneToMany(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pId = this->getDataIdOwner(); + qAssert(pId); + IxDataMember *pForeign = this->getDataByKey(this->m_pImpl->m_sForeignKey); + qAssert(pForeign); + QString table = this->table(); + QString tableAlias = this->tableAlias(params); + QString tableRef = this->tableAliasOwner(params); + if (!pId || !pForeign) + { + return; + } + + QString joinQuery; + qx::dao::detail::IxDao_Helper *pDaoHelper = params.builder().getDaoHelper(); + if (pDaoHelper) + { + qx_query &query = pDaoHelper->qxQuery(); + joinQuery = query.getJoinQuery(this->getKey(), tableAlias); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + sql += this->getSqlJoin(params.joinType()) + qx::IxDataMember::getSqlTableName(table) + " " + tableAlias + " ON "; + if (!joinQuery.isEmpty()) + { + sql += "("; + } + params.builder().addSqlQueryAlias(table, tableAlias); + for (int i = 0; i < pId->getNameCount(); i++) + { + sql += pForeign->getSqlAlias(tableAlias, true, i, (¶ms.builder())) + " = " + pId->getSqlAlias(tableRef, true, i, (¶ms.builder())) + " AND "; + } + if (!oSoftDelete.isEmpty() && oSoftDelete.getSqlFetchInJoin()) + { + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + if (!joinQuery.isEmpty()) + { + sql += " " + joinQuery + ")"; + } + } + + void IxSqlRelation::eagerJoin_OneToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pId = this->getDataId(); + qAssert(pId); + IxDataMember *pIdRef = this->getDataIdOwner(); + qAssert(pIdRef); + QString table = this->table(); + QString tableAlias = this->tableAlias(params); + QString tableRef = this->tableAliasOwner(params); + if (!pId || !pIdRef) + { + return; + } + + QString joinQuery; + qx::dao::detail::IxDao_Helper *pDaoHelper = params.builder().getDaoHelper(); + if (pDaoHelper) + { + qx_query &query = pDaoHelper->qxQuery(); + joinQuery = query.getJoinQuery(this->getKey(), tableAlias); + } + + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + sql += this->getSqlJoin(params.joinType()) + qx::IxDataMember::getSqlTableName(table) + " " + tableAlias + " ON "; + if (!joinQuery.isEmpty()) + { + sql += "("; + } + params.builder().addSqlQueryAlias(table, tableAlias); + for (int i = 0; i < pId->getNameCount(); i++) + { + sql += pId->getSqlAlias(tableAlias, true, i, (¶ms.builder())) + " = " + pIdRef->getSqlAlias(tableRef, true, i, (¶ms.builder())) + " AND "; + } + if (!oSoftDelete.isEmpty() && oSoftDelete.getSqlFetchInJoin()) + { + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + if (!joinQuery.isEmpty()) + { + sql += " " + joinQuery + ")"; + } + } + + void IxSqlRelation::eagerWhereSoftDelete_ManyToMany(QxSqlRelationParams ¶ms) const + { + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (oSoftDelete.isEmpty()) + { + return; + } + if (oSoftDelete.getSqlFetchInJoin()) + { + return; + } + QString &sql = params.sql(); + QString tableAlias = this->tableAlias(params); + sql += qx::IxSqlQueryBuilder::addSqlCondition(sql); + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias); + } + + void IxSqlRelation::eagerWhereSoftDelete_ManyToOne(QxSqlRelationParams ¶ms) const + { + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (oSoftDelete.isEmpty()) + { + return; + } + if (oSoftDelete.getSqlFetchInJoin()) + { + return; + } + QString &sql = params.sql(); + QString tableAlias = this->tableAlias(params); + sql += qx::IxSqlQueryBuilder::addSqlCondition(sql); + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias); + } + + void IxSqlRelation::eagerWhereSoftDelete_OneToMany(QxSqlRelationParams ¶ms) const + { + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (oSoftDelete.isEmpty()) + { + return; + } + if (oSoftDelete.getSqlFetchInJoin()) + { + return; + } + QString &sql = params.sql(); + QString tableAlias = this->tableAlias(params); + sql += qx::IxSqlQueryBuilder::addSqlCondition(sql); + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias); + } + + void IxSqlRelation::eagerWhereSoftDelete_OneToOne(QxSqlRelationParams ¶ms) const + { + const QxSoftDelete &oSoftDelete = this->m_pImpl->getSoftDelete(params); + if (oSoftDelete.isEmpty()) + { + return; + } + if (oSoftDelete.getSqlFetchInJoin()) + { + return; + } + QString &sql = params.sql(); + QString tableAlias = this->tableAlias(params); + sql += qx::IxSqlQueryBuilder::addSqlCondition(sql); + sql += oSoftDelete.buildSqlQueryToFetch(tableAlias); + } + + void IxSqlRelation::lazySelect_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + QString tableRef = this->tableAliasOwner(params); + QString sSuffixAlias; + if (params.indexOwner() > 0) + { + sSuffixAlias = "_" + QString::number(params.indexOwner()); + } + if (pData) + { + sql += (pData->getSqlTablePointNameAsAlias(tableRef, ", ", sSuffixAlias, false, "", (¶ms.builder())) + ", "); + } + } + + void IxSqlRelation::lazyInsert_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (pData) + { + sql += pData->getSqlName(", ", "", false, (¶ms.builder())) + ", "; + } + } + + void IxSqlRelation::lazyInsert_Values_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (pData) + { + sql += pData->getSqlPlaceHolder("", -1, ", ") + ", "; + } + } + + void IxSqlRelation::lazyUpdate_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (pData) + { + sql += pData->getSqlNameEqualToPlaceHolder("", ", ", false, (¶ms.builder())) + ", "; + } + } + + void IxSqlRelation::createTable_ManyToOne(QxSqlRelationParams ¶ms) const + { + QString &sql = params.sql(); + IxDataMember *pData = this->getDataMember(); + qAssert(pData); + if (pData) + { + sql += pData->getSqlNameAndTypeAndParams(", ") + ", "; + qAssert(!pData->getSqlType().isEmpty()); + } + } + + QString IxSqlRelation::createExtraTable_ManyToMany() const + { + IxDataMember *pIdOwner = this->getDataIdOwner(); + qAssert(pIdOwner); + IxDataMember *pIdData = this->getDataId(); + qAssert(pIdData); + if (!pIdOwner || !pIdData) + { + return ""; + } + + bool bOldPKOwner = pIdOwner->getIsPrimaryKey(); + pIdOwner->setIsPrimaryKey(false); + bool bOldPKData = ((pIdOwner == pIdData) ? bOldPKOwner : pIdData->getIsPrimaryKey()); + pIdData->setIsPrimaryKey(false); + bool bOldAIOwner = pIdOwner->getAutoIncrement(); + pIdOwner->setAutoIncrement(false); + bool bOldAIData = ((pIdOwner == pIdData) ? bOldAIOwner : pIdData->getAutoIncrement()); + pIdData->setAutoIncrement(false); + + QString sql = "CREATE TABLE IF NOT EXISTS " + this->m_pImpl->m_sExtraTable + " ("; + sql += pIdOwner->getSqlNameAndTypeAndParams(", ", this->m_pImpl->m_sForeignKeyOwner) + ", "; + qAssert(!pIdOwner->getSqlType().isEmpty()); + sql += pIdData->getSqlNameAndTypeAndParams(", ", this->m_pImpl->m_sForeignKeyDataType) + ", "; + qAssert(!pIdData->getSqlType().isEmpty()); + sql = sql.left(sql.length() - 2); // Remove last ", " + sql += ")"; + + pIdOwner->setIsPrimaryKey(bOldPKOwner); + pIdData->setIsPrimaryKey(bOldPKData); + pIdOwner->setAutoIncrement(bOldAIOwner); + pIdData->setAutoIncrement(bOldAIData); + if (this->traceSqlQuery()) + { + qDebug("[QxOrm] create extra-table (relation many-to-many) : %s", qPrintable(sql)); + } + return sql; + } + + QSqlError IxSqlRelation::deleteFromExtraTable_ManyToMany(QxSqlRelationParams ¶ms) const + { + IxDataMember *pIdOwner = this->getDataIdOwner(); + qAssert(pIdOwner); + QString sql = "DELETE FROM " + this->m_pImpl->m_sExtraTable + " WHERE "; + QStringList lstForeignKeyOwner = this->m_pImpl->m_sForeignKeyOwner.split("|"); + qAssert(pIdOwner->getNameCount() == lstForeignKeyOwner.count()); + for (int i = 0; i < pIdOwner->getNameCount(); i++) + { + sql += this->m_pImpl->m_sExtraTable + "." + lstForeignKeyOwner.at(i) + " = " + pIdOwner->getSqlPlaceHolder("", i) + " AND "; + } + sql = sql.left(sql.length() - 5); // Remove last " AND " + if (this->traceSqlQuery()) + { + qDebug("[QxOrm] sql query (extra-table) : %s", qPrintable(sql)); + } + + QSqlQuery queryDelete(params.database()); + if (!queryDelete.prepare(sql)) + { + return queryDelete.lastError(); + } + pIdOwner->setSqlPlaceHolder(queryDelete, params.owner()); + if (!queryDelete.exec()) + { + return queryDelete.lastError(); + } + return QSqlError(); + } + + bool IxSqlRelation::addLazyRelation(QxSqlRelationParams ¶ms, IxSqlRelation *pRelation) const + { + if (!params.relationX() || !pRelation || !params.checkColumns(pRelation->getKey())) + { + return false; + } + qx::QxSqlRelationLinked_ptr pRelationLinked = params.relationX()->value(this->getKey()); + return (!pRelationLinked || !pRelationLinked->existRelation(pRelation->getKey())); + } + +} // namespace qx diff --git a/src/QxDao/QxDaoAsync.cpp b/src/QxDao/QxDaoAsync.cpp new file mode 100644 index 0000000..8787e25 --- /dev/null +++ b/src/QxDao/QxDaoAsync.cpp @@ -0,0 +1,543 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +#include + +#define QX_DAO_ASYNC_QUERY_ALREADY_RUNNING qDebug("[QxOrm] qx::QxDaoAsync : '%s'", "another query is already running"); + +namespace qx +{ + + QxDaoAsync::QxDaoAsync() : QThread() { ; } + + QxDaoAsync::~QxDaoAsync() + { + if (!isRunning()) + { + return; + } + qDebug("[QxOrm] qx::QxDaoAsync thread is running : %s", "quit and wait"); + quit(); + wait(); + } + + void QxDaoAsync::run() + { + qx::dao::detail::QxDaoAsyncRunner daoRunner; + qRegisterMetaType("QSqlError"); + qRegisterMetaType("qx::dao::detail::QxDaoAsyncParams_ptr"); + QObject::connect(this, SIGNAL(queryStarted(qx::dao::detail::QxDaoAsyncParams_ptr)), (&daoRunner), SLOT(onQueryStarted(qx::dao::detail::QxDaoAsyncParams_ptr))); + QObject::connect((&daoRunner), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr))); + if (m_pDaoParams && (m_pDaoParams->daoAction != qx::dao::detail::QxDaoAsyncParams::dao_none)) + { + daoRunner.onQueryStarted(m_pDaoParams); + } + exec(); + } + + void QxDaoAsync::startQuery() + { + if (!m_pDaoParams) + { + qAssert(false); + return; + } + if (isRunning()) + { + Q_EMIT queryStarted(m_pDaoParams); + } + else + { + start(); + } + } + + void QxDaoAsync::onQueryFinished(const QSqlError &daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams) + { + m_pDaoParams.reset(); + Q_EMIT queryFinished(daoError, pDaoParams); + } + + bool QxDaoAsync::asyncCount(const QString &className, const qx::QxSqlQuery &query /* = qx::QxSqlQuery() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_count; + m_pDaoParams->className = className; + m_pDaoParams->query = query; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncFetchById(IxPersistable_ptr pToFetch, const QVariant &id /* = QVariant() */, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_fetch_by_id; + m_pDaoParams->pInstance = pToFetch; + m_pDaoParams->id = id; + m_pDaoParams->listColumns = columns; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncFetchAll(const QString &className, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_fetch_all; + m_pDaoParams->className = className; + m_pDaoParams->listColumns = columns; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncFetchByQuery(const QString &className, const qx::QxSqlQuery &query, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_fetch_by_query; + m_pDaoParams->className = className; + m_pDaoParams->query = query; + m_pDaoParams->listColumns = columns; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncInsert(IxPersistable_ptr pToInsert, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_insert; + m_pDaoParams->pInstance = pToInsert; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncUpdate(IxPersistable_ptr pToUpdate, const qx::QxSqlQuery &query /* = qx::QxSqlQuery() */, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_update; + m_pDaoParams->pInstance = pToUpdate; + m_pDaoParams->query = query; + m_pDaoParams->listColumns = columns; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncSave(IxPersistable_ptr pToSave, const QStringList &relation /* = QStringList() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_save; + m_pDaoParams->pInstance = pToSave; + m_pDaoParams->listRelations = relation; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDeleteById(IxPersistable_ptr pToDelete, const QVariant &id /* = QVariant() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_delete_by_id; + m_pDaoParams->pInstance = pToDelete; + m_pDaoParams->id = id; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDeleteAll(const QString &className, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_delete_all; + m_pDaoParams->className = className; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDeleteByQuery(const QString &className, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_delete_by_query; + m_pDaoParams->className = className; + m_pDaoParams->query = query; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDestroyById(IxPersistable_ptr pToDestroy, const QVariant &id /* = QVariant() */, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_destroy_by_id; + m_pDaoParams->pInstance = pToDestroy; + m_pDaoParams->id = id; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDestroyAll(const QString &className, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_destroy_all; + m_pDaoParams->className = className; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncDestroyByQuery(const QString &className, const qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_destroy_by_query; + m_pDaoParams->className = className; + m_pDaoParams->query = query; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncExecuteQuery(const QString &className, qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + if (!QxClassX::implementIxPersistable(className)) + { + qAssert(false); + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_execute_query; + m_pDaoParams->className = className; + m_pDaoParams->query = query; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + bool QxDaoAsync::asyncCallQuery(qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) + { + QMutexLocker locker(&m_mutex); + if (m_pDaoParams) + { + QX_DAO_ASYNC_QUERY_ALREADY_RUNNING; + return false; + } + m_pDaoParams = std::make_shared(); + m_pDaoParams->daoAction = qx::dao::detail::QxDaoAsyncParams::dao_call_query; + m_pDaoParams->query = query; + m_pDaoParams->pDatabase = pDatabase; + startQuery(); + return true; + } + + namespace dao + { + namespace detail + { + + QxDaoAsyncRunner::QxDaoAsyncRunner() : QObject() { ; } + + QxDaoAsyncRunner::~QxDaoAsyncRunner() { ; } + + void QxDaoAsyncRunner::onQueryStarted(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams) + { + QSqlError daoError = this->runQuery(pDaoParams); + Q_EMIT queryFinished(daoError, pDaoParams); + } + + QSqlError QxDaoAsyncRunner::runQuery(qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams) + { + if (!pDaoParams) + { + qAssert(false); + return QSqlError("[QxOrm] qx::QxDaoAsync : 'null dao parameters'", "", QSqlError::UnknownError); + } + + QSqlError daoError; + QSqlDatabase *pDatabase(NULL); + QSqlDatabase db; + QString dbKey; + + try + { + if (!pDaoParams->className.isEmpty() && !pDaoParams->pInstance) + { + pDaoParams->pInstance.reset(static_cast(qx::create_void_ptr(pDaoParams->className))); + } + if (!pDaoParams->pInstance && (pDaoParams->daoAction != qx::dao::detail::QxDaoAsyncParams::dao_call_query)) + { + qAssert(false); + return QSqlError("[QxOrm] qx::QxDaoAsync : 'null instance implementing qx::IxPersistable interface'", "", QSqlError::UnknownError); + } + qx::IxPersistable_ptr pInstance = pDaoParams->pInstance; + + if ((pDaoParams->daoAction == qx::dao::detail::QxDaoAsyncParams::dao_fetch_all) || + (pDaoParams->daoAction == qx::dao::detail::QxDaoAsyncParams::dao_fetch_by_query) || + (pDaoParams->daoAction == qx::dao::detail::QxDaoAsyncParams::dao_execute_query)) + { + pDaoParams->pListOfInstances = pInstance->qxNewPersistableCollection(); + } + + if (pDaoParams->pDatabase != NULL) + { + dbKey = QUuid::createUuid().toString(); + db = QSqlDatabase::cloneDatabase((*pDaoParams->pDatabase), dbKey); + db.open(); + } + pDatabase = (pDaoParams->pDatabase ? (&db) : NULL); + + switch (pDaoParams->daoAction) + { + case qx::dao::detail::QxDaoAsyncParams::dao_count: + daoError = pInstance->qxCount(pDaoParams->daoCount, pDaoParams->query, pDatabase, pDaoParams->listRelations); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_fetch_by_id: + daoError = pInstance->qxFetchById(pDaoParams->id, pDaoParams->listColumns, pDaoParams->listRelations, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_fetch_all: + daoError = pInstance->qxFetchAll(pDaoParams->pListOfInstances.get(), pDaoParams->listColumns, pDaoParams->listRelations, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_fetch_by_query: + daoError = pInstance->qxFetchByQuery(pDaoParams->query, pDaoParams->pListOfInstances.get(), pDaoParams->listColumns, pDaoParams->listRelations, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_insert: + daoError = pInstance->qxInsert(pDaoParams->listRelations, pDatabase, pDaoParams->useExecBatch); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_update: + daoError = pInstance->qxUpdate(pDaoParams->query, pDaoParams->listColumns, pDaoParams->listRelations, pDatabase, pDaoParams->useExecBatch); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_save: + daoError = pInstance->qxSave(pDaoParams->listRelations, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_delete_by_id: + daoError = pInstance->qxDeleteById(pDaoParams->id, pDatabase, pDaoParams->useExecBatch); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_delete_all: + daoError = pInstance->qxDeleteAll(pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_delete_by_query: + daoError = pInstance->qxDeleteByQuery(pDaoParams->query, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_destroy_by_id: + daoError = pInstance->qxDestroyById(pDaoParams->id, pDatabase, pDaoParams->useExecBatch); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_destroy_all: + daoError = pInstance->qxDestroyAll(pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_destroy_by_query: + daoError = pInstance->qxDestroyByQuery(pDaoParams->query, pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_execute_query: + daoError = pInstance->qxExecuteQuery(pDaoParams->query, pDaoParams->pListOfInstances.get(), pDatabase); + break; + case qx::dao::detail::QxDaoAsyncParams::dao_call_query: + daoError = qx::dao::call_query(pDaoParams->query, pDatabase); + break; + default: + qAssert(false); + break; + } + } + catch (const qx::dao::sql_error &sqlErr) + { + daoError = sqlErr.get(); + } + catch (const std::exception &err) + { + daoError = QSqlError(err.what(), "", QSqlError::UnknownError); + } + catch (...) + { + daoError = QSqlError("[QxOrm] qx::QxDaoAsync : 'unknown error executing query'", "", QSqlError::UnknownError); + } + + if (pDatabase) + { + pDatabase->close(); + } + if (pDatabase && !dbKey.isEmpty()) + { + QSqlDatabase::removeDatabase(dbKey); + } + return daoError; + } + + } // namespace detail + } // namespace dao +} // namespace qx + +// Not really implemented, this is just to avoid a compilation error with Qt6 and _QX_UNITY_BUILD compilation option (?) +QDataStream &operator<<(QDataStream &stream, const qx::dao::detail::QxDaoAsyncParams &t) +{ + Q_UNUSED(t); + return stream; +} +QDataStream &operator>>(QDataStream &stream, qx::dao::detail::QxDaoAsyncParams &t) +{ + Q_UNUSED(t); + return stream; +} diff --git a/src/QxDao/QxDateNeutral.cpp b/src/QxDao/QxDateNeutral.cpp new file mode 100644 index 0000000..153542a --- /dev/null +++ b/src/QxDao/QxDateNeutral.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const qx::QxDateNeutral &t) +{ + stream << t.m_date; + stream << t.m_neutral; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxDateNeutral &t) +{ + stream >> t.m_date; + stream >> t.m_neutral; + return stream; +} diff --git a/src/QxDao/QxDateTimeNeutral.cpp b/src/QxDao/QxDateTimeNeutral.cpp new file mode 100644 index 0000000..8607d09 --- /dev/null +++ b/src/QxDao/QxDateTimeNeutral.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const qx::QxDateTimeNeutral &t) +{ + stream << t.m_dt; + stream << t.m_neutral; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxDateTimeNeutral &t) +{ + stream >> t.m_dt; + stream >> t.m_neutral; + return stream; +} diff --git a/src/QxDao/QxMongoDB/QxMongoDB_Helper.cpp b/src/QxDao/QxMongoDB/QxMongoDB_Helper.cpp new file mode 100644 index 0000000..072ca5a --- /dev/null +++ b/src/QxDao/QxMongoDB/QxMongoDB_Helper.cpp @@ -0,0 +1,1851 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_MONGODB + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::dao::mongodb::QxMongoDB_Helper) + +namespace qx +{ + namespace dao + { + namespace mongodb + { + + struct qx_engine + { + ; + }; + struct qx_reply + { + ; + }; + struct qx_opts + { + ; + }; + + template + struct qx_scoped_wrapper + { + ; + }; + + template <> + struct qx_scoped_wrapper + { + qx_scoped_wrapper() { mongoc_init(); } + ~qx_scoped_wrapper() { mongoc_cleanup(); } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_uri_t *m_uri; + qx_scoped_wrapper(const std::string &uri) : m_uri(NULL) { m_uri = mongoc_uri_new(uri.c_str()); } + ~qx_scoped_wrapper() + { + if (m_uri) + { + mongoc_uri_destroy(m_uri); + } + } + mongoc_uri_t *get() { return m_uri; } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_client_pool_t *m_pool; + qx_scoped_wrapper(mongoc_uri_t *uri) : m_pool(NULL) + { + if (uri) + { + m_pool = mongoc_client_pool_new(uri); + }; + } + ~qx_scoped_wrapper() + { + if (m_pool) + { + mongoc_client_pool_destroy(m_pool); + } + } + mongoc_client_pool_t *get() { return m_pool; } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_client_t *m_client; + mongoc_client_pool_t *m_pool; + qx_scoped_wrapper(mongoc_client_pool_t *pool) : m_client(NULL), m_pool(pool) + { + if (m_pool) + { + m_client = mongoc_client_pool_pop(m_pool); + }; + } + ~qx_scoped_wrapper() + { + if (m_pool && m_client) + { + mongoc_client_pool_push(m_pool, m_client); + } + } + mongoc_client_t *get() { return m_client; } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_database_t *m_db; + qx_scoped_wrapper(mongoc_client_t *client, const std::string &name) : m_db(NULL) + { + if (client) + { + m_db = mongoc_client_get_database(client, name.c_str()); + }; + } + ~qx_scoped_wrapper() + { + if (m_db) + { + mongoc_database_destroy(m_db); + } + } + mongoc_database_t *get() { return m_db; } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_collection_t *m_collection; + qx_scoped_wrapper(mongoc_client_t *client, const std::string &db, const std::string &name) : m_collection(NULL) + { + if (client) + { + m_collection = mongoc_client_get_collection(client, db.c_str(), name.c_str()); + }; + } + ~qx_scoped_wrapper() + { + if (m_collection) + { + mongoc_collection_destroy(m_collection); + } + } + mongoc_collection_t *get() { return m_collection; } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_cursor_t *m_cursor; + qx_scoped_wrapper(mongoc_cursor_t *cursor) : m_cursor(cursor) { ; } + ~qx_scoped_wrapper() + { + if (m_cursor) + { + mongoc_cursor_destroy(m_cursor); + } + } + mongoc_cursor_t *get() { return m_cursor; } + }; + + template <> + struct qx_scoped_wrapper + { + bson_t *m_doc; + bson_error_t m_err; + qx_scoped_wrapper(bson_t *doc) : m_doc(doc) { ; } + qx_scoped_wrapper(const std::string &json) : m_doc(NULL) + { + if (json.empty()) + { + m_doc = bson_new(); + } + else + { + m_doc = bson_new_from_json((const uint8_t *)(json.c_str()), -1, (&m_err)); + } + } + ~qx_scoped_wrapper() + { + if (m_doc) + { + bson_destroy(m_doc); + } + } + bson_error_t *err() { return (&m_err); } + bson_t *get() { return m_doc; } + }; + + template <> + struct qx_scoped_wrapper> + { + bson_error_t m_err; + std::vector m_docs; + qx_scoped_wrapper>(int size) { m_docs.reserve(size); } + ~qx_scoped_wrapper>() + { + for (bson_t *doc : m_docs) + { + if (doc) + { + bson_destroy(doc); + } + } + } + bool append(const std::string &json) + { + if (!json.empty()) + { + bson_t *doc = bson_new_from_json((const uint8_t *)(json.c_str()), -1, (&m_err)); + if (doc) + { + m_docs.push_back(doc); + return true; + } + }; + return false; + } + std::vector *get() { return (&m_docs); } + bson_error_t *err() { return (&m_err); } + }; + + template <> + struct qx_scoped_wrapper + { + mongoc_bulk_operation_t *m_bulk; + qx_scoped_wrapper(mongoc_collection_t *coll, const bson_t *opts) : m_bulk(NULL) + { + if (coll) + { + m_bulk = mongoc_collection_create_bulk_operation_with_opts(coll, opts); + } + } + ~qx_scoped_wrapper() + { + if (m_bulk) + { + mongoc_bulk_operation_destroy(m_bulk); + } + } + mongoc_bulk_operation_t *get() { return m_bulk; } + }; + + template <> + struct qx_scoped_wrapper + { + bson_t *m_opts; + bson_error_t m_err; + qx_scoped_wrapper(const std::string &json) : m_opts(NULL) + { + if (!json.empty()) + { + m_opts = bson_new_from_json((const uint8_t *)(json.c_str()), -1, (&m_err)); + } + } + ~qx_scoped_wrapper() + { + if (m_opts) + { + bson_destroy(m_opts); + } + } + const bson_t *get() const { return const_cast(m_opts); } + bson_error_t *err() { return (&m_err); } + }; + typedef std::unique_ptr> qx_opts_ptr; + + template <> + struct qx_scoped_wrapper + { + bson_t m_reply; + bool m_destroy; + QString m_json; + QVariantMap m_values; + qx_scoped_wrapper() : m_destroy(true) { ; } + ~qx_scoped_wrapper() + { + if (m_destroy) + { + bson_destroy(&m_reply); + } + } + QString toString() + { + if (!m_json.isEmpty()) + { + return m_json; + }; + char *s = bson_as_relaxed_extended_json((&m_reply), NULL); + m_json = QString(s); + bson_free(s); + return m_json; + } + QVariantMap &values() + { + if (m_values.isEmpty()) + { + QString txt = toString(); + qx::serialization::json::from_string(m_values, txt); + }; + return m_values; + } + QVariant value(const QString &key) { return (values().contains(key) ? values().value(key) : QVariant()); } + void log() + { + QString txt = toString(); + qDebug("[QxOrm] MongoDB database reply : %s", qPrintable(txt)); + } + bson_t *get() { return (&m_reply); } + }; + typedef std::unique_ptr> qx_reply_ptr; + + struct qx_db_collection + { + std::shared_ptr> client; + std::shared_ptr> db; + std::shared_ptr> collection; + }; + + struct Q_DECL_HIDDEN QxMongoDB_Helper::QxMongoDB_HelperImpl + { + + QMutex m_oDbMutex; //!< Mutex => 'QxMongoDB_Helper' is thread-safe + std::unique_ptr> m_pInstance; //!< MongoDB database driver instance + std::unique_ptr> m_pUri; //!< MongoDB database uri (connection string) + std::unique_ptr> m_pPool; //!< MongoDB database pool to get client connections + QHash m_lstOpts; //!< MongoDB database options per action (based on QxMongoDB_Helper::opts enum) + bool m_bLogDatabaseReply; //!< Log MongoDB database replies + bool m_bLogDatabaseInfo; //!< Log MongoDB database info (ping, server name, etc...) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + QRegularExpression m_regExpCheckNumber; //!< Regular expression to check if a string contains only numbers +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + QxMongoDB_HelperImpl() : m_bLogDatabaseReply(false), m_bLogDatabaseInfo(true) + { + m_pInstance.reset(new qx_scoped_wrapper()); + m_regExpCheckNumber = QRegularExpression(QRegularExpression::anchoredPattern("\\d*")); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + QxMongoDB_HelperImpl() : m_bLogDatabaseReply(false), m_bLogDatabaseInfo(true) { m_pInstance.reset(new qx_scoped_wrapper()); } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + ~QxMongoDB_HelperImpl() + { + m_pPool.reset(); + m_pUri.reset(); + m_pInstance.reset(); + } + + QSqlError insertOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, QString &insertedId); + QSqlError insertMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, QStringList &insertedId); + QSqlError updateOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query); + QSqlError updateMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query); + QSqlError deleteOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query); + QSqlError deleteMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query); + QSqlError findOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QString &json, const qx::QxSqlQuery *query); + QSqlError findMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query, QxMongoDB_Fetcher *pFetcher); + QSqlError aggregate_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query, const QString &lookup, QxMongoDB_Fetcher *pFetcher, bool bModeDelete = false); + QSqlError count_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, long &cnt, const qx::QxSqlQuery *query); + QSqlError executeCommand_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, qx::QxSqlQuery *query); + + QSqlError initPool() + { + { + if (m_pPool) + { + return QSqlError(); + } + QMutexLocker locker(&m_oDbMutex); + if (m_pPool) + { + return QSqlError(); + } + + QString uri; + qx::QxSqlDatabase *db = qx::QxSqlDatabase::getSingleton(); + int port = db->getPort(); + if (port == -1) + { + port = 27017; + } + if (!db->getUserName().isEmpty()) + { + uri += db->getUserName(); + } + if (!db->getUserName().isEmpty() && !db->getPassword().isEmpty()) + { + uri += ":" + db->getPassword() + "@"; + } + if (!db->getHostName().isEmpty()) + { + uri += db->getHostName() + ":" + QString::number(port); + } + if (!db->getConnectOptions().isEmpty()) + { + uri += "/?" + db->getConnectOptions(); + } + if (!uri.isEmpty()) + { + uri = "mongodb://" + uri; + } + if (uri.isEmpty()) + { + return QSqlError("[QxOrm] Please define a connection string to a MongoDB database through 'qx::QxSqlDatabase::getSingleton()' settings", "", QSqlError::UnknownError); + } + if (m_bLogDatabaseInfo) + { + qDebug("[QxOrm] Connect to MongoDB database : %s", qPrintable(uri)); + } + + std::string uri_ = toStdString(uri); + m_pUri.reset(new qx_scoped_wrapper(uri_)); + if (!m_pUri->get()) + { + m_pUri.reset(); + return QSqlError("[QxOrm] Unable to create a 'mongoc_uri_t' instance to connect to MongoDB database (" + uri + ")", "", QSqlError::UnknownError); + } + m_pPool.reset(new qx_scoped_wrapper(m_pUri->get())); + if (!m_pPool->get()) + { + m_pPool.reset(); + m_pUri.reset(); + return QSqlError("[QxOrm] Unable to create a 'mongoc_client_pool_t' instance to connect to MongoDB database (" + uri + ")", "", QSqlError::UnknownError); + } + } + +#ifdef Q_COMPILER_INITIALIZER_LISTS + qx_query ping{{"ping", 1}}; +#else // Q_COMPILER_INITIALIZER_LISTS + qx_query ping("{ \"ping\": 1 }"); +#endif // Q_COMPILER_INITIALIZER_LISTS + QSqlError err = executeCommand_(NULL, NULL, (&ping)); + if (err.isValid()) + { + m_pPool.reset(); + m_pUri.reset(); + return err; + } + else + { + if (m_bLogDatabaseInfo) + { + qDebug("[QxOrm] Ping to MongoDB database server : %s", "OK"); + } + } + +#ifdef Q_COMPILER_INITIALIZER_LISTS + qx_query buildInfo{{"buildInfo", 1}}; +#else // Q_COMPILER_INITIALIZER_LISTS + qx_query buildInfo("{ \"buildInfo\": 1 }"); +#endif // Q_COMPILER_INITIALIZER_LISTS + err = executeCommand_(NULL, NULL, (&buildInfo)); + if (err.isValid()) + { + m_pPool.reset(); + m_pUri.reset(); + return err; + } + else + { + if (m_bLogDatabaseInfo) + { + QString resp = buildInfo.response().toString(); + qDebug("[QxOrm] Fetch build info from MongoDB database server : \n%s", qPrintable(resp)); + } + } + + return QSqlError(); + } + + QSqlError initCollection(qx::IxClass *pClass, qx_db_collection &coll) + { + if (!pClass) + { + return QSqlError("[QxOrm] Parameter 'qx::IxClass' is required to get MongoDB database collection name", "", QSqlError::UnknownError); + } + QSqlError err = initDatabase(coll); + if (err.isValid()) + { + return err; + } + std::string dbName = toStdString(qx::QxSqlDatabase::getSingleton()->getDatabaseName()); + coll.collection = std::make_shared>(coll.client->get(), dbName, toStdString(pClass->getName())); + if (!coll.collection->get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_collection_t' instance from MongoDB database (" + qx::QxSqlDatabase::getSingleton()->getDatabaseName() + " - " + pClass->getName() + ")", "", QSqlError::UnknownError); + } + return QSqlError(); + } + + QSqlError initDatabase(qx_db_collection &coll) + { + QSqlError err = initPool(); + if (err.isValid()) + { + return err; + } + coll.client = std::make_shared>(m_pPool->get()); + if (!coll.client->get()) + { + return QSqlError("[QxOrm] Unable to get a MongoDB client connection from pool of type 'mongoc_client_t'", "", QSqlError::UnknownError); + } + std::string dbName = toStdString(qx::QxSqlDatabase::getSingleton()->getDatabaseName()); + if (dbName.empty()) + { + return QSqlError("[QxOrm] Unable to connect to MongoDB database : please define a database name using qx::QxSqlDatabase::getSingleton()->setDatabaseName()", "", QSqlError::UnknownError); + } + coll.db = std::make_shared>(coll.client->get(), dbName); + if (!coll.db->get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_database_t' instance from MongoDB database (" + qx::QxSqlDatabase::getSingleton()->getDatabaseName() + ")", "", QSqlError::UnknownError); + } + return QSqlError(); + } + + std::string toStdString(const QString &s) const + { +#ifndef QT_NO_STL + return s.toStdString(); +#else // QT_NO_STL + return s.toLatin1().constData(); +#endif // QT_NO_STL + } + + QString asJson(const QString &s) const + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + QString json = s; + bool isNumber = m_regExpCheckNumber.match(s).hasMatch(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + QString json = s; + QRegExp regexp("\\d*"); + bool isNumber = regexp.exactMatch(s); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + if (s.startsWith("qx_oid:")) + { + return "{ \"$oid\": \"" + s.right(s.size() - 7) + "\" }"; + } + return ((isNumber ? QString() : QString("\"")) + json.replace("\"", "\\\"") + (isNumber ? QString() : QString("\""))); + } + + QSqlError checkInsertOID(bson_t *doc, qx::IxClass *pClass, QString &insertedId) + { + bson_iter_t itr; + if (!bson_iter_init_find((&itr), doc, "_id")) + { + bson_oid_t oid; + bson_oid_init((&oid), NULL); + if (!bson_append_oid(doc, "_id", -1, (&oid))) + { + return QSqlError("[QxOrm] Unable to append 'bson_oid_t' to document (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + char str[25]; + bson_oid_to_string((&oid), str); + insertedId = "qx_oid:" + QString(str); + } + return QSqlError(); + } + + bool setOptions_(QxMongoDB_Helper::opts e, const QString &optsAsJson) + { + int i = static_cast(e); + if (optsAsJson.isEmpty()) + { + m_lstOpts.remove(i); + return true; + } + m_lstOpts.insert(i, optsAsJson); + return true; + } + + QSqlError getOptions_(QxMongoDB_Helper::opts e, qx_opts_ptr &opts, const QString &customOpts = QString()) + { + opts.reset(); + int i = static_cast(e); + QString json = (customOpts.isEmpty() ? m_lstOpts.value(i) : customOpts); + if (json.isEmpty()) + { + return QSqlError(); + } + opts.reset(new qx_scoped_wrapper(toStdString(json))); + if (!opts->get()) + { + QString msg(opts->err()->message); + opts.reset(); + return QSqlError("[QxOrm] Unable to create a 'bson_t' options instance (" + QString::number(i) + " - " + json + ") from JSON : " + msg, "", QSqlError::UnknownError); + } + return QSqlError(); + } + + QString buildLookup(qx::dao::detail::IxDao_Helper *pDaoHelper, bool idAsArray, qx::QxSqlRelationLinked *pSubHierarchy = NULL, const QString &sTab = QString("\t"), QStringList *pSubFieldsAs = NULL) + { + qx::QxSqlRelationLinked *pHierarchy = (pSubHierarchy ? pSubHierarchy : (pDaoHelper ? pDaoHelper->getSqlRelationLinked() : NULL)); + if (!pHierarchy) + { + return QString(); + } + QString templFrom = "\n\t" + sTab + "\"from\": \"%COLL_TARGET%\""; + QString templLet = "\n\t" + sTab + "\"let\": { \"%COLL_LET_KEY%\": \"$%COLL_LET_VAL%\" }"; + QString templPipeline = "\n\t" + sTab + "\"pipeline\": [ { \"$match\": { \"$expr\": { \"$" + (idAsArray ? QString("in") : QString("eq")) + "\": [ \"$%COLL_EQ%\", \"$$%COLL_LET_KEY%\" ] } } } %NEXT_LEVEL_LOOKUP% %PROJECTION% ]"; + QString templAs = "\n\t" + sTab + "\"as\": \"%COLL_AS%\""; + QString templOneToMany = "\n" + sTab + "{ \"$lookup\": { " + templFrom + ", " + templLet + ", " + templPipeline + ", " + templAs + " } }"; + QString templManyToOne = templOneToMany + ",\n" + sTab + "{ \"$addFields\": { \"%COLL_AS%\": { \"$arrayElemAt\": [ \"$%COLL_AS%\", 0 ] } } }"; + QString templOneToOne = templManyToOne; + qx::QxSqlRelationLinked::type_lst_relation_linked pRelationsLinked = pHierarchy->getRelationLinkedX(); + qx::QxSqlRelationLinked::type_lst_relation pRelations = pHierarchy->getRelationX(); + QString result; + QStringList projectionFields; + QStringList subProjectionFields; + + for (auto itr = pRelations.begin(); itr != pRelations.end(); ++itr) + { + const QxSqlRelationLinked::type_relation &item = itr->second; + qx::IxSqlRelation *pRelation = std::get<1>(item); + if (!pRelation) + { + continue; + } + qx::IxSqlRelation::relation_type type = pRelation->getRelationType(); + if ((type != qx::IxSqlRelation::many_to_one) && (type != qx::IxSqlRelation::one_to_many) && (type != qx::IxSqlRelation::one_to_one)) + { + continue; + } + qx::IxDataMember *pDataMember = pRelation->getDataMember(); + if (!pDataMember) + { + continue; + } + qx::IxDataMember *pFromId = pRelation->getDataIdOwner(); + if (!pFromId) + { + continue; + } + qx::IxDataMember *pTargetId = pRelation->getDataId(); + if (!pTargetId) + { + continue; + } + qx::IxClass *pFrom = pRelation->getClassOwner(); + if (!pFrom) + { + continue; + } + qx::IxClass *pTarget = pRelation->getClass(); + if (!pTarget) + { + continue; + } + qx::QxSqlRelationLinked::type_ptr pRelationLinked = pRelationsLinked.value(pRelation->getKey()); + QString subLookup = (pRelationLinked ? buildLookup(pDaoHelper, false, pRelationLinked.get(), (sTab + "\t"), (&subProjectionFields)) : QString()); + if (!subLookup.isEmpty()) + { + subLookup = ", " + subLookup; + } + + QString lookup = ((type == qx::IxSqlRelation::many_to_one) ? templManyToOne : ((type == qx::IxSqlRelation::one_to_many) ? templOneToMany : templOneToOne)); + lookup.replace("%COLL_TARGET%", pTarget->getName()); + lookup.replace("%NEXT_LEVEL_LOOKUP%", subLookup); + lookup.replace("%COLL_AS%", pDataMember->getKey()); + if (pSubFieldsAs) + { + (*pSubFieldsAs) << pDataMember->getKey(); + } + else + { + projectionFields << pDataMember->getKey(); + } + + if (type == qx::IxSqlRelation::many_to_one) + { + qx::IxDataMember *pLinkRelationKey = pRelation->getLinkRelationKey(); + lookup.replace("%COLL_LET_KEY%", pDataMember->getKey()); + lookup.replace("%COLL_LET_VAL%", (pLinkRelationKey ? pLinkRelationKey->getKey() : pDataMember->getKey())); + lookup.replace("%COLL_EQ%", "_id"); + } + else if (type == qx::IxSqlRelation::one_to_many) + { + lookup.replace("%COLL_LET_KEY%", pRelation->getForeignKey()); + lookup.replace("%COLL_LET_VAL%", "_id"); + lookup.replace("%COLL_EQ%", pRelation->getForeignKey()); + } + else if (type == qx::IxSqlRelation::one_to_one) + { + qx::IxDataMember *pLinkRelationKey = pRelation->getLinkRelationKey(); + lookup.replace("%COLL_LET_KEY%", pDataMember->getKey()); + lookup.replace("%COLL_LET_VAL%", (pLinkRelationKey ? pLinkRelationKey->getKey() : pDataMember->getKey())); + lookup.replace("%COLL_EQ%", "_id"); + } + + QString projection; + QSet columns = std::get<2>(item).first; + if (columns.count() > 0) + { + long l = 0; + qx::IxDataMember *p = NULL; + while ((p = pRelation->nextData(l))) + { + if (p && columns.contains(p->getKey())) + { + projection += ((projection.isEmpty() ? QString("\"") : QString(", \"")) + p->getKey() + "\": 1"); + } + } + if (!projection.isEmpty()) + { + Q_FOREACH (QString s, subProjectionFields) + { + projection += ((projection.isEmpty() ? QString("\"") : QString(", \"")) + s + "\": 1"); + } + } + if (!projection.isEmpty()) + { + projection = ",\n\t" + sTab + "{ \"$project\": { " + projection + " } }"; + } + } + lookup.replace("%PROJECTION%", projection); + + result += ((result.isEmpty() ? QString() : QString(", ")) + lookup); + } + + QString project; + if (pDaoHelper && pHierarchy && !pSubHierarchy && !result.isEmpty()) + { + long l = 0; + qx::IxDataMember *p = NULL; + bool bIncludeAllFields = true; + while ((p = pDaoHelper->builder().nextData(l))) + { + if (p && pHierarchy->checkRootColumns(p->getKey())) + { + project += ((project.isEmpty() ? QString("\"") : QString(", \"")) + p->getKey() + "\": 1"); + } + else + { + bIncludeAllFields = false; + } + } + if (!project.isEmpty()) + { + Q_FOREACH (QString s, projectionFields) + { + project += ((project.isEmpty() ? QString("\"") : QString(", \"")) + s + "\": 1"); + } + } + if (!project.isEmpty()) + { + project = ",\n" + sTab + "{ \"$project\": { " + project + " } }"; + } + if (bIncludeAllFields) + { + project = ""; + } + } + + return (result + project); + } + }; + + QxMongoDB_Fetcher::QxMongoDB_Fetcher() { ; } + + QxMongoDB_Fetcher::~QxMongoDB_Fetcher() { ; } + + QxMongoDB_Helper::QxMongoDB_Helper() : QxSingleton("qx::dao::mongodb::QxMongoDB_Helper"), m_pImpl(new QxMongoDB_HelperImpl()) { ; } + + QxMongoDB_Helper::~QxMongoDB_Helper() { ; } + + QSqlError QxMongoDB_Helper::insertOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, QString &insertedId) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->insertOne_(pDaoHelper, pClass, json, insertedId); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::insertOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, QString &insertedId) + { + if (json.count() <= 0) + { + return QSqlError(); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB insert one '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json); + } + + qx_scoped_wrapper doc(toStdString(json)); + if (!doc.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document instance (" + pClass->getName() + ") from JSON : " + QString(doc.err()->message), "", QSqlError::UnknownError); + } + err = checkInsertOID(doc.get(), pClass, insertedId); + if (err.isValid()) + { + return err; + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + if (m_bLogDatabaseReply) + { + reply.reset(new qx_scoped_wrapper()); + } + err = getOptions_(QxMongoDB_Helper::opts_collection_insert_one, opts); + if (err.isValid()) + { + return err; + } + bool ok = mongoc_collection_insert_one(coll.collection->get(), doc.get(), (opts ? opts->get() : NULL), (reply ? reply->get() : NULL), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to insert one 'bson_t' document (" + pClass->getName() + ") to MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::insertMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, QStringList &insertedId) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->insertMany_(pDaoHelper, pClass, json, insertedId); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::insertMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, QStringList &insertedId) + { + if (json.count() <= 0) + { + return QSqlError(); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB insert many '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json.join(", \n")); + } + insertedId.clear(); + insertedId.reserve(json.count()); + + qx_scoped_wrapper> docs(json.count()); + Q_FOREACH (QString s, json) + { + if (s.isEmpty()) + { + continue; + } + if (!docs.append(toStdString(s))) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document instance (" + pClass->getName() + ") from JSON : " + QString(docs.err()->message), "", QSqlError::UnknownError); + } + QString oid; + err = checkInsertOID(docs.m_docs.back(), pClass, oid); + if (err.isValid()) + { + return err; + }; + insertedId.append(oid); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + const bson_t **docs_ = const_cast(docs.get()->data()); + if (m_bLogDatabaseReply) + { + reply.reset(new qx_scoped_wrapper()); + } + err = getOptions_(QxMongoDB_Helper::opts_collection_insert_many, opts); + if (err.isValid()) + { + return err; + } + bool ok = mongoc_collection_insert_many(coll.collection->get(), docs_, docs.get()->size(), (opts ? opts->get() : NULL), (reply ? reply->get() : NULL), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to insert many 'bson_t' documents (" + pClass->getName() + ") to MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::updateOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->updateOne_(pDaoHelper, pClass, json, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::updateOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query) + { + if (json.count() <= 0) + { + return QSqlError(); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB update one '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json + "\n" + (query ? query->queryAt(0) : QString())); + } + + qx_scoped_wrapper doc(toStdString(json)); + if (!doc.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document instance (" + pClass->getName() + ") from JSON : " + QString(doc.err()->message), "", QSqlError::UnknownError); + } + + qx_scoped_wrapper query_(toStdString((query ? query->queryAt(0) : QString()))); + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + if (!query || query->queryAt(0).isEmpty()) + { + bson_iter_t itr; + const bson_value_t *oid = (bson_iter_init_find((&itr), doc.get(), "_id") ? bson_iter_value(&itr) : NULL); + if (!oid) + { + return QSqlError("[QxOrm] Unable to find/fetch document oid '_id' (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + if (!bson_append_value(query_.get(), "_id", -1, oid)) + { + return QSqlError("[QxOrm] Unable to append 'bson_value_t' oid value to document (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + } + + qx_scoped_wrapper update_(""); + const bson_t *doc_ = const_cast(doc.get()); + if (!bson_append_document(update_.get(), "$set", -1, doc_)) + { + return QSqlError("[QxOrm] Unable to append 'bson_t' document for update query (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + reply.reset(new qx_scoped_wrapper()); + err = getOptions_(QxMongoDB_Helper::opts_collection_update_one, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + bool ok = mongoc_collection_update_one(coll.collection->get(), query_.get(), update_.get(), (opts ? opts->get() : NULL), (reply ? reply->get() : NULL), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to update one 'bson_t' document (" + pClass->getName() + ") to MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply && (reply->value("matchedCount").toInt() < 1)) + { + return QSqlError("[QxOrm] Nothing has been updated (" + pClass->getName() + ") in MongoDB database", "", QSqlError::UnknownError); + } + if (reply && m_bLogDatabaseReply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::updateMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->updateMany_(pDaoHelper, pClass, json, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::updateMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query) + { + if (json.count() <= 0) + { + return QSqlError(); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB update many '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json.join(", \n") + "\n" + (query ? query->queryAt(0) : QString())); + } + + qx_opts_ptr optsBulk; + err = getOptions_(QxMongoDB_Helper::opts_collection_create_bulk_operation, optsBulk); + if (err.isValid()) + { + return err; + } + qx_scoped_wrapper bulk(coll.collection->get(), (optsBulk ? optsBulk->get() : NULL)); + if (!bulk.get()) + { + return QSqlError("[QxOrm] Unable to create 'mongoc_bulk_operation_t' bulk operation instance (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + qx_opts_ptr opts; + err = getOptions_(QxMongoDB_Helper::opts_bulk_operation_update_one, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + int iUpdateCount = 0; + + Q_FOREACH (QString s, json) + { + if (s.isEmpty()) + { + continue; + } + qx_scoped_wrapper doc(toStdString(s)); + if (!doc.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document instance (" + pClass->getName() + ") from JSON : " + QString(doc.err()->message), "", QSqlError::UnknownError); + } + + qx_scoped_wrapper query_(toStdString((query ? query->queryAt(0) : QString()))); + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + if (!query || query->queryAt(0).isEmpty()) + { + bson_iter_t itr; + const bson_value_t *oid = (bson_iter_init_find((&itr), doc.get(), "_id") ? bson_iter_value(&itr) : NULL); + if (!oid) + { + return QSqlError("[QxOrm] Unable to find/fetch document oid '_id' (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + if (!bson_append_value(query_.get(), "_id", -1, oid)) + { + return QSqlError("[QxOrm] Unable to append 'bson_value_t' oid value to document (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + } + + qx_scoped_wrapper update_(""); + const bson_t *doc_ = const_cast(doc.get()); + if (!bson_append_document(update_.get(), "$set", -1, doc_)) + { + return QSqlError("[QxOrm] Unable to append 'bson_t' document for update query (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + bson_error_t bsonErr; + if (!mongoc_bulk_operation_update_one_with_opts(bulk.get(), query_.get(), update_.get(), (opts ? opts->get() : NULL), (&bsonErr))) + { + return QSqlError("[QxOrm] Unable to append update bulk operation (" + pClass->getName() + ") : " + QString(bsonErr.message), "", QSqlError::UnknownError); + } + iUpdateCount++; + } + + bson_error_t bsonError; + qx_reply_ptr reply; + reply.reset(new qx_scoped_wrapper()); + bool ok = mongoc_bulk_operation_execute(bulk.get(), reply->get(), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to update many 'bson_t' documents (" + pClass->getName() + ") to MongoDB database (bulk operation) : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply && (reply->value("nMatched").toInt() != iUpdateCount)) + { + return QSqlError("[QxOrm] Not everything has been updated (" + pClass->getName() + ") in MongoDB database (result:'" + QString::number(reply->value("nMatched").toInt()) + "', expected:'" + QString::number(iUpdateCount) + "')", "", QSqlError::UnknownError); + } + if (m_bLogDatabaseReply && reply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::deleteOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->deleteOne_(pDaoHelper, pClass, json, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::deleteOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QString &json, const qx::QxSqlQuery *query) + { + if (json.isEmpty() && !query) + { + return QSqlError(); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB delete one '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json + "\n" + (query ? query->queryAt(0) : QString())); + } + + qx_scoped_wrapper query_(toStdString((query ? query->queryAt(0) : json))); + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + reply.reset(new qx_scoped_wrapper()); + err = getOptions_(QxMongoDB_Helper::opts_collection_delete_one, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + bool ok = mongoc_collection_delete_one(coll.collection->get(), query_.get(), (opts ? opts->get() : NULL), (reply ? reply->get() : NULL), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to delete one 'bson_t' document (" + pClass->getName() + ") in MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply && (reply->value("deletedCount").toInt() < 1)) + { + return QSqlError("[QxOrm] Nothing has been deleted (" + pClass->getName() + ") in MongoDB database", "", QSqlError::UnknownError); + } + if (reply && m_bLogDatabaseReply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::deleteMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->deleteMany_(pDaoHelper, pClass, json, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::deleteMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, const QStringList &json, const qx::QxSqlQuery *query) + { + if ((json.count() <= 0) && (!query)) + { + return QSqlError(); + } + if (query && (query->type() == "aggregate")) + { + QStringList empty; + return aggregate_(pDaoHelper, pClass, empty, query, "", NULL, true); + } + QString listId = (query ? QString() : ((json.count() > 0) ? QString("{ \"_id\": { \"$in\": [ %ID% ] } }") : QString())); + if (!listId.isEmpty()) + { + QString ids; + Q_FOREACH (QString s, json) + { + ids += asJson(s) + ", "; + }; + ids = ids.left(ids.count() - 2); + listId.replace("%ID%", ids); + } + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB delete many '" + (pClass ? pClass->getName() : QString()) + "' :\n" + json.join(", \n") + "\n" + (query ? query->queryAt(0) : QString())); + } + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + + qx_scoped_wrapper query_(toStdString((query ? query->queryAt(0) : listId))); + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + if (m_bLogDatabaseReply) + { + reply.reset(new qx_scoped_wrapper()); + } + err = getOptions_(QxMongoDB_Helper::opts_collection_delete_many, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + bool ok = mongoc_collection_delete_many(coll.collection->get(), query_.get(), (opts ? opts->get() : NULL), (reply ? reply->get() : NULL), (&bsonError)); + if (!ok) + { + return QSqlError("[QxOrm] Unable to delete many 'bson_t' documents (" + pClass->getName() + ") in MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (reply) + { + reply->log(); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::findOne(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QString &json, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->findOne_(pDaoHelper, pClass, json, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::findOne_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QString &json, const qx::QxSqlQuery *query) + { + QString lookup = buildLookup(pDaoHelper, false); + QSqlError err; + if ((!lookup.isEmpty()) || (query && (query->type() == "aggregate"))) + { + QStringList result; + if ((!query) && (!json.isEmpty())) + { + qx_query query_tmp(json); + err = aggregate_(pDaoHelper, pClass, result, (&query_tmp), lookup, NULL); + } + else + { + err = aggregate_(pDaoHelper, pClass, result, query, lookup, NULL); + } + json = ((result.count() > 0) ? result.at(0) : QString()); + return err; + } + + QString id = (query ? QString() : json); + json = QString(); + qx_db_collection coll; + err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + + QString findQuery = (query ? query->queryAt(0) : id); + qx_scoped_wrapper query_(toStdString(findQuery)); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB find one '" + (pClass ? pClass->getName() : QString()) + "' :\n" + findQuery); + } + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + QStringList columns = (pDaoHelper ? pDaoHelper->getSqlColumns() : QStringList()); + QString projection; + Q_FOREACH (QString col, columns) + { + projection += (col.isEmpty() ? QString() : ((projection.isEmpty() ? QString("\"") : QString(", \"")) + col + "\": 1")); + } + projection = (projection.isEmpty() ? QString() : QString("{ \"projection\": { " + projection + " } }")); + + QString customOpts = ((query && !query->queryAt(1).isEmpty()) ? query->queryAt(1) : projection); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB find one '" + (pClass ? pClass->getName() : QString()) + "' :\n" + findQuery + "\n" + customOpts); + } + qx_opts_ptr opts; + err = getOptions_(QxMongoDB_Helper::opts_collection_find, opts, customOpts); + if (err.isValid()) + { + return err; + } + mongoc_cursor_t *cursor_ = mongoc_collection_find_with_opts(coll.collection->get(), query_.get(), (opts ? opts->get() : NULL), NULL); + + qx_scoped_wrapper cursor(cursor_); + if (!cursor.get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_cursor_t' cursor instance (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + const bson_t *doc = NULL; + if (mongoc_cursor_next(cursor.get(), (&doc))) + { + char *val = bson_as_relaxed_extended_json(doc, NULL); + json = QString(val); + bson_free(val); + } + + bson_error_t bsonError; + if (mongoc_cursor_error(cursor.get(), (&bsonError))) + { + return QSqlError("[QxOrm] MongoDB cursor error trying to find one document (" + pClass->getName() + ") : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::findMany(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query /* = NULL */, QxMongoDB_Fetcher *pFetcher /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->findMany_(pDaoHelper, pClass, json, query, pFetcher); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::findMany_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query, QxMongoDB_Fetcher *pFetcher) + { + QString lookup = buildLookup(pDaoHelper, false); + if ((!lookup.isEmpty()) || (query && (query->type() == "aggregate"))) + { + return aggregate_(pDaoHelper, pClass, json, query, lookup, pFetcher); + } + + QString listId = (query ? QString() : ((json.count() > 0) ? QString("{ \"_id\": { \"$in\": [ %ID% ] } }") : QString())); + if (!listId.isEmpty()) + { + QString ids; + Q_FOREACH (QString s, json) + { + ids += asJson(s) + ", "; + }; + ids = ids.left(ids.count() - 2); + listId.replace("%ID%", ids); + } + json.clear(); + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + + QString findQuery = (query ? query->queryAt(0) : listId); + qx_scoped_wrapper query_(toStdString((findQuery))); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB find many '" + (pClass ? pClass->getName() : QString()) + "' :\n" + findQuery); + } + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + QStringList columns = (pDaoHelper ? pDaoHelper->getSqlColumns() : QStringList()); + QString projection; + Q_FOREACH (QString col, columns) + { + projection += (col.isEmpty() ? QString() : ((projection.isEmpty() ? QString("\"") : QString(", \"")) + col + "\": 1")); + } + projection = (projection.isEmpty() ? QString() : QString("{ \"projection\": { " + projection + " } }")); + + QString customOpts = ((query && !query->queryAt(1).isEmpty()) ? query->queryAt(1) : projection); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB find many '" + (pClass ? pClass->getName() : QString()) + "' :\n" + findQuery + "\n" + customOpts); + } + qx_opts_ptr opts; + err = getOptions_(QxMongoDB_Helper::opts_collection_find, opts, customOpts); + if (err.isValid()) + { + return err; + } + mongoc_cursor_t *cursor_ = mongoc_collection_find_with_opts(coll.collection->get(), query_.get(), (opts ? opts->get() : NULL), NULL); + + qx_scoped_wrapper cursor(cursor_); + if (!cursor.get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_cursor_t' cursor instance (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + const bson_t *doc = NULL; + while (mongoc_cursor_next(cursor.get(), (&doc))) + { + char *val = bson_as_relaxed_extended_json(doc, NULL); + if (pFetcher) + { + QString tmp(val); + pFetcher->fetch(tmp); + if (pDaoHelper && (!pDaoHelper->isValid())) + { + bson_free(val); + return pDaoHelper->error(); + } + } + else + { + json << QString(val); + } + bson_free(val); + } + + bson_error_t bsonError; + if (mongoc_cursor_error(cursor.get(), (&bsonError))) + { + return QSqlError("[QxOrm] MongoDB cursor error trying to find many documents (" + pClass->getName() + ") : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::aggregate(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query /* = NULL */, const QString &lookup /* = QString() */, QxMongoDB_Fetcher *pFetcher /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->aggregate_(pDaoHelper, pClass, json, query, lookup, pFetcher); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::aggregate_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, QStringList &json, const qx::QxSqlQuery *query, const QString &lookup, QxMongoDB_Fetcher *pFetcher, bool bModeDelete /* = false */) + { + QString listId = (query ? QString() : ((json.count() > 0) ? QString("{ \"_id\": { \"$in\": [ %ID% ] } }") : QString())); + if (!listId.isEmpty()) + { + QString ids; + Q_FOREACH (QString s, json) + { + ids += asJson(s) + ", "; + }; + ids = ids.left(ids.count() - 2); + listId.replace("%ID%", ids); + } + json.clear(); + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + + QString findQuery = (query ? query->queryAt(0) : listId); + if (!lookup.isEmpty() && !findQuery.isEmpty()) + { + findQuery = "[ { \"$match\": " + findQuery + " }, " + lookup + " ]"; + } + else if (!lookup.isEmpty() && findQuery.isEmpty()) + { + findQuery = "[ " + lookup + " ]"; + } + + qx_scoped_wrapper query_(toStdString((findQuery))); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB aggregate '" + (pClass ? pClass->getName() : QString()) + "' :\n" + findQuery); + } + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + qx_opts_ptr opts; + err = getOptions_(QxMongoDB_Helper::opts_collection_aggregate, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + mongoc_cursor_t *cursor_ = mongoc_collection_aggregate(coll.collection->get(), MONGOC_QUERY_NONE, query_.get(), (opts ? opts->get() : NULL), NULL); + + qx_scoped_wrapper cursor(cursor_); + if (!cursor.get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_cursor_t' cursor instance (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + const bson_t *doc = NULL; + QStringList listIdsToDelete; + while (mongoc_cursor_next(cursor.get(), (&doc))) + { + char *val = bson_as_relaxed_extended_json(doc, NULL); + if (bModeDelete) + { + QJsonValue obj; + QString tmp(val); + qx::cvt::from_string(tmp, obj); + if (obj.isObject()) + { + QJsonValue id = obj.toObject().value("_id"); + qx::cvt::from_json(id, tmp, "mongodb"); + if (!tmp.isEmpty()) + { + listIdsToDelete.append(tmp); + } + } + } + else if (pFetcher) + { + QString tmp(val); + pFetcher->fetch(tmp); + if (pDaoHelper && (!pDaoHelper->isValid())) + { + bson_free(val); + return pDaoHelper->error(); + } + } + else + { + json << QString(val); + } + bson_free(val); + } + + bson_error_t bsonError; + if (mongoc_cursor_error(cursor.get(), (&bsonError))) + { + return QSqlError("[QxOrm] MongoDB cursor error trying to find many documents (" + pClass->getName() + ") : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + if (bModeDelete && (listIdsToDelete.count() > 0)) + { + return deleteMany_(pDaoHelper, pClass, listIdsToDelete, NULL); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::executeCommand(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, qx::QxSqlQuery *query) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->executeCommand_(pDaoHelper, pClass, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::executeCommand_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, qx::QxSqlQuery *query) + { + if (!query) + { + return QSqlError("[QxOrm] Unable to execute command in MongoDB database : 'query' parameter is required", "", QSqlError::UnknownError); + } + query->setResponse(QVariant()); + qx_db_collection coll; + QSqlError err = (pClass ? initCollection(pClass, coll) : initDatabase(coll)); + if (err.isValid()) + { + return err; + } + QString collName = (pClass ? pClass->getName() : QString()); + + qx_scoped_wrapper cmd_(toStdString((query ? query->queryAt(0) : QString()))); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB command '" + (pClass ? pClass->getName() : QString()) + "' :\n" + (query ? query->queryAt(0) : QString())); + } + if (!cmd_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/command instance (" + collName + ") from JSON : " + QString(cmd_.err()->message), "", QSqlError::UnknownError); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + qx_reply_ptr reply; + reply.reset(new qx_scoped_wrapper()); + err = getOptions_(QxMongoDB_Helper::opts_collection_command, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + + if (!pClass) + { + if (!mongoc_database_command_with_opts(coll.db->get(), cmd_.get(), NULL, (opts ? opts->get() : NULL), reply->get(), (&bsonError))) + { + return QSqlError("[QxOrm] Unable to execute command in MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + } + else + { + if (!mongoc_collection_command_with_opts(coll.collection->get(), cmd_.get(), NULL, (opts ? opts->get() : NULL), reply->get(), (&bsonError))) + { + return QSqlError("[QxOrm] Unable to execute command (" + collName + ") in MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + } + + if (query && (query->type() == "cursor")) + { + reply->m_destroy = false; + qx_scoped_wrapper cursor(mongoc_cursor_new_from_command_reply(coll.client->get(), reply->get(), 0)); + if (!cursor.get()) + { + return QSqlError("[QxOrm] Unable to create a 'mongoc_cursor_t' cursor instance from reply (" + pClass->getName() + ")", "", QSqlError::UnknownError); + } + + const bson_t *doc = NULL; + QString json; + while (mongoc_cursor_next(cursor.get(), (&doc))) + { + char *val = bson_as_relaxed_extended_json(doc, NULL); + json += ((json.isEmpty() ? QString() : QString(",\n")) + QString(val)); + bson_free(val); + } + if (!json.isEmpty()) + { + json = "[ " + json + " ]"; + } + query->setResponse(QVariant(json)); + + bson_error_t bsonError; + if (mongoc_cursor_error(cursor.get(), (&bsonError))) + { + return QSqlError("[QxOrm] MongoDB cursor error trying to find many documents from reply (" + pClass->getName() + ") : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + } + else + { + const bson_t *reply_ = const_cast(reply->get()); + char *val = bson_as_relaxed_extended_json(reply_, NULL); + query->setResponse(QVariant(QString(val))); + bson_free(val); + } + + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::count(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, long &cnt, const qx::QxSqlQuery *query /* = NULL */) + { + qx::dao::detail::IxDao_Timer timer(pDaoHelper, qx::dao::detail::IxDao_Helper::timer_db_exec); + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QSqlError err = pSingleton->m_pImpl->count_(pDaoHelper, pClass, cnt, query); + return (pDaoHelper ? pDaoHelper->updateError(err) : err); + } + + QSqlError QxMongoDB_Helper::QxMongoDB_HelperImpl::count_(qx::dao::detail::IxDao_Helper *pDaoHelper, qx::IxClass *pClass, long &cnt, const qx::QxSqlQuery *query) + { + cnt = 0; + qx_db_collection coll; + QSqlError err = initCollection(pClass, coll); + if (err.isValid()) + { + return err; + } + + qx_scoped_wrapper query_(toStdString((query ? query->queryAt(0) : QString()))); + if (pDaoHelper) + { + pDaoHelper->qxQuery().queryAt(0, "MongoDB count '" + (pClass ? pClass->getName() : QString()) + "' :\n" + (query ? query->queryAt(0) : QString())); + } + if (!query_.get()) + { + return QSqlError("[QxOrm] Unable to create a 'bson_t' document/query instance (" + pClass->getName() + ") from JSON : " + QString(query_.err()->message), "", QSqlError::UnknownError); + } + + bson_error_t bsonError; + qx_opts_ptr opts; + err = getOptions_(QxMongoDB_Helper::opts_collection_count, opts, (query ? query->queryAt(1) : QString())); + if (err.isValid()) + { + return err; + } + cnt = static_cast(mongoc_collection_count_with_opts(coll.collection->get(), MONGOC_QUERY_NONE, query_.get(), 0, 0, (opts ? opts->get() : NULL), NULL, (&bsonError))); + if (cnt < 0) + { + cnt = 0; + return QSqlError("[QxOrm] Unable to count 'bson_t' documents (" + pClass->getName() + ") in MongoDB database : " + QString(bsonError.message), "", QSqlError::UnknownError); + } + return QSqlError(); + } + + QSqlError QxMongoDB_Helper::autoCreateIndexes(bool log /* = true */) + { + qx::QxClassX::registerAllClasses(); + qx::QxCollection *pAllClasses = qx::QxClassX::getAllClasses(); + if (!pAllClasses) + { + return QSqlError("[QxOrm] Unable to get all classes registered in QxOrm context", "", QSqlError::UnknownError); + } + + for (auto itr = pAllClasses->begin(); itr != pAllClasses->end(); ++itr) + { + qx::IxClass *pClass = itr->second; + if (!pClass || pClass->isAbstract()) + { + continue; + } + QString collectionName = pClass->getName(); + + do + { + qx::IxDataMemberX *pDataMemberX = pClass->getDataMemberX(); + long cnt = (pDataMemberX ? pDataMemberX->count() : 0); + for (long l = 0; l < cnt; l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getDao() || pDataMember->getIsPrimaryKey()) + { + continue; + } + qx::IxSqlRelation *pRelation = pDataMember->getSqlRelation(); + bool isIndex = pDataMember->getIsIndex(); + if (!isIndex && !pRelation) + { + continue; + } + qx::IxSqlRelation::relation_type eRelationType = (pRelation ? pRelation->getRelationType() : qx::IxSqlRelation::no_relation); + bool isUnique = pDataMember->getIsUnique(); + + QString idxName; + if (eRelationType == qx::IxSqlRelation::many_to_one) + { + idxName = "idx_" + collectionName + "_" + pDataMember->getKey() + "_many_to_one"; + } + else if (eRelationType == qx::IxSqlRelation::one_to_one) + { + idxName = "idx_" + collectionName + "_" + pDataMember->getKey() + "_one_to_one"; + } + else if (isIndex) + { + idxName = "idx_" + collectionName + "_" + pDataMember->getKey(); + } + if (idxName.isEmpty()) + { + continue; + } + + QString query_ = "{ \"createIndexes\": \"" + collectionName + "\", \"indexes\": "; + query_ += "[ { \"key\": { \"" + pDataMember->getKey() + "\": 1 }, \"name\": \"" + idxName + "\"" + (isUnique ? QString(", \"unique\": true") : QString()) + " } ] }"; + qx_query query(query_); + + if (log) + { + QString msg = "MongoDB create index for '" + collectionName + "::" + pDataMember->getKey() + "', request : " + query_; + qDebug("[QxOrm] %s", qPrintable(msg)); + } + QSqlError err = executeCommand(NULL, NULL, (&query)); + if (err.isValid()) + { + return err; + } + if (log) + { + QString response = query.response().toString(); + QString msg = "MongoDB create index for '" + collectionName + "::" + pDataMember->getKey() + "', response : " + response; + qDebug("[QxOrm] %s", qPrintable(msg)); + } + } + pClass = pClass->getBaseClass(); + } while (pClass != NULL); + } + + return QSqlError(); + } + + bool QxMongoDB_Helper::setOptions(QxMongoDB_Helper::opts e, const QString &optsAsJson) + { + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + return pSingleton->m_pImpl->setOptions_(e, optsAsJson); + } + + void QxMongoDB_Helper::setLogDatabaseReply(bool b) + { + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + pSingleton->m_pImpl->m_bLogDatabaseReply = b; + } + + void QxMongoDB_Helper::setLogDatabaseInfo(bool b) + { + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + pSingleton->m_pImpl->m_bLogDatabaseInfo = b; + } + + void QxMongoDB_Helper::clearPoolConnection() + { + QxMongoDB_Helper *pSingleton = QxMongoDB_Helper::getSingleton(); + qAssert(pSingleton != NULL); + QMutexLocker locker(&pSingleton->m_pImpl->m_oDbMutex); + pSingleton->m_pImpl->m_pPool.reset(); + pSingleton->m_pImpl->m_pUri.reset(); + } + + } // namespace mongodb + } // namespace dao +} // namespace qx + +#endif // _QX_ENABLE_MONGODB diff --git a/src/QxDao/QxRepository/IxRepository.cpp b/src/QxDao/QxRepository/IxRepository.cpp new file mode 100644 index 0000000..b4f482a --- /dev/null +++ b/src/QxDao/QxRepository/IxRepository.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + + IxRepository::IxRepository(bool bRegister, const QString &sKey) : m_bRegister(bRegister), m_sKeyRepository(sKey), m_pSession(NULL) + { + if (m_bRegister && !m_sKeyRepository.isEmpty()) + { + QxRepositoryX::getSingleton()->registerRepository(m_sKeyRepository, this); + } + } + + IxRepository::IxRepository(bool bRegister, const QString &sKey, const QSqlDatabase &database) : m_bRegister(bRegister), m_sKeyRepository(sKey), m_database(database), m_pSession(NULL) + { + if (m_bRegister && !m_sKeyRepository.isEmpty()) + { + QxRepositoryX::getSingleton()->registerRepository(m_sKeyRepository, this); + } + } + + IxRepository::IxRepository(bool bRegister, const QString &sKey, QxSession *pSession) : m_bRegister(bRegister), m_sKeyRepository(sKey), m_pSession(pSession) + { + if (m_bRegister && !m_sKeyRepository.isEmpty()) + { + QxRepositoryX::getSingleton()->registerRepository(m_sKeyRepository, this); + } + } + + IxRepository::~IxRepository() + { + if (m_bRegister && !m_sKeyRepository.isEmpty() && !QxRepositoryX::isSingletonNull()) + { + QxRepositoryX::getSingleton()->unregisterRepository(m_sKeyRepository); + } + } + + QSqlDatabase *IxRepository::database() + { + if (m_pSession) + { + return (m_pSession->database()->isValid() ? m_pSession->database() : NULL); + } + return (m_database.isValid() ? (&m_database) : NULL); + } + + QxSession *IxRepository::session() const + { + return m_pSession; + } + + qx::IxCollection_ptr IxRepository::_fetchAll(const QString &repositoryKey, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */) + { + IxRepository *pRepository = QxRepositoryX::get(repositoryKey); + if (!pRepository) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxRepository::_fetchAll() : 'invalid repository key, unable to get repository pointer'", "", QSqlError::UnknownError)); + } + qx::IxCollection_ptr lst = pRepository->_newCollection(); + if (!lst) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxRepository::_fetchAll() : 'unable to create a new collection from repository'", "", QSqlError::UnknownError)); + } + QSqlError daoError = pRepository->_fetchAll(lst.get(), columns, relation); + if (daoError.isValid()) + { + throw qx::dao::sql_error(daoError); + } + return lst; + } + + qx::IxCollection_ptr IxRepository::_fetchByQuery(const QString &repositoryKey, const qx::QxSqlQuery &query, const QStringList &columns /* = QStringList() */, const QStringList &relation /* = QStringList() */) + { + IxRepository *pRepository = QxRepositoryX::get(repositoryKey); + if (!pRepository) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxRepository::_fetchByQuery() : 'invalid repository key, unable to get repository pointer'", "", QSqlError::UnknownError)); + } + qx::IxCollection_ptr lst = pRepository->_newCollection(); + if (!lst) + { + throw qx::dao::sql_error(QSqlError("[QxOrm] qx::IxRepository::_fetchByQuery() : 'unable to create a new collection from repository'", "", QSqlError::UnknownError)); + } + QSqlError daoError = pRepository->_fetchByQuery(query, lst.get(), columns, relation); + if (daoError.isValid()) + { + throw qx::dao::sql_error(daoError); + } + return lst; + } + +} // namespace qx diff --git a/src/QxDao/QxRepository/QxRepositoryX.cpp b/src/QxDao/QxRepository/QxRepositoryX.cpp new file mode 100644 index 0000000..1792e5b --- /dev/null +++ b/src/QxDao/QxRepository/QxRepositoryX.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxRepositoryX) + +namespace qx +{ + + void QxRepositoryX::registerRepository(const QString &sKey, IxRepository *pRepository) + { + QMutexLocker locker(&m_oMutexRepositoryX); + qAssert(!sKey.isEmpty() && !m_mapRepositoryX.contains(sKey)); + if (!pRepository || sKey.isEmpty() || m_mapRepositoryX.contains(sKey)) + { + return; + } + m_mapRepositoryX.insert(sKey, pRepository); + } + + void QxRepositoryX::unregisterRepository(const QString &sKey) + { + if (m_bUnregisterAllRepository) + { + return; + } + QMutexLocker locker(&m_oMutexRepositoryX); + IxRepository *pRepository = (m_mapRepositoryX.contains(sKey) ? m_mapRepositoryX.value(sKey) : NULL); + if (pRepository) + { + delete pRepository; + pRepository = NULL; + } + m_mapRepositoryX.remove(sKey); + } + + void QxRepositoryX::unregisterAllRepository() + { + m_bUnregisterAllRepository = true; + QMutexLocker locker(&m_oMutexRepositoryX); + QHashIterator itr(m_mapRepositoryX); + while (itr.hasNext()) + { + itr.next(); + delete itr.value(); + } + m_mapRepositoryX.clear(); + m_bUnregisterAllRepository = false; + } + + IxRepository *QxRepositoryX::get(const QString &sKey) + { + if (!QxRepositoryX::getSingleton()->m_mapRepositoryX.contains(sKey)) + { + return NULL; + } + return QxRepositoryX::getSingleton()->m_mapRepositoryX.value(sKey); + } + +} // namespace qx diff --git a/src/QxDao/QxSession.cpp b/src/QxDao/QxSession.cpp new file mode 100644 index 0000000..a8ab055 --- /dev/null +++ b/src/QxDao/QxSession.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN QxSession::QxSessionImpl + { + + QSqlDatabase m_database; //!< Database connexion of current session + QList m_lstSqlError; //!< List of SQL errors + bool m_bTransaction; //!< Flag to know if a transaction is opened or not + bool m_bThrowable; //!< When a SQL error is appended, an exception of type qx::dao::sql_error is thrown + bool m_bThrowInEvent; //!< An exception of type qx::dao::sql_error is throwing + bool m_bAutoOpenClose; //!< Open and close automatically connection to database + bool m_bIgnoreSoftDelete; //!< Ignore soft delete behavior even if it has been defined for registered classes + QStringList m_lstIgnoreSoftDelete; //!< List of registered classes to ignore soft delete behavior (if empty and m_bIgnoreSoftDelete is true, then all classes are ignored) + bool m_bAutoRollbackWhenDestroyed; //!< If true, then database rollback is called when this session instance destructor (or close() method) is invoked + QPair m_sessionId; //!< Session identifier based on connection name and current thread + + static QMutex m_mutex; //!< Mutex => qx::QxSession is thread-safe + static QHash, qx::QxSession *> m_lstActiveSessions; //!< List of active sessions by database connection name + + QxSessionImpl() : m_bTransaction(false), m_bThrowable(false), m_bThrowInEvent(false), m_bAutoOpenClose(false), m_bIgnoreSoftDelete(false), m_bAutoRollbackWhenDestroyed(false) { ; } + QxSessionImpl(const QSqlDatabase &database) : m_database(database), m_bTransaction(false), m_bThrowable(false), m_bThrowInEvent(false), m_bAutoOpenClose(false), m_bIgnoreSoftDelete(false), m_bAutoRollbackWhenDestroyed(false) { ; } + QxSessionImpl(const QSqlDatabase &database, bool bThrowable, bool bAutoRollbackWhenDestroyed) : m_database(database), m_bTransaction(false), m_bThrowable(bThrowable), m_bThrowInEvent(false), m_bAutoOpenClose(false), m_bIgnoreSoftDelete(false), m_bAutoRollbackWhenDestroyed(bAutoRollbackWhenDestroyed) { ; } + ~QxSessionImpl() { ; } + + void appendSqlError(const QSqlError &err) + { + if (!err.isValid()) + { + return; + } + m_lstSqlError.append(err); + if (m_bThrowInEvent) + { + return; + } + if (m_bThrowable) + { + QString msg = err.text(); + qDebug("[QxOrm] qx::QxSession throw 'qx::dao::sql_error' exception : '%s'", qPrintable(msg)); + } + if (m_bThrowable) + { + m_bThrowInEvent = true; + throw qx::dao::sql_error(err); + } + m_bThrowInEvent = false; + } + + void clear() + { + m_lstSqlError.clear(); + m_bTransaction = false; + } + + static QPair getSessionIdentifier(QSqlDatabase &db, qx::QxSession *pSessionToFill, qx::QxSession *pSessionToFetch) + { + if (pSessionToFetch && pSessionToFetch->m_pImpl) + { + return pSessionToFetch->m_pImpl->m_sessionId; + } + QString connectionName = db.connectionName(); + Qt::HANDLE hCurrThreadId = QThread::currentThreadId(); + QPair sessionId = qMakePair(hCurrThreadId, connectionName); + if (pSessionToFill && pSessionToFill->m_pImpl) + { + pSessionToFill->m_pImpl->m_sessionId = sessionId; + } + return sessionId; + } + }; + + QMutex qx::QxSession::QxSessionImpl::m_mutex; + QHash, qx::QxSession *> qx::QxSession::QxSessionImpl::m_lstActiveSessions; + + QxSession::QxSession() : m_pImpl(new QxSessionImpl()) + { + m_pImpl->m_database = qx::QxSqlDatabase::getDatabaseCloned(); + m_pImpl->m_bThrowable = qx::QxSqlDatabase::getSingleton()->getSessionThrowable(); + if (qx::QxSqlDatabase::getSingleton()->getSessionAutoTransaction()) + { + open(); + } + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier(m_pImpl->m_database, this, NULL); + if (!sessionId.second.isEmpty()) + { + QxSessionImpl::m_lstActiveSessions.insert(sessionId, this); + } + } + + QxSession::QxSession(const QSqlDatabase &database) : m_pImpl(new QxSessionImpl(database)) + { + m_pImpl->m_bThrowable = qx::QxSqlDatabase::getSingleton()->getSessionThrowable(); + if (qx::QxSqlDatabase::getSingleton()->getSessionAutoTransaction()) + { + open(); + } + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier(m_pImpl->m_database, this, NULL); + if (!sessionId.second.isEmpty()) + { + QxSessionImpl::m_lstActiveSessions.insert(sessionId, this); + } + } + + QxSession::QxSession(const QSqlDatabase &database, bool bOpenTransaction) : m_pImpl(new QxSessionImpl(database)) + { + m_pImpl->m_bThrowable = qx::QxSqlDatabase::getSingleton()->getSessionThrowable(); + if (bOpenTransaction) + { + open(); + } + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier(m_pImpl->m_database, this, NULL); + if (!sessionId.second.isEmpty()) + { + QxSessionImpl::m_lstActiveSessions.insert(sessionId, this); + } + } + + QxSession::QxSession(const QSqlDatabase &database, bool bOpenTransaction, bool bThrowable, bool bAutoRollbackWhenDestroyed /* = false */) : m_pImpl(new QxSessionImpl(database, bThrowable, bAutoRollbackWhenDestroyed)) + { + if (bOpenTransaction) + { + open(); + } + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier(m_pImpl->m_database, this, NULL); + if (!sessionId.second.isEmpty()) + { + QxSessionImpl::m_lstActiveSessions.insert(sessionId, this); + } + } + + QxSession::~QxSession() + { + close(); + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier(m_pImpl->m_database, NULL, this); + if (!sessionId.second.isEmpty()) + { + QxSessionImpl::m_lstActiveSessions.remove(sessionId); + } + } + + QxSession *QxSession::getActiveSession(QSqlDatabase *db) + { + if (!db) + { + return NULL; + } + QMutexLocker locker(&QxSessionImpl::m_mutex); + QPair sessionId = QxSessionImpl::getSessionIdentifier((*db), NULL, NULL); + if (sessionId.second.isEmpty()) + { + return NULL; + } + return (QxSessionImpl::m_lstActiveSessions.contains(sessionId) ? QxSessionImpl::m_lstActiveSessions.value(sessionId) : NULL); + } + + bool QxSession::isThrowable() const { return m_pImpl->m_bThrowable; } + + bool QxSession::isOpened() const { return m_pImpl->m_bTransaction; } + + bool QxSession::isValid() const { return (m_pImpl->m_lstSqlError.count() <= 0); } + + bool QxSession::isAutoRollbackWhenDestroyed() const { return m_pImpl->m_bAutoRollbackWhenDestroyed; } + + void QxSession::setAutoRollbackWhenDestroyed(bool b) { m_pImpl->m_bAutoRollbackWhenDestroyed = b; } + + QSqlError QxSession::firstError() const { return ((m_pImpl->m_lstSqlError.count() > 0) ? m_pImpl->m_lstSqlError.first() : QSqlError()); } + + QSqlError QxSession::lastError() const { return ((m_pImpl->m_lstSqlError.count() > 0) ? m_pImpl->m_lstSqlError.last() : QSqlError()); } + + QList QxSession::allErrors() const { return m_pImpl->m_lstSqlError; } + + const QSqlDatabase *QxSession::database() const { return (&m_pImpl->m_database); } + + QSqlDatabase *QxSession::database() { return (&m_pImpl->m_database); } + + bool QxSession::open() + { + if (m_pImpl->m_bTransaction) + { + return true; + } + if (!m_pImpl->m_database.isOpen()) + { + m_pImpl->m_bAutoOpenClose = m_pImpl->m_database.open(); + if (!m_pImpl->m_bAutoOpenClose) + { + m_pImpl->appendSqlError(m_pImpl->m_database.lastError()); + return false; + } + } + if (!m_pImpl->m_database.driver() || !m_pImpl->m_database.driver()->hasFeature(QSqlDriver::Transactions)) + { + return false; + } + m_pImpl->m_bTransaction = m_pImpl->m_database.transaction(); + return m_pImpl->m_bTransaction; + } + + bool QxSession::close() + { + bool bCloseOk = true; + if (m_pImpl->m_bTransaction && m_pImpl->m_bAutoRollbackWhenDestroyed) + { + bCloseOk = rollback(); + } + else if (m_pImpl->m_bTransaction && isValid()) + { + bCloseOk = commit(); + } + else if (m_pImpl->m_bTransaction) + { + bCloseOk = rollback(); + } + if (m_pImpl->m_bAutoOpenClose) + { + m_pImpl->m_database.close(); + m_pImpl->m_bAutoOpenClose = false; + } + return bCloseOk; + } + + bool QxSession::commit() + { + if (m_pImpl->m_bTransaction && !isValid()) + { + qDebug("[QxOrm] %s", "qx::QxSession is not valid and 'commit()' method is called"); + } + if (!m_pImpl->m_bTransaction) + { + m_pImpl->clear(); + return false; + } + bool bCommit = m_pImpl->m_database.commit(); + if (bCommit) + { + m_pImpl->clear(); + return true; + } + m_pImpl->appendSqlError(m_pImpl->m_database.lastError()); + m_pImpl->m_bTransaction = false; + return false; + } + + bool QxSession::rollback() + { + if (!m_pImpl->m_bTransaction) + { + m_pImpl->clear(); + return false; + } + qDebug("[QxOrm] qx::QxSession : '%s'", "rollback transaction"); + bool bRollback = m_pImpl->m_database.rollback(); + if (bRollback) + { + m_pImpl->clear(); + return true; + } + m_pImpl->appendSqlError(m_pImpl->m_database.lastError()); + m_pImpl->m_bTransaction = false; + return false; + } + + QxSession &QxSession::operator+=(const QSqlError &err) + { + m_pImpl->appendSqlError(err); + return (*this); + } + + void QxSession::ignoreSoftDelete(bool bIgnoreSoftDelete /* = true */, const QStringList &classesToIgnore /* = QStringList() */) + { + m_pImpl->m_bIgnoreSoftDelete = bIgnoreSoftDelete; + m_pImpl->m_lstIgnoreSoftDelete = classesToIgnore; + m_pImpl->m_lstIgnoreSoftDelete.sort(); + } + + bool QxSession::checkIgnoreSoftDelete(const QString &classKey) const + { + if (!m_pImpl->m_bIgnoreSoftDelete) + { + return false; + } + if (m_pImpl->m_lstIgnoreSoftDelete.isEmpty()) + { + return true; + } + if (m_pImpl->m_lstIgnoreSoftDelete.contains(classKey)) + { + return true; + } + return false; + } + + QString QxSession::getIgnoreSoftDeleteHash() const + { + if (!m_pImpl->m_bIgnoreSoftDelete) + { + return ""; + } + if (m_pImpl->m_lstIgnoreSoftDelete.isEmpty()) + { + return "[ALL]"; + } + return m_pImpl->m_lstIgnoreSoftDelete.join("_"); + } + +} // namespace qx diff --git a/src/QxDao/QxSoftDelete.cpp b/src/QxDao/QxSoftDelete.cpp new file mode 100644 index 0000000..bacace9 --- /dev/null +++ b/src/QxDao/QxSoftDelete.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + + QxSoftDelete::QxSoftDelete() : m_eMode(QxSoftDelete::mode_date_time), m_bFetchInJoin(true) { ; } + + QxSoftDelete::QxSoftDelete(const QString &sColumn) : m_sColumn(sColumn), m_eMode(QxSoftDelete::mode_date_time), m_bFetchInJoin(true) { ; } + + QxSoftDelete::QxSoftDelete(const QString &sColumn, QxSoftDelete::mode eMode) : m_sColumn(sColumn), m_eMode(eMode), m_bFetchInJoin(true) { ; } + + QxSoftDelete::~QxSoftDelete() { ; } + + QString QxSoftDelete::getTableName() const { return m_sTable; } + + QString QxSoftDelete::getColumnName() const { return m_sColumn; } + + QString QxSoftDelete::getSqlQueryToFetch() const { return m_sSqlQueryToFetch; } + + QString QxSoftDelete::getSqlQueryToUpdate() const { return m_sSqlQueryToUpdate; } + + QString QxSoftDelete::getSqlQueryToCreateTable() const { return m_sSqlQueryToCreateTable; } + + QxSoftDelete::mode QxSoftDelete::getMode() const { return m_eMode; } + + bool QxSoftDelete::getSqlFetchInJoin() const { return m_bFetchInJoin; } + + void QxSoftDelete::setTableName(const QString &sTable) { m_sTable = sTable; } + + void QxSoftDelete::setColumnName(const QString &sColumn) { m_sColumn = sColumn; } + + void QxSoftDelete::setSqlQueryToFetch(const QString &s) { m_sSqlQueryToFetch = s; } + + void QxSoftDelete::setSqlQueryToUpdate(const QString &s) { m_sSqlQueryToUpdate = s; } + + void QxSoftDelete::setSqlQueryToCreateTable(const QString &s) { m_sSqlQueryToCreateTable = s; } + + void QxSoftDelete::setMode(QxSoftDelete::mode eMode) { m_eMode = eMode; } + + void QxSoftDelete::setSqlFetchInJoin(bool b) { m_bFetchInJoin = b; } + + bool QxSoftDelete::isEmpty() const { return (m_sTable.isEmpty() || m_sColumn.isEmpty()); } + + QString QxSoftDelete::buildSqlTablePointName(const QString &sTable /* = QString() */) const + { + if (this->isEmpty()) + { + return ""; + } + QString sCurrTable = (sTable.isEmpty() ? m_sTable : sTable); + sCurrTable.replace(".", "_"); + return (sCurrTable + "." + m_sColumn); + } + + QString QxSoftDelete::buildSqlQueryToFetch(const QString &sTable /* = QString() */) const + { + QString sCurrTable = (sTable.isEmpty() ? m_sTable : sTable); + sCurrTable.replace(".", "_"); + if (this->isEmpty()) + { + return ""; + } + else if (!m_sSqlQueryToFetch.isEmpty()) + { + return m_sSqlQueryToFetch; + } + else if (m_eMode == QxSoftDelete::mode_flag) + { + return ("(" + sCurrTable + "." + m_sColumn + " IS NULL" + " OR " + sCurrTable + "." + m_sColumn + " = ''" + " OR " + sCurrTable + "." + m_sColumn + " = '0'" + ")"); + } + else if (m_eMode == QxSoftDelete::mode_date_time) + { + return ("(" + sCurrTable + "." + m_sColumn + " IS NULL" + " OR " + sCurrTable + "." + m_sColumn + " = ''" + ")"); + } + qAssert(false); + return ""; + } + + QString QxSoftDelete::buildSqlQueryToUpdate() const + { + if (this->isEmpty()) + { + return ""; + } + else if (!m_sSqlQueryToUpdate.isEmpty()) + { + return m_sSqlQueryToUpdate; + } + else if (m_eMode == QxSoftDelete::mode_flag) + { + return (m_sColumn + " = '1'"); + } + else if (m_eMode == QxSoftDelete::mode_date_time) + { + return (m_sColumn + " = '" + QDateTime::currentDateTime().toString(QX_DAO_SOFT_DELETE_QDATETIME_FORMAT) + "'"); + } + qAssert(false); + return ""; + } + + QString QxSoftDelete::buildSqlQueryToCreateTable() const + { + if (this->isEmpty()) + { + return ""; + } + else if (!m_sSqlQueryToCreateTable.isEmpty()) + { + return m_sSqlQueryToCreateTable; + } + else if (m_eMode == QxSoftDelete::mode_flag) + { + return (m_sColumn + " " + "TEXT"); + } + else if (m_eMode == QxSoftDelete::mode_date_time) + { + return (m_sColumn + " " + "TEXT"); + } + qAssert(false); + return ""; + } + +} // namespace qx diff --git a/src/QxDao/QxSqlDatabase.cpp b/src/QxDao/QxSqlDatabase.cpp new file mode 100644 index 0000000..747b1e5 --- /dev/null +++ b/src/QxDao/QxSqlDatabase.cpp @@ -0,0 +1,1298 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +#ifdef _QX_ENABLE_MONGODB +#include +#endif // _QX_ENABLE_MONGODB + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) +#define QX_CONSTRUCT_QX_SQL_DATABASE_MUTEX() m_oDbMutex() +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) +#define QX_CONSTRUCT_QX_SQL_DATABASE_MUTEX() m_oDbMutex(QMutex::Recursive) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + +#define QX_CONSTRUCT_QX_SQL_DATABASE() \ + QX_CONSTRUCT_QX_SQL_DATABASE_MUTEX(), m_iPort(-1), m_bTraceSqlQuery(true), m_bTraceSqlRecord(false), \ + m_bTraceSqlBoundValues(false), m_bTraceSqlBoundValuesOnError(true), \ + m_ePlaceHolderStyle(QxSqlDatabase::ph_style_2_point_name), m_bSessionThrowable(false), \ + m_bSessionAutoTransaction(true), m_bValidatorThrowable(false), \ + m_bAutoReplaceSqlAliasIntoQuery(true), m_bVerifyOffsetRelation(false), \ + m_bAddAutoIncrementIdToUpdateQuery(true), m_bForceParentIdToAllChildren(false), \ + m_bAddSqlSquareBracketsForTableName(false), m_bAddSqlSquareBracketsForColumnName(false), \ + m_bFormatSqlQueryBeforeLogging(false), m_iTraceSqlOnlySlowQueriesDatabase(-1), m_iTraceSqlOnlySlowQueriesTotal(-1), \ + m_bDisplayTimerDetails(false) + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxSqlDatabase) + +namespace qx +{ + + struct Q_DECL_HIDDEN QxSqlDatabase::QxSqlDatabaseImpl + { + + QxSqlDatabase *m_pParent; //!< Parent instance of the private implementation idiom + QHash m_lstDbByThread; //!< Collection of databases connexions by thread id +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QRecursiveMutex m_oDbMutex; //!< Mutex => 'QxSqlDatabase' is thread-safe +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QMutex m_oDbMutex; //!< Mutex => 'QxSqlDatabase' is thread-safe +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QString m_sDriverName; //!< Driver name to connect to database + QString m_sConnectOptions; //!< Connect options to database + QString m_sDatabaseName; //!< Database name + QString m_sUserName; //!< Connection's user name + QString m_sPassword; //!< Connection's password + QString m_sHostName; //!< Connection's host name + int m_iPort; //!< Connection's port number + bool m_bTraceSqlQuery; //!< Trace each sql query executed + bool m_bTraceSqlRecord; //!< Trace each sql record + bool m_bTraceSqlBoundValues; //!< Trace sql bound values + bool m_bTraceSqlBoundValuesOnError; //!< Trace sql bound values (only when an error occurred) + QxSqlDatabase::ph_style m_ePlaceHolderStyle; //!< Place holder style to build sql query + bool m_bSessionThrowable; //!< An exception of type qx::dao::sql_error is thrown when a SQL error is appended to qx::QxSession object + bool m_bSessionAutoTransaction; //!< A transaction is automatically beginned when a qx::QxSession object is instantiated + bool m_bValidatorThrowable; //!< An exception of type qx::validator_error is thrown when invalid values are detected inserting or updating an element into database + qx::dao::detail::IxSqlGenerator_ptr m_pSqlGenerator; //!< SQL generator to build SQL query specific for each database + bool m_bAutoReplaceSqlAliasIntoQuery; //!< Replace all sql alias into sql query automatically + bool m_bVerifyOffsetRelation; //!< Only for debug purpose : assert if invalid offset detected fetching a relation + bool m_bAddAutoIncrementIdToUpdateQuery; //!< For Microsoft SqlServer database compatibility : add or not auto-increment id to SQL update query + bool m_bForceParentIdToAllChildren; //!< Force parent id to all children (for 1-n relationship for example) + QxSqlDatabase::type_fct_db_open m_fctDatabaseOpen; //!< Callback function called when a new database connection is opened (can be used for example with SQLite database to define some PRAGMAs before executing any SQL query) + bool m_bAddSqlSquareBracketsForTableName; //!< Add square brackets [] for table name in SQL queries (to support specific database keywords) + bool m_bAddSqlSquareBracketsForColumnName; //!< Add square brackets [] for column name in SQL queries (to support specific database keywords) + bool m_bFormatSqlQueryBeforeLogging; //!< Format SQL query (pretty-printing) before logging it (can be customized creating a qx::dao::detail::IxSqlGenerator sub-class) + QStringList m_lstSqlDelimiterForTableName; //!< Add delimiter characters for table name in SQL queries (to support specific database keywords) : for example, use ` for MySQL database + QStringList m_lstSqlDelimiterForColumnName; //!< Add delimiter characters for column name in SQL queries (to support specific database keywords) : for example, use ` for MySQL database + QStringList m_lstSqlDelimiterForTableNameAlias; //!< Add delimiter characters for table name alias in SQL queries (to support specific database keywords) : for example, use ` for MySQL database + QStringList m_lstSqlDelimiterForColumnNameAlias; //!< Add delimiter characters for column name alias in SQL queries (to support specific database keywords) : for example, use ` for MySQL database + int m_iTraceSqlOnlySlowQueriesDatabase; //!< Trace only slow sql queries (database execution time only, in milliseconds) + int m_iTraceSqlOnlySlowQueriesTotal; //!< Trace only slow sql queries (database execution time + C++ qx::dao execution time, in milliseconds) + bool m_bDisplayTimerDetails; //!< Display in logs all timers details (exec(), next(), prepare(), open(), etc...) + + QHash, QVariant> m_lstSettingsByThread; //!< List of settings per thread (override global settings) : can be useful to use different databases per thread (see bJustForCurrentThread parameter in all setXXXX() methods) + QHash m_lstGeneratorByThread; //!< List of SQL generator per thread (override global settings) : can be useful to use different databases per thread (see bJustForCurrentThread parameter in setSqlGenerator() method) + QHash, QVariant> m_lstSettingsByDatabase; //!< List of settings per database (override global settings and thread settings) : can be useful to use different databases in a same thread (see pJustForThisDatabase parameter in all setXXXX() method) + QHash m_lstGeneratorByDatabase; //!< List of SQL generator per database (override global settings and thread settings) : can be useful to use different databases in a same thread (see pJustForThisDatabase parameter in setSqlGenerator() method) + QHash m_lstCurrDatabaseKeyByThread; //!< Current database key (key = driverName + hostName + databaseName + connectionName) used per thread : this list is filled by each qx::dao::detail::IxDao_Helper instance using RAII + + QxSqlDatabaseImpl(QxSqlDatabase *p) : m_pParent(p), QX_CONSTRUCT_QX_SQL_DATABASE() { ; } + ~QxSqlDatabaseImpl() { ; } + + QSqlDatabase getDatabaseByCurrThreadId(QSqlError &dbError); + QSqlDatabase createDatabase(QSqlError &dbError); + + void displayLastError(const QSqlDatabase &db, const QString &sDesc) const; + QString formatLastError(const QSqlDatabase &db) const; + + bool isValid() const { return (!m_sDriverName.isEmpty() && !m_sDatabaseName.isEmpty()); } + QString computeDatabaseKey(QSqlDatabase *p) const { return (p ? (p->driverName() + p->hostName() + p->databaseName()) : (m_sDriverName + m_sHostName + m_sDatabaseName)); } + + QVariant getSetting(const QString &key) const + { + if (m_lstSettingsByDatabase.count() > 0) + { + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QString sDatabaseKey = (m_lstCurrDatabaseKeyByThread.contains(lCurrThreadId) ? m_lstCurrDatabaseKeyByThread.value(lCurrThreadId) : QString()); + QPair pairDatabase = qMakePair(sDatabaseKey, key); + if (m_lstSettingsByDatabase.contains(pairDatabase)) + { + return m_lstSettingsByDatabase.value(pairDatabase); + } + } + if (m_lstSettingsByThread.count() > 0) + { + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QPair pairThread = qMakePair(lCurrThreadId, key); + if (m_lstSettingsByThread.contains(pairThread)) + { + return m_lstSettingsByThread.value(pairThread); + } + } + return QVariant(); + } + + bool setSetting(const QString &key, const QVariant &val, bool bJustForCurrentThread, QSqlDatabase *pJustForThisDatabase) + { + bool bUpdateGlobal = true; + if (bJustForCurrentThread) + { + QMutexLocker locker(&m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QPair pairThread = qMakePair(lCurrThreadId, key); + m_lstSettingsByThread.insert(pairThread, val); + bUpdateGlobal = false; + } + if (pJustForThisDatabase != NULL) + { + QMutexLocker locker(&m_oDbMutex); + QString sDatabaseKey = computeDatabaseKey(pJustForThisDatabase); + if (sDatabaseKey.isEmpty()) + { + qDebug("[QxOrm] qx::QxSqlDatabase::setSetting() : database parameters are empty ==> cannot add setting database '%s'", qPrintable(key)); + qAssert(false); + return false; + } + QPair pairDatabase = qMakePair(sDatabaseKey, key); + m_lstSettingsByDatabase.insert(pairDatabase, val); + bUpdateGlobal = false; + } + return bUpdateGlobal; + } + }; + + QxSqlDatabase::QxSqlDatabase() : QxSingleton("qx::QxSqlDatabase"), m_pImpl(new QxSqlDatabaseImpl(this)) { ; } + + QxSqlDatabase::~QxSqlDatabase() { ; } + + QString QxSqlDatabase::getDriverName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sDriverName; + } + QVariant setting = m_pImpl->getSetting("DriverName"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sDriverName; + } + + QString QxSqlDatabase::getConnectOptions() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sConnectOptions; + } + QVariant setting = m_pImpl->getSetting("ConnectOptions"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sConnectOptions; + } + + QString QxSqlDatabase::getDatabaseName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sDatabaseName; + } + QVariant setting = m_pImpl->getSetting("DatabaseName"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sDatabaseName; + } + + QString QxSqlDatabase::getUserName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sUserName; + } + QVariant setting = m_pImpl->getSetting("UserName"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sUserName; + } + + QString QxSqlDatabase::getPassword() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sPassword; + } + QVariant setting = m_pImpl->getSetting("Password"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sPassword; + } + + QString QxSqlDatabase::getHostName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_sHostName; + } + QVariant setting = m_pImpl->getSetting("HostName"); + if (!setting.isNull()) + { + return setting.toString(); + } + return m_pImpl->m_sHostName; + } + + int QxSqlDatabase::getPort() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_iPort; + } + QVariant setting = m_pImpl->getSetting("Port"); + if (!setting.isNull()) + { + return setting.toInt(); + } + return m_pImpl->m_iPort; + } + + bool QxSqlDatabase::getTraceSqlQuery() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bTraceSqlQuery; + } + QVariant setting = m_pImpl->getSetting("TraceSqlQuery"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bTraceSqlQuery; + } + + bool QxSqlDatabase::getTraceSqlRecord() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bTraceSqlRecord; + } + QVariant setting = m_pImpl->getSetting("TraceSqlRecord"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bTraceSqlRecord; + } + + bool QxSqlDatabase::getTraceSqlBoundValues() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bTraceSqlBoundValues; + } + QVariant setting = m_pImpl->getSetting("TraceSqlBoundValues"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bTraceSqlBoundValues; + } + + bool QxSqlDatabase::getTraceSqlBoundValuesOnError() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bTraceSqlBoundValuesOnError; + } + QVariant setting = m_pImpl->getSetting("TraceSqlBoundValuesOnError"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bTraceSqlBoundValuesOnError; + } + + QxSqlDatabase::ph_style QxSqlDatabase::getSqlPlaceHolderStyle() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_ePlaceHolderStyle; + } + QVariant setting = m_pImpl->getSetting("SqlPlaceHolderStyle"); + if (!setting.isNull()) + { + return static_cast(setting.toInt()); + } + return m_pImpl->m_ePlaceHolderStyle; + } + + bool QxSqlDatabase::getSessionThrowable() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bSessionThrowable; + } + QVariant setting = m_pImpl->getSetting("SessionThrowable"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bSessionThrowable; + } + + bool QxSqlDatabase::getSessionAutoTransaction() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bSessionAutoTransaction; + } + QVariant setting = m_pImpl->getSetting("SessionAutoTransaction"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bSessionAutoTransaction; + } + + bool QxSqlDatabase::getValidatorThrowable() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bValidatorThrowable; + } + QVariant setting = m_pImpl->getSetting("ValidatorThrowable"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bValidatorThrowable; + } + + bool QxSqlDatabase::getAutoReplaceSqlAliasIntoQuery() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bAutoReplaceSqlAliasIntoQuery; + } + QVariant setting = m_pImpl->getSetting("AutoReplaceSqlAliasIntoQuery"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bAutoReplaceSqlAliasIntoQuery; + } + + bool QxSqlDatabase::getVerifyOffsetRelation() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bVerifyOffsetRelation; + } + QVariant setting = m_pImpl->getSetting("VerifyOffsetRelation"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bVerifyOffsetRelation; + } + + bool QxSqlDatabase::getAddAutoIncrementIdToUpdateQuery() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bAddAutoIncrementIdToUpdateQuery; + } + QVariant setting = m_pImpl->getSetting("AddAutoIncrementIdToUpdateQuery"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bAddAutoIncrementIdToUpdateQuery; + } + + bool QxSqlDatabase::getForceParentIdToAllChildren() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bForceParentIdToAllChildren; + } + QVariant setting = m_pImpl->getSetting("ForceParentIdToAllChildren"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bForceParentIdToAllChildren; + } + + QxSqlDatabase::type_fct_db_open QxSqlDatabase::getFctDatabaseOpen() const + { + return m_pImpl->m_fctDatabaseOpen; + } + + bool QxSqlDatabase::getAddSqlSquareBracketsForTableName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bAddSqlSquareBracketsForTableName; + } + QVariant setting = m_pImpl->getSetting("AddSqlSquareBracketsForTableName"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bAddSqlSquareBracketsForTableName; + } + + bool QxSqlDatabase::getAddSqlSquareBracketsForColumnName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bAddSqlSquareBracketsForColumnName; + } + QVariant setting = m_pImpl->getSetting("AddSqlSquareBracketsForColumnName"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bAddSqlSquareBracketsForColumnName; + } + + bool QxSqlDatabase::getFormatSqlQueryBeforeLogging() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bFormatSqlQueryBeforeLogging; + } + QVariant setting = m_pImpl->getSetting("FormatSqlQueryBeforeLogging"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bFormatSqlQueryBeforeLogging; + } + + QStringList QxSqlDatabase::getSqlDelimiterForTableName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_lstSqlDelimiterForTableName; + } + QVariant setting = m_pImpl->getSetting("SqlDelimiterForTableName"); + if (!setting.isNull()) + { + return setting.toStringList(); + } + return m_pImpl->m_lstSqlDelimiterForTableName; + } + + QStringList QxSqlDatabase::getSqlDelimiterForColumnName() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_lstSqlDelimiterForColumnName; + } + QVariant setting = m_pImpl->getSetting("SqlDelimiterForColumnName"); + if (!setting.isNull()) + { + return setting.toStringList(); + } + return m_pImpl->m_lstSqlDelimiterForColumnName; + } + + QStringList QxSqlDatabase::getSqlDelimiterForTableNameAlias() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_lstSqlDelimiterForTableNameAlias; + } + QVariant setting = m_pImpl->getSetting("SqlDelimiterForTableNameAlias"); + if (!setting.isNull()) + { + return setting.toStringList(); + } + return m_pImpl->m_lstSqlDelimiterForTableNameAlias; + } + + QStringList QxSqlDatabase::getSqlDelimiterForColumnNameAlias() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_lstSqlDelimiterForColumnNameAlias; + } + QVariant setting = m_pImpl->getSetting("SqlDelimiterForColumnNameAlias"); + if (!setting.isNull()) + { + return setting.toStringList(); + } + return m_pImpl->m_lstSqlDelimiterForColumnNameAlias; + } + + int QxSqlDatabase::getTraceSqlOnlySlowQueriesDatabase() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_iTraceSqlOnlySlowQueriesDatabase; + } + QVariant setting = m_pImpl->getSetting("TraceSqlOnlySlowQueriesDatabase"); + if (!setting.isNull()) + { + return setting.toInt(); + } + return m_pImpl->m_iTraceSqlOnlySlowQueriesDatabase; + } + + int QxSqlDatabase::getTraceSqlOnlySlowQueriesTotal() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_iTraceSqlOnlySlowQueriesTotal; + } + QVariant setting = m_pImpl->getSetting("TraceSqlOnlySlowQueriesTotal"); + if (!setting.isNull()) + { + return setting.toInt(); + } + return m_pImpl->m_iTraceSqlOnlySlowQueriesTotal; + } + + bool QxSqlDatabase::getDisplayTimerDetails() const + { + if ((m_pImpl->m_lstSettingsByThread.count() <= 0) && (m_pImpl->m_lstSettingsByDatabase.count() <= 0)) + { + return m_pImpl->m_bDisplayTimerDetails; + } + QVariant setting = m_pImpl->getSetting("DisplayTimerDetails"); + if (!setting.isNull()) + { + return setting.toBool(); + } + return m_pImpl->m_bDisplayTimerDetails; + } + + void QxSqlDatabase::setDriverName(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("DriverName", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sDriverName = s; + } + getSqlGenerator(); + } + + void QxSqlDatabase::setConnectOptions(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("ConnectOptions", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sConnectOptions = s; + } + } + + void QxSqlDatabase::setDatabaseName(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("DatabaseName", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sDatabaseName = s; + } + } + + void QxSqlDatabase::setUserName(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("UserName", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sUserName = s; + } + } + + void QxSqlDatabase::setPassword(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("Password", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sPassword = s; + } + } + + void QxSqlDatabase::setHostName(const QString &s, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("HostName", s, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_sHostName = s; + } + } + + void QxSqlDatabase::setPort(int i, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("Port", i, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_iPort = i; + } + } + + void QxSqlDatabase::setTraceSqlQuery(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlQuery", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bTraceSqlQuery = b; + } + } + + void QxSqlDatabase::setTraceSqlRecord(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlRecord", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bTraceSqlRecord = b; + } + } + + void QxSqlDatabase::setTraceSqlBoundValues(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlBoundValues", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bTraceSqlBoundValues = b; + } + } + + void QxSqlDatabase::setTraceSqlBoundValuesOnError(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlBoundValuesOnError", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bTraceSqlBoundValuesOnError = b; + } + } + + void QxSqlDatabase::setSqlPlaceHolderStyle(QxSqlDatabase::ph_style e, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + int i = static_cast(e); + bool bUpdateGlobal = m_pImpl->setSetting("SqlPlaceHolderStyle", i, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_ePlaceHolderStyle = e; + } + } + + void QxSqlDatabase::setSessionThrowable(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SessionThrowable", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bSessionThrowable = b; + } + } + + void QxSqlDatabase::setSessionAutoTransaction(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SessionAutoTransaction", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bSessionAutoTransaction = b; + } + } + + void QxSqlDatabase::setValidatorThrowable(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("ValidatorThrowable", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bValidatorThrowable = b; + } + } + + void QxSqlDatabase::setSqlGenerator(qx::dao::detail::IxSqlGenerator_ptr p, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = true; + if (p && bJustForCurrentThread) + { + QMutexLocker locker(&m_pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + m_pImpl->m_lstGeneratorByThread.insert(lCurrThreadId, p); + bUpdateGlobal = false; + } + if (p && (pJustForThisDatabase != NULL)) + { + QMutexLocker locker(&m_pImpl->m_oDbMutex); + QString sDatabaseKey = m_pImpl->computeDatabaseKey(pJustForThisDatabase); + if (sDatabaseKey.isEmpty()) + { + qDebug("[QxOrm] qx::QxSqlDatabase::setSqlGenerator() : database parameters are empty ==> cannot add setting database '%s'", "SqlGenerator"); + qAssert(false); + return; + } + m_pImpl->m_lstGeneratorByDatabase.insert(sDatabaseKey, p); + bUpdateGlobal = false; + } + + if (bUpdateGlobal) + { + m_pImpl->m_pSqlGenerator = p; + } + if (p) + { + p->init(); + } + } + + void QxSqlDatabase::setAutoReplaceSqlAliasIntoQuery(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("AutoReplaceSqlAliasIntoQuery", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bAutoReplaceSqlAliasIntoQuery = b; + } + } + + void QxSqlDatabase::setVerifyOffsetRelation(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("VerifyOffsetRelation", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bVerifyOffsetRelation = b; + } + } + + void QxSqlDatabase::setAddAutoIncrementIdToUpdateQuery(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("AddAutoIncrementIdToUpdateQuery", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bAddAutoIncrementIdToUpdateQuery = b; + } + } + + void QxSqlDatabase::setForceParentIdToAllChildren(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("ForceParentIdToAllChildren", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bForceParentIdToAllChildren = b; + } + } + + void QxSqlDatabase::setFctDatabaseOpen(QxSqlDatabase::type_fct_db_open fct, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + Q_UNUSED(bJustForCurrentThread); + Q_UNUSED(pJustForThisDatabase); + m_pImpl->m_fctDatabaseOpen = fct; + } + + void QxSqlDatabase::setAddSqlSquareBracketsForTableName(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("AddSqlSquareBracketsForTableName", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bAddSqlSquareBracketsForTableName = b; + } + } + + void QxSqlDatabase::setAddSqlSquareBracketsForColumnName(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("AddSqlSquareBracketsForColumnName", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bAddSqlSquareBracketsForColumnName = b; + } + } + + void QxSqlDatabase::setFormatSqlQueryBeforeLogging(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("FormatSqlQueryBeforeLogging", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bFormatSqlQueryBeforeLogging = b; + } + } + + void QxSqlDatabase::setSqlDelimiterForTableName(const QStringList &lst, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SqlDelimiterForTableName", lst, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_lstSqlDelimiterForTableName = lst; + } + } + + void QxSqlDatabase::setSqlDelimiterForColumnName(const QStringList &lst, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SqlDelimiterForColumnName", lst, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_lstSqlDelimiterForColumnName = lst; + } + } + + void QxSqlDatabase::setSqlDelimiterForTableNameAlias(const QStringList &lst, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SqlDelimiterForTableNameAlias", lst, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_lstSqlDelimiterForTableNameAlias = lst; + } + } + + void QxSqlDatabase::setSqlDelimiterForColumnNameAlias(const QStringList &lst, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("SqlDelimiterForColumnNameAlias", lst, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_lstSqlDelimiterForColumnNameAlias = lst; + } + } + + void QxSqlDatabase::setTraceSqlOnlySlowQueriesDatabase(int i, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlOnlySlowQueriesDatabase", i, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_iTraceSqlOnlySlowQueriesDatabase = i; + } + } + + void QxSqlDatabase::setTraceSqlOnlySlowQueriesTotal(int i, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("TraceSqlOnlySlowQueriesTotal", i, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_iTraceSqlOnlySlowQueriesTotal = i; + } + } + + void QxSqlDatabase::setDisplayTimerDetails(bool b, bool bJustForCurrentThread /* = false */, QSqlDatabase *pJustForThisDatabase /* = NULL */) + { + bool bUpdateGlobal = m_pImpl->setSetting("DisplayTimerDetails", b, bJustForCurrentThread, pJustForThisDatabase); + if (bUpdateGlobal) + { + m_pImpl->m_bDisplayTimerDetails = b; + } + } + + QSqlDatabase QxSqlDatabase::getDatabase(QSqlError &dbError) { return QxSqlDatabase::getSingleton()->m_pImpl->getDatabaseByCurrThreadId(dbError); } + + QSqlDatabase QxSqlDatabase::getDatabase() + { + QSqlError dbError; + Q_UNUSED(dbError); + return QxSqlDatabase::getDatabase(dbError); + } + + QSqlDatabase QxSqlDatabase::getDatabaseCloned() + { + QSqlError dbError; + Q_UNUSED(dbError); + QString sKeyClone = QUuid::createUuid().toString(); + return QSqlDatabase::cloneDatabase(QxSqlDatabase::getDatabase(dbError), sKeyClone); + } + + QSqlDatabase QxSqlDatabase::checkDatabaseByThread() + { + QxSqlDatabase::QxSqlDatabaseImpl *pImpl = QxSqlDatabase::getSingleton()->m_pImpl.get(); + QMutexLocker locker(&pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + if (!pImpl->m_lstDbByThread.contains(lCurrThreadId)) + { + return QSqlDatabase(); + } + QString sDbKey = pImpl->m_lstDbByThread.value(lCurrThreadId); + if (!QSqlDatabase::contains(sDbKey)) + { + return QSqlDatabase(); + } + return QSqlDatabase::database(sDbKey); + } + + void QxSqlDatabase::removeDatabaseByThread() + { + QxSqlDatabase::QxSqlDatabaseImpl *pImpl = QxSqlDatabase::getSingleton()->m_pImpl.get(); + QMutexLocker locker(&pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + if (!pImpl->m_lstDbByThread.contains(lCurrThreadId)) + { + return; + } + QString sDbKey = pImpl->m_lstDbByThread.value(lCurrThreadId); + if (!QSqlDatabase::contains(sDbKey)) + { + return; + } + QSqlDatabase::database(sDbKey).close(); + QSqlDatabase::removeDatabase(sDbKey); + pImpl->m_lstDbByThread.remove(lCurrThreadId); + } + + QSqlDatabase QxSqlDatabase::QxSqlDatabaseImpl::getDatabaseByCurrThreadId(QSqlError &dbError) + { + QMutexLocker locker(&m_oDbMutex); + dbError = QSqlError(); + + if (!isValid()) + { + qDebug("[QxOrm] qx::QxSqlDatabase : '%s'", "parameters are not valid"); + dbError = QSqlError("[QxOrm] qx::QxSqlDatabase : 'parameters are not valid'", "", QSqlError::UnknownError); + qAssert(false); + return QSqlDatabase(); + } + + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + if (!lCurrThreadId) + { + qDebug("[QxOrm] qx::QxSqlDatabase : '%s'", "unable to find current thread id"); + dbError = QSqlError("[QxOrm] qx::QxSqlDatabase : 'unable to find current thread id'", "", QSqlError::UnknownError); + qAssert(false); + return QSqlDatabase(); + } + + if (!m_lstDbByThread.contains(lCurrThreadId)) + { + return createDatabase(dbError); + } + QString sDbKey = m_lstDbByThread.value(lCurrThreadId); + if (!QSqlDatabase::contains(sDbKey)) + { + return createDatabase(dbError); + } + QSqlDatabase db = QSqlDatabase::database(sDbKey); + if (!db.isValid()) + { + return createDatabase(dbError); + } + if (db.driver() && (db.driver()->thread() != QThread::currentThread())) + { + return createDatabase(dbError); + } + return db; + } + + namespace helper + { + + template + struct CvtQtHandle + { + static QString toString(T t) { return QString::number(static_cast(t)); } + }; + + template + struct CvtQtHandle + { + static QString toString(T t) + { + const void *ptr = static_cast(t); + QString value; + QTextStream stream(&value); + stream << ptr; + return value; + } + }; + + } // namespace helper + + QSqlDatabase QxSqlDatabase::QxSqlDatabaseImpl::createDatabase(QSqlError &dbError) + { + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QString sCurrThreadId = qx::helper::CvtQtHandle::value>::toString(lCurrThreadId); + QString sDbKeyNew = QUuid::createUuid().toString(); + dbError = QSqlError(); + bool bError = false; + + { + QSqlDatabase db = QSqlDatabase::addDatabase(m_pParent->getDriverName(), sDbKeyNew); + db.setConnectOptions(m_pParent->getConnectOptions()); + db.setDatabaseName(m_pParent->getDatabaseName()); + db.setUserName(m_pParent->getUserName()); + db.setPassword(m_pParent->getPassword()); + db.setHostName(m_pParent->getHostName()); + if (m_pParent->getPort() != -1) + { + db.setPort(m_pParent->getPort()); + } + if (!db.open()) + { + displayLastError(db, "unable to open connection to database"); + bError = true; + } + if (bError) + { + dbError = db.lastError(); + } + if (bError && !dbError.isValid()) + { + dbError = QSqlError("[QxOrm] qx::QxSqlDatabase : 'unable to open connection to database'", "", QSqlError::UnknownError); + } + } + + if (bError) + { + QSqlDatabase::removeDatabase(sDbKeyNew); + return QSqlDatabase(); + } + m_lstDbByThread.insert(lCurrThreadId, sDbKeyNew); + qDebug("[QxOrm] qx::QxSqlDatabase : create new database connection in thread '%s' with key '%s'", qPrintable(sCurrThreadId), qPrintable(sDbKeyNew)); + QSqlDatabase dbconn = QSqlDatabase::database(sDbKeyNew); + if (m_fctDatabaseOpen) + { + m_fctDatabaseOpen(dbconn); + } + return dbconn; + } + + void QxSqlDatabase::QxSqlDatabaseImpl::displayLastError(const QSqlDatabase &db, const QString &sDesc) const + { + QString sLastError = formatLastError(db); + if (sDesc.isEmpty()) + { + qDebug("[QxOrm] qx::QxSqlDatabase : '%s'", qPrintable(sLastError)); + } + else + { + qDebug("[QxOrm] qx::QxSqlDatabase : '%s'\n%s", qPrintable(sDesc), qPrintable(sLastError)); + } + } + + QString QxSqlDatabase::QxSqlDatabaseImpl::formatLastError(const QSqlDatabase &db) const + { + QString sLastError; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + if (!db.lastError().nativeErrorCode().isEmpty()) + { + sLastError += QString("Error number '") + db.lastError().nativeErrorCode() + QString("' : "); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + if (db.lastError().number() != -1) + { + sLastError += QString("Error number '") + QString::number(db.lastError().number()) + QString("' : "); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + if (!db.lastError().text().isEmpty()) + { + sLastError += db.lastError().text(); + } + else + { + sLastError += ""; + } + return sLastError; + } + + qx::dao::detail::IxSqlGenerator *QxSqlDatabase::getSqlGenerator() + { + if (m_pImpl->m_lstGeneratorByDatabase.count() > 0) + { + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QString sDatabaseKey = (m_pImpl->m_lstCurrDatabaseKeyByThread.contains(lCurrThreadId) ? m_pImpl->m_lstCurrDatabaseKeyByThread.value(lCurrThreadId) : QString()); + if (m_pImpl->m_lstGeneratorByDatabase.contains(sDatabaseKey)) + { + return m_pImpl->m_lstGeneratorByDatabase.value(sDatabaseKey).get(); + } + } + if (m_pImpl->m_lstGeneratorByThread.count() > 0) + { + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + if (m_pImpl->m_lstGeneratorByThread.contains(lCurrThreadId)) + { + return m_pImpl->m_lstGeneratorByThread.value(lCurrThreadId).get(); + } + } + + if (m_pImpl->m_pSqlGenerator) + { + return m_pImpl->m_pSqlGenerator.get(); + } + QMutexLocker locker(&m_pImpl->m_oDbMutex); + + if (m_pImpl->m_sDriverName == "QMYSQL") + { + m_pImpl->m_pSqlGenerator = std::make_shared(); + } + else if (m_pImpl->m_sDriverName == "QPSQL") + { + m_pImpl->m_pSqlGenerator = std::make_shared(); + } + else if (m_pImpl->m_sDriverName == "QSQLITE") + { + m_pImpl->m_pSqlGenerator = std::make_shared(); + } + else if (m_pImpl->m_sDriverName == "QOCI") + { + m_pImpl->m_pSqlGenerator = std::make_shared(); + } + + if (!m_pImpl->m_pSqlGenerator) + { + m_pImpl->m_pSqlGenerator = std::make_shared(); + } + m_pImpl->m_pSqlGenerator->init(); + return m_pImpl->m_pSqlGenerator.get(); + } + + void QxSqlDatabase::closeAllDatabases() + { + qx::QxSqlDatabase *pSingleton = qx::QxSqlDatabase::getSingleton(); + if (!pSingleton) + { + qAssert(false); + return; + } + QMutexLocker locker(&pSingleton->m_pImpl->m_oDbMutex); + + Q_FOREACH (QString sDbKey, pSingleton->m_pImpl->m_lstDbByThread) + { + QSqlDatabase::database(sDbKey).close(); + QSqlDatabase::removeDatabase(sDbKey); + } + pSingleton->m_pImpl->m_lstDbByThread.clear(); + +#ifdef _QX_ENABLE_MONGODB + qx::dao::mongodb::QxMongoDB_Helper::clearPoolConnection(); +#endif // _QX_ENABLE_MONGODB + } + + void QxSqlDatabase::clearAllDatabases() + { + qx::QxSqlDatabase *pSingleton = qx::QxSqlDatabase::getSingleton(); + if (!pSingleton) + { + qAssert(false); + return; + } + QMutexLocker locker(&pSingleton->m_pImpl->m_oDbMutex); + + qx::QxSqlDatabase::closeAllDatabases(); + pSingleton->m_pImpl->m_sDriverName = ""; + pSingleton->m_pImpl->m_sConnectOptions = ""; + pSingleton->m_pImpl->m_sDatabaseName = ""; + pSingleton->m_pImpl->m_sUserName = ""; + pSingleton->m_pImpl->m_sPassword = ""; + pSingleton->m_pImpl->m_sHostName = ""; + pSingleton->m_pImpl->m_iPort = -1; + } + + bool QxSqlDatabase::isEmpty() + { + qx::QxSqlDatabase *pSingleton = qx::QxSqlDatabase::getSingleton(); + if (!pSingleton) + { + qAssert(false); + return true; + } + QMutexLocker locker(&pSingleton->m_pImpl->m_oDbMutex); + return pSingleton->m_pImpl->m_lstDbByThread.isEmpty(); + } + + bool QxSqlDatabase::setCurrentDatabaseByThread(QSqlDatabase *p) + { + if (!p) + { + return false; + } + QString sDatabaseKey = m_pImpl->computeDatabaseKey(p); + QString sCurrDatabaseKey = m_pImpl->computeDatabaseKey(NULL); + if (sDatabaseKey.toUpper() == sCurrDatabaseKey.toUpper()) + { + return false; + } + + QMutexLocker locker(&m_pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + if (!sDatabaseKey.isEmpty() && !m_pImpl->m_lstCurrDatabaseKeyByThread.contains(lCurrThreadId)) + { + m_pImpl->m_lstCurrDatabaseKeyByThread.insert(lCurrThreadId, sDatabaseKey); + return true; + } + return false; + } + + void QxSqlDatabase::clearCurrentDatabaseByThread() + { + if (m_pImpl->m_lstCurrDatabaseKeyByThread.count() <= 0) + { + return; + } + QMutexLocker locker(&m_pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + m_pImpl->m_lstCurrDatabaseKeyByThread.remove(lCurrThreadId); + } + + void QxSqlDatabase::clearAllSettingsForCurrentThread() + { + QMutexLocker locker(&m_pImpl->m_oDbMutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + QMutableHashIterator, QVariant> itr(m_pImpl->m_lstSettingsByThread); + while (itr.hasNext()) + { + itr.next(); + if (itr.key().first == lCurrThreadId) + { + itr.remove(); + } + } + QMutableHashIterator itr2(m_pImpl->m_lstGeneratorByThread); + while (itr2.hasNext()) + { + itr2.next(); + if (itr2.key() == lCurrThreadId) + { + itr2.remove(); + } + } + } + + void QxSqlDatabase::clearAllSettingsForDatabase(QSqlDatabase *p) + { + if (!p) + { + return; + } + QMutexLocker locker(&m_pImpl->m_oDbMutex); + QString sDatabaseKey = m_pImpl->computeDatabaseKey(p); + QMutableHashIterator, QVariant> itr(m_pImpl->m_lstSettingsByDatabase); + while (itr.hasNext()) + { + itr.next(); + if (itr.key().first == sDatabaseKey) + { + itr.remove(); + } + } + QMutableHashIterator itr2(m_pImpl->m_lstGeneratorByDatabase); + while (itr2.hasNext()) + { + itr2.next(); + if (itr2.key() == sDatabaseKey) + { + itr2.remove(); + } + } + } + +} // namespace qx diff --git a/src/QxDao/QxSqlElement/IxSqlElement.cpp b/src/QxDao/QxSqlElement/IxSqlElement.cpp new file mode 100644 index 0000000..2a74603 --- /dev/null +++ b/src/QxDao/QxSqlElement/IxSqlElement.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + IxSqlElement::IxSqlElement(int index) : m_iIndex(index), m_pSqlGenerator(NULL) + { + m_pSqlGenerator = qx::QxSqlDatabase::getSingleton()->getSqlGenerator(); + qAssert((m_iIndex >= 0) && (m_pSqlGenerator != NULL)); + } + + IxSqlElement::~IxSqlElement() { ; } + + void IxSqlElement::setColumn(const QString &column) + { + m_lstColumns.clear(); + m_lstColumns.append(column); + updateKeys(); + } + + void IxSqlElement::setColumns(const QStringList &columns) + { + m_lstColumns.clear(); + m_lstColumns = columns; + updateKeys(); + } + + void IxSqlElement::setValue(const QVariant &val) + { + m_lstValues.clear(); + m_lstValues.append(val); + } + + void IxSqlElement::setValues(const QVariantList &values) + { + m_lstValues.clear(); + m_lstValues = values; + } + + void IxSqlElement::clone(IxSqlElement *other) + { + if (!other) + { + return; + } + m_lstColumns = other->m_lstColumns; + m_lstValues = other->m_lstValues; + updateKeys(); + } + + void IxSqlElement::updateKeys() + { + m_lstKeys.clear(); + for (int i = 0; i < m_lstColumns.count(); i++) + { + QString sColumn = m_lstColumns.at(i); + QString sKey = sColumn.replace(".", "_") + "_" + QString::number(m_iIndex) + "_" + QString::number(i); + if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark) + { + sKey = "?"; + } + else if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_at_name) + { + sKey = QString("@") + sKey; + } + else + { + sKey = QString(":") + sKey; + } + m_lstKeys.append(sKey); + } + } + + IxSqlElement_ptr create_sql_element(IxSqlElement::type_class e) + { + IxSqlElement_ptr p; + switch (e) + { + case IxSqlElement::_sql_compare: + p = std::make_shared(); + break; + case IxSqlElement::_sql_element_temp: + p = std::make_shared(); + break; + case IxSqlElement::_sql_embed_query: + p = std::make_shared(); + break; + case IxSqlElement::_sql_expression: + p = std::make_shared(); + break; + case IxSqlElement::_sql_free_text: + p = std::make_shared(); + break; + case IxSqlElement::_sql_in: + p = std::make_shared(); + break; + case IxSqlElement::_sql_is_between: + p = std::make_shared(); + break; + case IxSqlElement::_sql_is_null: + p = std::make_shared(); + break; + case IxSqlElement::_sql_limit: + p = std::make_shared(); + break; + case IxSqlElement::_sql_sort: + p = std::make_shared(); + break; + default: + qAssert(false); + } + return p; + } + + } // namespace detail + } // namespace dao +} // namespace qx + +QDataStream &operator<<(QDataStream &stream, const qx::dao::detail::IxSqlElement &t) +{ + QString sExtraSettings = t.getExtraSettings(); + stream << t.m_iIndex; + stream << t.m_lstColumns; + stream << t.m_lstKeys; + stream << t.m_lstValues; + stream << sExtraSettings; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::dao::detail::IxSqlElement &t) +{ + QString sExtraSettings; + stream >> t.m_iIndex; + stream >> t.m_lstColumns; + stream >> t.m_lstKeys; + stream >> t.m_lstValues; + stream >> sExtraSettings; + t.setExtraSettings(sExtraSettings); + return stream; +} diff --git a/src/QxDao/QxSqlElement/QxSqlCompare.cpp b/src/QxDao/QxSqlElement/QxSqlCompare.cpp new file mode 100644 index 0000000..6286dc4 --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlCompare.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlCompare::QxSqlCompare() : IxSqlElement(0), m_type(QxSqlCompare::_is_equal_to) { ; } + + QxSqlCompare::QxSqlCompare(int index, QxSqlCompare::type t, const QString &sCustomOperator /* = QString() */) : IxSqlElement(index), m_type(t), m_sCustomOperator(sCustomOperator) { ; } + + QxSqlCompare::~QxSqlCompare() { ; } + + IxSqlElement::type_class QxSqlCompare::getTypeClass() const { return IxSqlElement::_sql_compare; } + + QString QxSqlCompare::toString() const + { + qAssert((m_lstColumns.count() == 1) && (m_lstKeys.count() == 1)); + QString sReturn, sColumn(m_lstColumns.at(0)), sKey(m_lstKeys.at(0)); + qAssert(!sColumn.isEmpty() && !sKey.isEmpty()); + + switch (m_type) + { + case _is_equal_to: + sReturn = sColumn + " = " + sKey; + break; + case _is_not_equal_to: + sReturn = sColumn + " <> " + sKey; + break; + case _is_greater_than: + sReturn = sColumn + " > " + sKey; + break; + case _is_greater_than_or_equal_to: + sReturn = sColumn + " >= " + sKey; + break; + case _is_less_than: + sReturn = sColumn + " < " + sKey; + break; + case _is_less_than_or_equal_to: + sReturn = sColumn + " <= " + sKey; + break; + case _like: + sReturn = sColumn + " LIKE " + sKey; + break; + case _not_like: + sReturn = sColumn + " NOT LIKE " + sKey; + break; + case _starts_with: + sReturn = sColumn + " LIKE " + sKey; + break; + case _ends_with: + sReturn = sColumn + " LIKE " + sKey; + break; + case _contains_string: + sReturn = sColumn + " LIKE " + sKey; + break; + case _custom_operator: + sReturn = sColumn + " " + m_sCustomOperator + " " + sKey; + break; + case _is_equal_to_select: + sReturn = sColumn + " = (" + sKey + ")"; + break; + case _is_not_equal_to_select: + sReturn = sColumn + " <> (" + sKey + ")"; + break; + default: + qAssert(false); + } + + return sReturn; + } + + void QxSqlCompare::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + qAssert((m_lstKeys.count() == 1) && (m_lstValues.count() == 1)); + QString sKey(m_lstKeys.at(0)); + QVariant vValue(m_lstValues.at(0)); + + QString sWildCard = m_pSqlGenerator->getWildCard(); + if (m_type == _starts_with) + { + vValue = QVariant(vValue.toString() + sWildCard); + } + else if (m_type == _ends_with) + { + vValue = QVariant(sWildCard + vValue.toString()); + } + else if (m_type == _contains_string) + { + vValue = QVariant(sWildCard + vValue.toString() + sWildCard); + } + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sKey)) + { + QVariantList empty; + pLstExecBatch->insert(sKey, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(sKey)); + values.append(vValue); + } + else + { + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + if (bQuestionMark) + { + query.addBindValue(vValue); + } + else + { + query.bindValue(sKey, vValue); + } + } + } + + void QxSqlCompare::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlCompare::getExtraSettings() const { return (QString::number(static_cast(m_type)) + "|" + m_sCustomOperator); } + + void QxSqlCompare::setExtraSettings(const QString &s) + { + int iPos = s.indexOf("|"); + if (iPos == -1) + { + m_type = static_cast(s.toInt()); + return; + } + m_type = static_cast(s.left(iPos).toInt()); + m_sCustomOperator = s.right(s.size() - (iPos + 1)); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlElementTemp.cpp b/src/QxDao/QxSqlElement/QxSqlElementTemp.cpp new file mode 100644 index 0000000..dd991de --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlElementTemp.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlElementTemp::QxSqlElementTemp() : IxSqlElement(0) { ; } + + QxSqlElementTemp::~QxSqlElementTemp() { ; } + + IxSqlElement::type_class QxSqlElementTemp::getTypeClass() const { return IxSqlElement::_sql_element_temp; } + + QString QxSqlElementTemp::toString() const { return ""; } + + void QxSqlElementTemp::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + Q_UNUSED(query); + Q_UNUSED(pLstExecBatch); + } + + void QxSqlElementTemp::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlElementTemp::getExtraSettings() const { return ""; } + + void QxSqlElementTemp::setExtraSettings(const QString &s) { Q_UNUSED(s); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlEmbedQuery.cpp b/src/QxDao/QxSqlElement/QxSqlEmbedQuery.cpp new file mode 100644 index 0000000..23c62ba --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlEmbedQuery.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#ifndef _QX_NO_JSON +#include +#endif // _QX_NO_JSON + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + struct Q_DECL_HIDDEN QxSqlEmbedQuery::QxSqlEmbedQueryImpl + { + + qx::QxSqlQuery m_query; //!< SQL sub-query to embed inside a parent SQL query + QxSqlEmbedQuery::type m_type; //!< Embed query type + + QxSqlEmbedQueryImpl(QxSqlEmbedQuery::type type) : m_type(type) { ; } + ~QxSqlEmbedQueryImpl() { ; } + }; + + QxSqlEmbedQuery::QxSqlEmbedQuery(QxSqlEmbedQuery::type type /* = QxSqlEmbedQuery::_none */) : IxSqlElement(0), m_pImpl(new QxSqlEmbedQueryImpl(type)) { ; } + + QxSqlEmbedQuery::QxSqlEmbedQuery(int index, QxSqlEmbedQuery::type type /* = QxSqlEmbedQuery::_none */) : IxSqlElement(index), m_pImpl(new QxSqlEmbedQueryImpl(type)) { ; } + + QxSqlEmbedQuery::~QxSqlEmbedQuery() { ; } + + IxSqlElement::type_class QxSqlEmbedQuery::getTypeClass() const { return IxSqlElement::_sql_embed_query; } + + void QxSqlEmbedQuery::setQuery(const qx::QxSqlQuery &query) { m_pImpl->m_query = query; } + + QString QxSqlEmbedQuery::toString() const + { + QString result; + QString column = m_lstColumns.at(0); + QString sql = m_pImpl->m_query.query(); + switch (m_pImpl->m_type) + { + case _none: + result = sql; + break; + case _in: + result = column + " IN (" + sql + ")"; + break; + case _not_in: + result = column + " NOT IN (" + sql + ")"; + break; + case _is_equal_to: + result = column + " = (" + sql + ")"; + break; + case _is_not_equal_to: + result = column + " <> (" + sql + ")"; + break; + default: + qAssert(false); + } + return result; + } + + void QxSqlEmbedQuery::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const { m_pImpl->m_query.resolve(query, pLstExecBatch); } + + void QxSqlEmbedQuery::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlEmbedQuery::getExtraSettings() const + { +#ifndef _QX_NO_JSON + return (QString::number(static_cast(m_pImpl->m_type)) + "|" + qx::serialization::json::to_string(m_pImpl->m_query)); +#else // _QX_NO_JSON + return QString(); +#endif // _QX_NO_JSON + } + + void QxSqlEmbedQuery::setExtraSettings(const QString &s) + { +#ifndef _QX_NO_JSON + int pos = s.indexOf("|"); + if (pos == -1) + { + m_pImpl->m_type = static_cast(s.toInt()); + return; + } + m_pImpl->m_type = static_cast(s.left(pos).toInt()); + QString json = s.right(s.size() - (pos + 1)); + qx::serialization::json::from_string(m_pImpl->m_query, json); +#else // _QX_NO_JSON + Q_UNUSED(s); +#endif // _QX_NO_JSON + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlExpression.cpp b/src/QxDao/QxSqlElement/QxSqlExpression.cpp new file mode 100644 index 0000000..9bbc49f --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlExpression.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlExpression::QxSqlExpression() : IxSqlElement(0), m_type(QxSqlExpression::_where) { ; } + + QxSqlExpression::QxSqlExpression(int index, QxSqlExpression::type t) : IxSqlElement(index), m_type(t) { ; } + + QxSqlExpression::~QxSqlExpression() { ; } + + IxSqlElement::type_class QxSqlExpression::getTypeClass() const { return IxSqlElement::_sql_expression; } + + QString QxSqlExpression::toString() const + { + QString sReturn; + + switch (m_type) + { + case _where: + sReturn = "WHERE"; + break; + case _and: + sReturn = "AND"; + break; + case _or: + sReturn = "OR"; + break; + case _open_parenthesis: + sReturn = "("; + break; + case _close_parenthesis: + sReturn = ")"; + break; + default: + qAssert(false); + } + + return sReturn; + } + + void QxSqlExpression::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + Q_UNUSED(query); + Q_UNUSED(pLstExecBatch); + } + + void QxSqlExpression::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlExpression::getExtraSettings() const { return QString::number(static_cast(m_type)); } + + void QxSqlExpression::setExtraSettings(const QString &s) { m_type = static_cast(s.toInt()); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlFreeText.cpp b/src/QxDao/QxSqlElement/QxSqlFreeText.cpp new file mode 100644 index 0000000..da110cf --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlFreeText.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlFreeText::QxSqlFreeText() : IxSqlElement(0) { ; } + + QxSqlFreeText::QxSqlFreeText(int index) : IxSqlElement(index) { ; } + + QxSqlFreeText::~QxSqlFreeText() { ; } + + IxSqlElement::type_class QxSqlFreeText::getTypeClass() const { return IxSqlElement::_sql_free_text; } + + QString QxSqlFreeText::toString() const { return m_sText; } + + void QxSqlFreeText::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if (m_lstValues.count() <= 0) + { + return; + } + qx::QxSqlDatabase::ph_style phStyle = qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle(); + bool bQuestionMark = (phStyle == qx::QxSqlDatabase::ph_style_question_mark); + QString toFind = ((phStyle == qx::QxSqlDatabase::ph_style_2_point_name) ? QString(":") : QString("@")); + QString txt = m_sText.trimmed(); + int posBegin = -1; + int posEnd = -1; + + for (int i = 0; i < m_lstValues.count(); i++) + { + QString key = (QString("sql_free_text_") + QString::number(i)); + QVariant val(m_lstValues.at(i)); + if (!bQuestionMark) + { + posBegin = txt.indexOf(toFind); + posEnd = txt.indexOf(" ", (posBegin + 1)); + if ((posEnd == -1) && (i == (m_lstValues.count() - 1))) + { + posEnd = txt.size(); + } + if ((posBegin == -1) || (posEnd == -1) || (posEnd <= posBegin)) + { + qAssert(false); + break; + } + key = txt.mid(posBegin, (posEnd - posBegin)).replace(")", ""); + txt = txt.right(txt.size() - posEnd).trimmed(); + } + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(key)) + { + QVariantList empty; + pLstExecBatch->insert(key, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(key)); + values.append(val); + } + else + { + if (bQuestionMark) + { + query.addBindValue(val); + } + else + { + query.bindValue(key, val); + } + } + } + } + + void QxSqlFreeText::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlFreeText::getExtraSettings() const { return m_sText; } + + void QxSqlFreeText::setExtraSettings(const QString &s) { m_sText = s; } + + void QxSqlFreeText::setText(const QString &txt) { m_sText = txt; } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlIn.cpp b/src/QxDao/QxSqlElement/QxSqlIn.cpp new file mode 100644 index 0000000..18b33bc --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlIn.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlIn::QxSqlIn() : IxSqlElement(0), m_type(QxSqlIn::_in) { ; } + + QxSqlIn::QxSqlIn(int index, QxSqlIn::type t) : IxSqlElement(index), m_type(t) { ; } + + QxSqlIn::~QxSqlIn() { ; } + + IxSqlElement::type_class QxSqlIn::getTypeClass() const { return IxSqlElement::_sql_in; } + + QString QxSqlIn::toString() const + { + qAssert((m_lstColumns.count() == 1) && (m_lstKeys.count() == 1) && (m_lstValues.count() >= 1)); + QString sReturn, sColumn(m_lstColumns.at(0)), sKey(m_lstKeys.at(0)); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + qAssert(!sColumn.isEmpty() && !sKey.isEmpty()); + + switch (m_type) + { + case _in: + sReturn = sColumn + " IN ("; + break; + case _not_in: + sReturn = sColumn + " NOT IN ("; + break; + case _in_select: + sReturn = sColumn + " IN ("; + break; + case _not_in_select: + sReturn = sColumn + " NOT IN ("; + break; + default: + qAssert(false); + } + + for (int i = 0; i < m_lstValues.count(); i++) + { + if ((m_type == _in_select) || (m_type == _not_in_select)) + { + sReturn += m_lstValues.at(i).toString(); + continue; + } + QString sCurrKey = (bQuestionMark ? QString("?") : (sKey + QString("_") + QString::number(i))); + sReturn += ((i == 0) ? QString("") : QString(", ")); + sReturn += sCurrKey; + } + + sReturn += QString(")"); + return sReturn; + } + + void QxSqlIn::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if ((m_type == _in_select) || (m_type == _not_in_select)) + { + return; + } + qAssert((m_lstKeys.count() == 1) && (m_lstValues.count() >= 1)); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + QString sKey(m_lstKeys.at(0)); + + for (int i = 0; i < m_lstValues.count(); i++) + { + QString sCurrKey = (sKey + QString("_") + QString::number(i)); + QVariant vValue(m_lstValues.at(i)); + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sCurrKey)) + { + QVariantList empty; + pLstExecBatch->insert(sCurrKey, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(sCurrKey)); + values.append(vValue); + } + else + { + if (bQuestionMark) + { + query.addBindValue(vValue); + } + else + { + query.bindValue(sCurrKey, vValue); + } + } + } + } + + void QxSqlIn::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlIn::getExtraSettings() const { return QString::number(static_cast(m_type)); } + + void QxSqlIn::setExtraSettings(const QString &s) { m_type = static_cast(s.toInt()); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlIsBetween.cpp b/src/QxDao/QxSqlElement/QxSqlIsBetween.cpp new file mode 100644 index 0000000..5621835 --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlIsBetween.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlIsBetween::QxSqlIsBetween() : IxSqlElement(0), m_type(QxSqlIsBetween::_is_between) { ; } + + QxSqlIsBetween::QxSqlIsBetween(int index, QxSqlIsBetween::type t) : IxSqlElement(index), m_type(t) { ; } + + QxSqlIsBetween::~QxSqlIsBetween() { ; } + + IxSqlElement::type_class QxSqlIsBetween::getTypeClass() const { return IxSqlElement::_sql_is_between; } + + QString QxSqlIsBetween::toString() const + { + qAssert((m_lstColumns.count() == 1) && (m_lstKeys.count() == 1)); + QString sReturn, sColumn(m_lstColumns.at(0)), sKey(m_lstKeys.at(0)); + qAssert(!sColumn.isEmpty() && !sKey.isEmpty()); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + QString sKey1(bQuestionMark ? QString("?") : (sKey + "_1")), sKey2(bQuestionMark ? QString("?") : (sKey + "_2")); + + switch (m_type) + { + case _is_between: + sReturn = sColumn + " BETWEEN " + sKey1 + " AND " + sKey2; + break; + case _is_not_between: + sReturn = sColumn + " NOT BETWEEN " + sKey1 + " AND " + sKey2; + break; + default: + qAssert(false); + } + + return sReturn; + } + + void QxSqlIsBetween::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + qAssert((m_lstKeys.count() == 1) && (m_lstValues.count() == 2)); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + QString sKey1(m_lstKeys.at(0) + "_1"), sKey2(m_lstKeys.at(0) + "_2"); + QVariant vValue1(m_lstValues.at(0)), vValue2(m_lstValues.at(1)); + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sKey1)) + { + QVariantList empty; + pLstExecBatch->insert(sKey1, empty); + } + if (!pLstExecBatch->exist(sKey2)) + { + QVariantList empty; + pLstExecBatch->insert(sKey2, empty); + } + QVariantList &values1 = const_cast(pLstExecBatch->getByKey(sKey1)); + QVariantList &values2 = const_cast(pLstExecBatch->getByKey(sKey2)); + values1.append(vValue1); + values2.append(vValue2); + } + else + { + if (bQuestionMark) + { + query.addBindValue(vValue1); + query.addBindValue(vValue2); + } + else + { + query.bindValue(sKey1, vValue1); + query.bindValue(sKey2, vValue2); + } + } + } + + void QxSqlIsBetween::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlIsBetween::getExtraSettings() const { return QString::number(static_cast(m_type)); } + + void QxSqlIsBetween::setExtraSettings(const QString &s) { m_type = static_cast(s.toInt()); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlIsNull.cpp b/src/QxDao/QxSqlElement/QxSqlIsNull.cpp new file mode 100644 index 0000000..551a86e --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlIsNull.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlIsNull::QxSqlIsNull() : IxSqlElement(0), m_type(QxSqlIsNull::_is_null) { ; } + + QxSqlIsNull::QxSqlIsNull(int index, QxSqlIsNull::type t) : IxSqlElement(index), m_type(t) { ; } + + QxSqlIsNull::~QxSqlIsNull() { ; } + + IxSqlElement::type_class QxSqlIsNull::getTypeClass() const { return IxSqlElement::_sql_is_null; } + + QString QxSqlIsNull::toString() const + { + qAssert(m_lstColumns.count() == 1); + QString sReturn, sColumn(m_lstColumns.at(0)); + qAssert(!sColumn.isEmpty()); + + switch (m_type) + { + case _is_null: + sReturn = sColumn + " IS NULL"; + break; + case _is_not_null: + sReturn = sColumn + " IS NOT NULL"; + break; + default: + qAssert(false); + } + + return sReturn; + } + + void QxSqlIsNull::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + Q_UNUSED(query); + Q_UNUSED(pLstExecBatch); + } + + void QxSqlIsNull::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlIsNull::getExtraSettings() const { return QString::number(static_cast(m_type)); } + + void QxSqlIsNull::setExtraSettings(const QString &s) { m_type = static_cast(s.toInt()); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlLimit.cpp b/src/QxDao/QxSqlElement/QxSqlLimit.cpp new file mode 100644 index 0000000..5da573a --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlLimit.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlLimit::QxSqlLimit() : IxSqlElement(0) { ; } + + QxSqlLimit::QxSqlLimit(int index) : IxSqlElement(index) { ; } + + QxSqlLimit::~QxSqlLimit() { ; } + + IxSqlElement::type_class QxSqlLimit::getTypeClass() const { return IxSqlElement::_sql_limit; } + + QString QxSqlLimit::toString() const + { + if (!m_pSqlGenerator) + { + qAssert(false); + return ""; + } + return m_pSqlGenerator->getLimit(this); + } + + void QxSqlLimit::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if (!m_pSqlGenerator) + { + qAssert(false); + return; + } + m_pSqlGenerator->resolveLimit(query, this, pLstExecBatch); + } + + void QxSqlLimit::postProcess(QString &sql) const + { + if (!m_pSqlGenerator) + { + qAssert(false); + return; + } + m_pSqlGenerator->postProcess(sql, this); + } + + int QxSqlLimit::getStartRow() const + { + qAssert(m_lstValues.count() >= 2); + return ((m_lstValues.count() > 0) ? m_lstValues.at(0).toInt() : 0); + } + + int QxSqlLimit::getRowsCount() const + { + qAssert(m_lstValues.count() >= 2); + return ((m_lstValues.count() > 1) ? m_lstValues.at(1).toInt() : 0); + } + + int QxSqlLimit::getMaxRow() const + { + qAssert(m_lstValues.count() >= 2); + return ((m_lstValues.count() > 1) ? (m_lstValues.at(0).toInt() + m_lstValues.at(1).toInt()) : 0); + } + + bool QxSqlLimit::getWithTies() const + { + qAssert(m_lstValues.count() >= 3); + return ((m_lstValues.count() > 2) ? m_lstValues.at(2).toBool() : false); + } + + QString QxSqlLimit::getStartRow_ParamKey() const + { + QString sStartRow("offset_start_row"); + sStartRow += "_" + QString::number(m_iIndex) + "_0"; + if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark) + { + sStartRow = "?"; + } + else if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_at_name) + { + sStartRow = "@" + sStartRow; + } + else + { + sStartRow = ":" + sStartRow; + } + return sStartRow; + } + + QString QxSqlLimit::getRowsCount_ParamKey() const + { + QString sRowsCount("limit_rows_count"); + sRowsCount += "_" + QString::number(m_iIndex) + "_0"; + if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark) + { + sRowsCount = "?"; + } + else if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_at_name) + { + sRowsCount = "@" + sRowsCount; + } + else + { + sRowsCount = ":" + sRowsCount; + } + return sRowsCount; + } + + QString QxSqlLimit::getMaxRow_ParamKey() const + { + QString sMaxRow("offset_max_row"); + sMaxRow += "_" + QString::number(m_iIndex) + "_0"; + if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark) + { + sMaxRow = "?"; + } + else if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_at_name) + { + sMaxRow = "@" + sMaxRow; + } + else + { + sMaxRow = ":" + sMaxRow; + } + return sMaxRow; + } + + QString QxSqlLimit::getExtraSettings() const { return ""; } + + void QxSqlLimit::setExtraSettings(const QString &s) { Q_UNUSED(s); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlElement/QxSqlSort.cpp b/src/QxDao/QxSqlElement/QxSqlSort.cpp new file mode 100644 index 0000000..dad5a25 --- /dev/null +++ b/src/QxDao/QxSqlElement/QxSqlSort.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlSort::QxSqlSort() : IxSqlElement(0), m_type(QxSqlSort::_order_asc) { ; } + + QxSqlSort::QxSqlSort(int index, QxSqlSort::type t) : IxSqlElement(index), m_type(t) { ; } + + QxSqlSort::~QxSqlSort() { ; } + + IxSqlElement::type_class QxSqlSort::getTypeClass() const { return IxSqlElement::_sql_sort; } + + QString QxSqlSort::toString() const + { + qAssert(m_lstColumns.count() >= 1); + QString sReturn; + + switch (m_type) + { + case _order_asc: + sReturn = "ORDER BY "; + break; + case _order_desc: + sReturn = "ORDER BY "; + break; + case _group_by: + sReturn = "GROUP BY "; + break; + default: + qAssert(false); + } + + for (int i = 0; i < m_lstColumns.count(); i++) + { + sReturn += ((i == 0) ? QString("") : QString(", ")); + QString sColumn = m_lstColumns.at(i); + qAssert(!sColumn.isEmpty()); + + switch (m_type) + { + case _order_asc: + sReturn += sColumn + " ASC"; + break; + case _order_desc: + sReturn += sColumn + " DESC"; + break; + case _group_by: + sReturn += sColumn; + break; + } + } + + return sReturn; + } + + void QxSqlSort::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + Q_UNUSED(query); + Q_UNUSED(pLstExecBatch); + } + + void QxSqlSort::postProcess(QString &sql) const { Q_UNUSED(sql); } + + QString QxSqlSort::getExtraSettings() const { return QString::number(static_cast(m_type)); } + + void QxSqlSort::setExtraSettings(const QString &s) { m_type = static_cast(s.toInt()); } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/IxSqlGenerator.cpp b/src/QxDao/QxSqlGenerator/IxSqlGenerator.cpp new file mode 100644 index 0000000..7e6f8bf --- /dev/null +++ b/src/QxDao/QxSqlGenerator/IxSqlGenerator.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + IxSqlGenerator::IxSqlGenerator() { ; } + + IxSqlGenerator::~IxSqlGenerator() { ; } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.cpp new file mode 100644 index 0000000..b1b246c --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_MSSQLServer::QxSqlGenerator_MSSQLServer() : QxSqlGenerator_Standard() { this->initSqlTypeByClassName(); } + + QxSqlGenerator_MSSQLServer::~QxSqlGenerator_MSSQLServer() { ; } + + void QxSqlGenerator_MSSQLServer::init() { qx::QxSqlDatabase::getSingleton()->setAddAutoIncrementIdToUpdateQuery(false); } + + QString QxSqlGenerator_MSSQLServer::getLimit(const QxSqlLimit *pLimit) const + { + Q_UNUSED(pLimit); + return ""; + } + + void QxSqlGenerator_MSSQLServer::resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if (!pLimit) + { + qAssert(false); + return; + } + QString sRowsCount = pLimit->getRowsCount_ParamKey(); + int iRowsCount(pLimit->getRowsCount()); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sRowsCount)) + { + QVariantList empty; + pLstExecBatch->insert(sRowsCount, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(sRowsCount)); + values.append(iRowsCount); + } + else + { + if (bQuestionMark) + { + query.addBindValue(iRowsCount); + } + else + { + query.bindValue(sRowsCount, iRowsCount); + } + } + } + + void QxSqlGenerator_MSSQLServer::postProcess(QString &sql, const QxSqlLimit *pLimit) const + { + if (!pLimit) + { + qAssert(false); + return; + } + if (!sql.left(7).contains("SELECT ", Qt::CaseInsensitive)) + { + qAssert(false); + return; + } + QString sRowsCount = pLimit->getRowsCount_ParamKey(); + sql = sql.right(sql.size() - 7); + sql = "SELECT TOP " + sRowsCount + " " + sql; + } + + void QxSqlGenerator_MSSQLServer::initSqlTypeByClassName() const + { + QHash *lstSqlType = qx::QxClassX::getAllSqlTypeByClassName(); + if (!lstSqlType) + { + qAssert(false); + return; + } + + lstSqlType->insert("bool", "TINYINT"); + lstSqlType->insert("qx_bool", "TEXT"); + lstSqlType->insert("short", "SMALLINT"); + lstSqlType->insert("int", "INT"); + lstSqlType->insert("long", "INT"); + lstSqlType->insert("long long", "BIGINT"); + lstSqlType->insert("float", "FLOAT"); + lstSqlType->insert("double", "FLOAT"); + lstSqlType->insert("long double", "FLOAT"); + lstSqlType->insert("unsigned short", "SMALLINT"); + lstSqlType->insert("unsigned int", "INT"); + lstSqlType->insert("unsigned long", "INT"); + lstSqlType->insert("unsigned long long", "BIGINT"); + lstSqlType->insert("std::string", "TEXT"); + lstSqlType->insert("std::wstring", "TEXT"); + lstSqlType->insert("QString", "TEXT"); + lstSqlType->insert("QVariant", "TEXT"); + lstSqlType->insert("QUuid", "TEXT"); + lstSqlType->insert("QDate", "DATE"); + lstSqlType->insert("QTime", "TIME"); + lstSqlType->insert("QDateTime", "TIMESTAMP"); + lstSqlType->insert("QByteArray", "IMAGE"); + lstSqlType->insert("qx::QxDateNeutral", "TEXT"); + lstSqlType->insert("qx::QxTimeNeutral", "TEXT"); + lstSqlType->insert("qx::QxDateTimeNeutral", "TEXT"); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.cpp new file mode 100644 index 0000000..ee76e76 --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_MySQL::QxSqlGenerator_MySQL() : QxSqlGenerator_Standard() { this->initSqlTypeByClassName(); } + + QxSqlGenerator_MySQL::~QxSqlGenerator_MySQL() { ; } + + QString QxSqlGenerator_MySQL::getAutoIncrement() const { return "AUTO_INCREMENT"; } + + void QxSqlGenerator_MySQL::initSqlTypeByClassName() const + { + QHash *lstSqlType = qx::QxClassX::getAllSqlTypeByClassName(); + if (!lstSqlType) + { + qAssert(false); + return; + } + + lstSqlType->insert("bool", "SMALLINT"); + lstSqlType->insert("qx_bool", "TEXT"); + lstSqlType->insert("short", "SMALLINT"); + lstSqlType->insert("int", "INTEGER"); + lstSqlType->insert("long", "INTEGER"); + lstSqlType->insert("long long", "BIGINT"); + lstSqlType->insert("float", "FLOAT"); + lstSqlType->insert("double", "DOUBLE"); + lstSqlType->insert("long double", "DOUBLE"); + lstSqlType->insert("unsigned short", "SMALLINT"); + lstSqlType->insert("unsigned int", "INTEGER"); + lstSqlType->insert("unsigned long", "INTEGER"); + lstSqlType->insert("unsigned long long", "BIGINT"); + lstSqlType->insert("std::string", "TEXT"); + lstSqlType->insert("std::wstring", "TEXT"); + lstSqlType->insert("QString", "TEXT"); + lstSqlType->insert("QVariant", "TEXT"); + lstSqlType->insert("QUuid", "TEXT"); + lstSqlType->insert("QDate", "DATE"); + lstSqlType->insert("QTime", "TIME"); + lstSqlType->insert("QDateTime", "TIMESTAMP"); + lstSqlType->insert("QByteArray", "LONGBLOB"); + lstSqlType->insert("qx::QxDateNeutral", "TEXT"); + lstSqlType->insert("qx::QxTimeNeutral", "TEXT"); + lstSqlType->insert("qx::QxDateTimeNeutral", "TEXT"); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.cpp new file mode 100644 index 0000000..4b35cd7 --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.cpp @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_Oracle::QxSqlGenerator_Oracle() : QxSqlGenerator_Standard(), m_bOldLimitSyntax(false), m_bManageLastInsertId(false) { this->initSqlTypeByClassName(); } + + QxSqlGenerator_Oracle::QxSqlGenerator_Oracle(bool bManageLastInsertId) : QxSqlGenerator_Standard(), m_bOldLimitSyntax(false), m_bManageLastInsertId(bManageLastInsertId) { this->initSqlTypeByClassName(); } + + QxSqlGenerator_Oracle::~QxSqlGenerator_Oracle() { ; } + + bool QxSqlGenerator_Oracle::getOldLimitSyntax() const { return m_bOldLimitSyntax; } + + void QxSqlGenerator_Oracle::setOldLimitSyntax(bool b) { m_bOldLimitSyntax = b; } + + bool QxSqlGenerator_Oracle::getManageLastInsertId() const { return m_bManageLastInsertId; } + + void QxSqlGenerator_Oracle::setManageLastInsertId(bool b) { m_bManageLastInsertId = b; } + + QString QxSqlGenerator_Oracle::getTableAliasSep() const { return " "; } + + QString QxSqlGenerator_Oracle::getLimit(const QxSqlLimit *pLimit) const + { + Q_UNUSED(pLimit); + return ""; + } + + void QxSqlGenerator_Oracle::resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if (!m_bOldLimitSyntax) + { + return; + } + if (!pLimit) + { + qAssert(false); + return; + } + QString sMinRow = pLimit->getStartRow_ParamKey(); + QString sMaxRow = pLimit->getMaxRow_ParamKey(); + int iMinRow(pLimit->getStartRow()), iMaxRow(pLimit->getMaxRow()); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sMaxRow)) + { + QVariantList empty; + pLstExecBatch->insert(sMaxRow, empty); + } + if (!pLstExecBatch->exist(sMinRow)) + { + QVariantList empty; + pLstExecBatch->insert(sMinRow, empty); + } + QVariantList &valuesMaxRow = const_cast(pLstExecBatch->getByKey(sMaxRow)); + QVariantList &valuesMinRow = const_cast(pLstExecBatch->getByKey(sMinRow)); + valuesMaxRow.append(iMaxRow); + valuesMinRow.append(iMinRow); + } + else + { + if (bQuestionMark) + { + query.addBindValue(iMaxRow); + query.addBindValue(iMinRow); + } + else + { + query.bindValue(sMaxRow, iMaxRow); + query.bindValue(sMinRow, iMinRow); + } + } + } + + void QxSqlGenerator_Oracle::postProcess(QString &sql, const QxSqlLimit *pLimit) const + { + if (!pLimit) + { + qAssert(false); + return; + } + QString sMinRow = pLimit->getStartRow_ParamKey(); + QString sMaxRow = pLimit->getMaxRow_ParamKey(); + int iMinRow(pLimit->getStartRow()), iRowsCount(pLimit->getRowsCount()); + bool bWithTies = pLimit->getWithTies(); + + if (m_bOldLimitSyntax) + { + QString sqlPaging; + QString sReplace = "%SQL_QUERY%"; + sqlPaging += "SELECT * FROM "; + sqlPaging += " ( SELECT a.*, ROWNUM rnum FROM "; + sqlPaging += " ( " + sReplace + " ) a "; + sqlPaging += " WHERE ROWNUM <= " + sMaxRow + " ) "; + sqlPaging += "WHERE rnum >= " + sMinRow; + sqlPaging.replace(sReplace, sql); + sql = sqlPaging; + return; + } + + if (iMinRow <= 0) + { + if (bWithTies) + { + sql += " FETCH FIRST " + QString::number(iRowsCount) + " ROWS WITH TIES"; + } + else + { + sql += " FETCH FIRST " + QString::number(iRowsCount) + " ROWS ONLY"; + } + } + else + { + if (bWithTies) + { + sql += " OFFSET " + QString::number(iMinRow) + " ROWS FETCH NEXT " + QString::number(iRowsCount) + " ROWS WITH TIES"; + } + else + { + sql += " OFFSET " + QString::number(iMinRow) + " ROWS FETCH NEXT " + QString::number(iRowsCount) + " ROWS ONLY"; + } + } + } + + void QxSqlGenerator_Oracle::checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const + { + if (!m_bManageLastInsertId) + { + return; + } + if (!pDaoHelper) + { + qAssert(false); + return; + } + if (!pDaoHelper->getDataId()) + { + return; + } + qx::IxDataMember *pId = pDaoHelper->getDataId(); + if (!pId->getAutoIncrement()) + { + return; + } + if (pId->getNameCount() > 1) + { + qAssert(false); + return; + } + QString sqlToAdd = " RETURNING ID INTO :ID; END;"; + if (sql.right(sqlToAdd.size()) == sqlToAdd) + { + return; + } + sql = "BEGIN " + sql + sqlToAdd; + pDaoHelper->builder().setSqlQuery(sql); + } + + void QxSqlGenerator_Oracle::onBeforeInsert(IxDao_Helper *pDaoHelper, void *pOwner) const + { + if (!m_bManageLastInsertId) + { + return; + } + if (!pDaoHelper || !pOwner) + { + qAssert(false); + return; + } + if (!pDaoHelper->getDataId()) + { + return; + } + qx::IxDataMember *pId = pDaoHelper->getDataId(); + if (!pId->getAutoIncrement()) + { + return; + } + if (pId->getNameCount() > 1) + { + qAssert(false); + return; + } + QString key = ":ID"; + if (pDaoHelper->getUseExecBatch()) + { + qx::QxCollection &lstExecBatch = pDaoHelper->getListExecBatch(); + if (!lstExecBatch.exist(key)) + { + QVariantList empty; + lstExecBatch.insert(key, empty); + } + QVariantList &values = const_cast(lstExecBatch.getByKey(key)); + values.append(0); + } + else + { + pDaoHelper->query().bindValue(key, 0, QSql::InOut); + } + } + + void QxSqlGenerator_Oracle::onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const + { + if (!m_bManageLastInsertId) + { + return; + } + if (!pDaoHelper || !pOwner) + { + qAssert(false); + return; + } + if (!pDaoHelper->getDataId()) + { + return; + } + qx::IxDataMember *pId = pDaoHelper->getDataId(); + if (!pId->getAutoIncrement()) + { + return; + } + if (pId->getNameCount() > 1) + { + qAssert(false); + return; + } + QVariant vId = pDaoHelper->query().boundValue(":ID"); + pId->fromVariant(pOwner, vId, -1, qx::cvt::context::e_database); + } + + void QxSqlGenerator_Oracle::initSqlTypeByClassName() const + { + QHash *lstSqlType = qx::QxClassX::getAllSqlTypeByClassName(); + if (!lstSqlType) + { + qAssert(false); + return; + } + + lstSqlType->insert("bool", "SMALLINT"); + lstSqlType->insert("qx_bool", "VARCHAR2(4000)"); + lstSqlType->insert("short", "SMALLINT"); + lstSqlType->insert("int", "INTEGER"); + lstSqlType->insert("long", "INTEGER"); + lstSqlType->insert("long long", "INTEGER"); + lstSqlType->insert("float", "FLOAT"); + lstSqlType->insert("double", "FLOAT"); + lstSqlType->insert("long double", "FLOAT"); + lstSqlType->insert("unsigned short", "SMALLINT"); + lstSqlType->insert("unsigned int", "INTEGER"); + lstSqlType->insert("unsigned long", "INTEGER"); + lstSqlType->insert("unsigned long long", "INTEGER"); + lstSqlType->insert("std::string", "VARCHAR2(4000)"); + lstSqlType->insert("std::wstring", "VARCHAR2(4000)"); + lstSqlType->insert("QString", "VARCHAR2(4000)"); + lstSqlType->insert("QVariant", "CLOB"); + lstSqlType->insert("QUuid", "VARCHAR2(255)"); + lstSqlType->insert("QDate", "DATE"); + lstSqlType->insert("QTime", "DATE"); + lstSqlType->insert("QDateTime", "TIMESTAMP"); + lstSqlType->insert("QByteArray", "BLOB"); + lstSqlType->insert("qx::QxDateNeutral", "VARCHAR2(8)"); + lstSqlType->insert("qx::QxTimeNeutral", "VARCHAR2(6)"); + lstSqlType->insert("qx::QxDateTimeNeutral", "VARCHAR2(14)"); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.cpp new file mode 100644 index 0000000..ff0245b --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.cpp @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_PostgreSQL::QxSqlGenerator_PostgreSQL() : QxSqlGenerator_Standard() { this->initSqlTypeByClassName(); } + + QxSqlGenerator_PostgreSQL::~QxSqlGenerator_PostgreSQL() { ; } + + void QxSqlGenerator_PostgreSQL::checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const + { + if (!pDaoHelper) + { + qAssert(false); + return; + } + if (!pDaoHelper->getDataId()) + { + return; + } + qx::IxDataMember *pId = pDaoHelper->getDataId(); + if (!pId->getAutoIncrement()) + { + return; + } + if (pId->getNameCount() > 1) + { + qAssert(false); + return; + } + QString sqlToAdd = " RETURNING " + pId->getName(); + if (sql.right(sqlToAdd.size()) == sqlToAdd) + { + return; + } + sql += sqlToAdd; + pDaoHelper->builder().setSqlQuery(sql); + } + + void QxSqlGenerator_PostgreSQL::onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const + { + if (!pDaoHelper || !pOwner) + { + qAssert(false); + return; + } + if (!pDaoHelper->getDataId()) + { + return; + } + qx::IxDataMember *pId = pDaoHelper->getDataId(); + if (!pId->getAutoIncrement()) + { + return; + } + if (pId->getNameCount() > 1) + { + qAssert(false); + return; + } + if (!pDaoHelper->nextRecord()) + { + qAssert(false); + return; + } + QVariant vId = pDaoHelper->query().value(0); + pId->fromVariant(pOwner, vId, -1, qx::cvt::context::e_database); + } + + void QxSqlGenerator_PostgreSQL::initSqlTypeByClassName() const + { + QHash *lstSqlType = qx::QxClassX::getAllSqlTypeByClassName(); + if (!lstSqlType) + { + qAssert(false); + return; + } + + lstSqlType->insert("bool", "BOOLEAN"); + lstSqlType->insert("qx_bool", "TEXT"); + lstSqlType->insert("short", "SMALLINT"); + lstSqlType->insert("int", "INTEGER"); + lstSqlType->insert("long", "INTEGER"); + lstSqlType->insert("long long", "BIGINT"); + lstSqlType->insert("float", "FLOAT"); + lstSqlType->insert("double", "FLOAT"); + lstSqlType->insert("long double", "FLOAT"); + lstSqlType->insert("unsigned short", "SMALLINT"); + lstSqlType->insert("unsigned int", "INTEGER"); + lstSqlType->insert("unsigned long", "INTEGER"); + lstSqlType->insert("unsigned long long", "BIGINT"); + lstSqlType->insert("std::string", "TEXT"); + lstSqlType->insert("std::wstring", "TEXT"); + lstSqlType->insert("QString", "TEXT"); + lstSqlType->insert("QVariant", "TEXT"); + lstSqlType->insert("QUuid", "TEXT"); + lstSqlType->insert("QDate", "DATE"); + lstSqlType->insert("QTime", "TIME"); + lstSqlType->insert("QDateTime", "TIMESTAMP"); + lstSqlType->insert("QByteArray", "BYTEA"); + lstSqlType->insert("qx::QxDateNeutral", "TEXT"); + lstSqlType->insert("qx::QxTimeNeutral", "TEXT"); + lstSqlType->insert("qx::QxDateTimeNeutral", "TEXT"); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.cpp new file mode 100644 index 0000000..1f4c250 --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_SQLite::QxSqlGenerator_SQLite() : QxSqlGenerator_Standard() { this->initSqlTypeByClassName(); } + + QxSqlGenerator_SQLite::~QxSqlGenerator_SQLite() { ; } + + void QxSqlGenerator_SQLite::initSqlTypeByClassName() const + { + QHash *lstSqlType = qx::QxClassX::getAllSqlTypeByClassName(); + if (!lstSqlType) + { + qAssert(false); + return; + } + + lstSqlType->insert("bool", "SMALLINT"); + lstSqlType->insert("qx_bool", "TEXT"); + lstSqlType->insert("short", "SMALLINT"); + lstSqlType->insert("int", "INTEGER"); + lstSqlType->insert("long", "INTEGER"); + lstSqlType->insert("long long", "INTEGER"); + lstSqlType->insert("float", "FLOAT"); + lstSqlType->insert("double", "FLOAT"); + lstSqlType->insert("long double", "FLOAT"); + lstSqlType->insert("unsigned short", "SMALLINT"); + lstSqlType->insert("unsigned int", "INTEGER"); + lstSqlType->insert("unsigned long", "INTEGER"); + lstSqlType->insert("unsigned long long", "INTEGER"); + lstSqlType->insert("std::string", "TEXT"); + lstSqlType->insert("std::wstring", "TEXT"); + lstSqlType->insert("QString", "TEXT"); + lstSqlType->insert("QVariant", "TEXT"); + lstSqlType->insert("QUuid", "TEXT"); + lstSqlType->insert("QDate", "DATE"); + lstSqlType->insert("QTime", "TIME"); + lstSqlType->insert("QDateTime", "TIMESTAMP"); + lstSqlType->insert("QByteArray", "BLOB"); + lstSqlType->insert("qx::QxDateNeutral", "TEXT"); + lstSqlType->insert("qx::QxTimeNeutral", "TEXT"); + lstSqlType->insert("qx::QxDateTimeNeutral", "TEXT"); + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.cpp b/src/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.cpp new file mode 100644 index 0000000..cb49af1 --- /dev/null +++ b/src/QxDao/QxSqlGenerator/QxSqlGenerator_Standard.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +namespace qx +{ + namespace dao + { + namespace detail + { + + QxSqlGenerator_Standard::QxSqlGenerator_Standard() : IxSqlGenerator() { ; } + + QxSqlGenerator_Standard::~QxSqlGenerator_Standard() { ; } + + void QxSqlGenerator_Standard::init() { ; } + + QString QxSqlGenerator_Standard::getAutoIncrement() const { return "AUTOINCREMENT"; } + + QString QxSqlGenerator_Standard::getWildCard() const { return "%"; } + + QString QxSqlGenerator_Standard::getTableAliasSep() const { return " AS "; } + + QString QxSqlGenerator_Standard::getLimit(const QxSqlLimit *pLimit) const + { + if (!pLimit) + { + qAssert(false); + return ""; + } + QString sStartRow = pLimit->getStartRow_ParamKey(); + QString sRowsCount = pLimit->getRowsCount_ParamKey(); + return ("LIMIT " + sRowsCount + " OFFSET " + sStartRow); + } + + void QxSqlGenerator_Standard::resolveLimit(QSqlQuery &query, const QxSqlLimit *pLimit, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + if (!pLimit) + { + qAssert(false); + return; + } + QString sStartRow = pLimit->getStartRow_ParamKey(); + QString sRowsCount = pLimit->getRowsCount_ParamKey(); + int iStartRow(pLimit->getStartRow()), iRowsCount(pLimit->getRowsCount()); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + + if (pLstExecBatch) + { + if (!pLstExecBatch->exist(sRowsCount)) + { + QVariantList empty; + pLstExecBatch->insert(sRowsCount, empty); + } + if (!pLstExecBatch->exist(sStartRow)) + { + QVariantList empty; + pLstExecBatch->insert(sStartRow, empty); + } + QVariantList &valuesRowsCount = const_cast(pLstExecBatch->getByKey(sRowsCount)); + QVariantList &valuesStartRow = const_cast(pLstExecBatch->getByKey(sStartRow)); + valuesRowsCount.append(iRowsCount); + valuesStartRow.append(iStartRow); + } + else + { + if (bQuestionMark) + { + query.addBindValue(iRowsCount); + query.addBindValue(iStartRow); + } + else + { + query.bindValue(sRowsCount, iRowsCount); + query.bindValue(sStartRow, iStartRow); + } + } + } + + void QxSqlGenerator_Standard::postProcess(QString &sql, const QxSqlLimit *pLimit) const + { + Q_UNUSED(sql); + Q_UNUSED(pLimit); + } + + void QxSqlGenerator_Standard::onBeforeInsert(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::onAfterInsert(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::onBeforeUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::onAfterUpdate(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::onBeforeDelete(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::onAfterDelete(IxDao_Helper *pDaoHelper, void *pOwner) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(pOwner); + } + + void QxSqlGenerator_Standard::checkSqlInsert(IxDao_Helper *pDaoHelper, QString &sql) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(sql); + } + + void QxSqlGenerator_Standard::onBeforeSqlPrepare(IxDao_Helper *pDaoHelper, QString &sql) const + { + Q_UNUSED(pDaoHelper); + Q_UNUSED(sql); + } + + void QxSqlGenerator_Standard::formatSqlQuery(IxDao_Helper *pDaoHelper, QString &sql) const + { + Q_UNUSED(pDaoHelper); + + if (sql.startsWith("SELECT ")) + { + sql = "\nSELECT " + sql.right(sql.size() - 7); + } + else if (sql.startsWith("INSERT ")) + { + sql = "\nINSERT " + sql.right(sql.size() - 7); + } + else if (sql.startsWith("UPDATE ")) + { + sql = "\nUPDATE " + sql.right(sql.size() - 7); + } + else if (sql.startsWith("DELETE ")) + { + sql = "\nDELETE " + sql.right(sql.size() - 7); + } + else if (sql.startsWith("CREATE ")) + { + sql = "\nCREATE " + sql.right(sql.size() - 7); + } + + sql.replace(" FROM ", "\n FROM "); + sql.replace(" WHERE ", "\n WHERE "); + sql.replace(" LEFT OUTER JOIN ", "\n LEFT OUTER JOIN "); + sql.replace(" INNER JOIN ", "\n INNER JOIN "); + sql.replace(" ORDER BY ", "\n ORDER BY "); + sql.replace(" GROUP BY ", "\n GROUP BY "); + sql.replace(" AND ", "\n AND "); + sql.replace(" OR ", "\n OR "); + sql.replace(" VALUES ", "\n VALUES "); + sql.replace(" SET ", "\n SET "); + sql.replace(" RETURNING ", "\n RETURNING "); + sql.replace(" LIMIT ", "\n LIMIT "); + sql += "\n"; + } + + } // namespace detail + } // namespace dao +} // namespace qx diff --git a/src/QxDao/QxSqlQuery.cpp b/src/QxDao/QxSqlQuery.cpp new file mode 100644 index 0000000..ec92613 --- /dev/null +++ b/src/QxDao/QxSqlQuery.cpp @@ -0,0 +1,1604 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +namespace qx +{ + + QxSqlQuery::QxSqlQuery() : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) { m_sQuery << QString(); } + + QxSqlQuery::QxSqlQuery(const char *query, const QVariantList &values /* = QVariantList() */) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) + { + if (values.count() <= 0) + { + m_sQuery << QString(query); + } + else + { + addFreeText(query, values); + } + } + + QxSqlQuery::QxSqlQuery(const QString &query, const QVariantList &values /* = QVariantList() */) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) + { + if (values.count() <= 0) + { + m_sQuery << query; + } + else + { + addFreeText(query, values); + } + } + + QxSqlQuery::QxSqlQuery(const QStringList &query) : m_sQuery(query), m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) { ; } + + QxSqlQuery::QxSqlQuery(const QString &type, const QString &query) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false), m_sType(type) { m_sQuery << query; } + + QxSqlQuery::QxSqlQuery(const QString &type, const QStringList &query) : m_sQuery(query), m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false), m_sType(type) { ; } + +#ifndef _QX_NO_JSON +#ifdef Q_COMPILER_INITIALIZER_LISTS + + QxSqlQuery::QxSqlQuery(std::initializer_list> json) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) + { + QJsonObject obj; + for (std::initializer_list>::const_iterator itr = json.begin(); itr != json.end(); ++itr) + { + obj.insert(itr->first, itr->second); + } + QJsonDocument doc(obj); + m_sQuery << QString::fromUtf8(doc.toJson()); + } + + QxSqlQuery::QxSqlQuery(std::initializer_list> json, std::initializer_list> opts) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false) + { + QJsonObject obj1; + for (std::initializer_list>::const_iterator itr = json.begin(); itr != json.end(); ++itr) + { + obj1.insert(itr->first, itr->second); + } + QJsonObject obj2; + for (std::initializer_list>::const_iterator itr = opts.begin(); itr != opts.end(); ++itr) + { + obj2.insert(itr->first, itr->second); + } + QJsonDocument doc1(obj1); + QJsonDocument doc2(obj2); + m_sQuery << QString::fromUtf8(doc1.toJson()) << QString::fromUtf8(doc2.toJson()); + } + + QxSqlQuery::QxSqlQuery(const QString &type, std::initializer_list> json) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false), m_sType(type) + { + QJsonObject obj; + for (std::initializer_list>::const_iterator itr = json.begin(); itr != json.end(); ++itr) + { + obj.insert(itr->first, itr->second); + } + QJsonDocument doc(obj); + m_sQuery << QString::fromUtf8(doc.toJson()); + } + + QxSqlQuery::QxSqlQuery(const QString &type, std::initializer_list> json, std::initializer_list> opts) : m_iSqlElementIndex(0), m_iParenthesisCount(0), m_bDistinct(false), m_sType(type) + { + QJsonObject obj1; + for (std::initializer_list>::const_iterator itr = json.begin(); itr != json.end(); ++itr) + { + obj1.insert(itr->first, itr->second); + } + QJsonObject obj2; + for (std::initializer_list>::const_iterator itr = opts.begin(); itr != opts.end(); ++itr) + { + obj2.insert(itr->first, itr->second); + } + QJsonDocument doc1(obj1); + QJsonDocument doc2(obj2); + m_sQuery << QString::fromUtf8(doc1.toJson()) << QString::fromUtf8(doc2.toJson()); + } + +#endif // Q_COMPILER_INITIALIZER_LISTS +#endif // _QX_NO_JSON + + QxSqlQuery::~QxSqlQuery() { ; } + + void QxSqlQuery::verifyQuery() const + { +#ifdef _QX_MODE_DEBUG + if (queryAt(0).isEmpty() || (m_lstSqlElement.count() <= 0)) + { + return; + } + qDebug("[QxOrm] qx::QxSqlQuery::verifyQuery() : '%s'", "invalid SQL query, you cannot mix classic SQL and C++ syntax"); + qAssert(false); +#endif // _QX_MODE_DEBUG + } + + QString QxSqlQuery::query() + { + verifyQuery(); + if (m_lstSqlElement.count() <= 0) + { + return queryAt(0); + } + while (m_iParenthesisCount > 0) + { + closeParenthesis(); + } + + QString sQuery; + for (int i = 0; i < m_lstSqlElement.count(); i++) + { + sQuery += m_lstSqlElement.at(i)->toString() + " "; + } + return sQuery; + } + + QString QxSqlQuery::queryAt(int idx) const + { + if ((idx < 0) || (idx >= m_sQuery.count())) + { + return QString(); + } + return m_sQuery.at(idx); + } + + void QxSqlQuery::queryAt(int idx, const QString &query) + { + while ((m_sQuery.count() - 1) < idx) + { + m_sQuery << QString(); + } + m_sQuery.replace(idx, query); + qAssert(m_sQuery.at(idx) == query); + } + + QVariant QxSqlQuery::response() const + { + return m_vResponse; + } + + void QxSqlQuery::setResponse(const QVariant &v) + { + m_vResponse = v; + } + + QString QxSqlQuery::type() const + { + return m_sType; + } + + void QxSqlQuery::setType(const QString &s) + { + m_sType = s; + } + + bool QxSqlQuery::isEmpty() const + { + return (queryAt(0).isEmpty() && (m_lstSqlElement.count() <= 0) && (m_lstJoinQueryUser.count() <= 0)); + } + + bool QxSqlQuery::isDistinct() const + { + return m_bDistinct; + } + + void QxSqlQuery::clear() + { + m_sQuery.clear(); + m_lstValue.clear(); + m_pSqlElementTemp.reset(); + m_lstSqlElement.clear(); + m_iSqlElementIndex = 0; + m_iParenthesisCount = 0; + m_vResponse = QVariant(); + m_sType = ""; + m_lstJoinQueryUser.clear(); + m_lstJoinQueryToResolve.clear(); + } + + QxSqlQuery &QxSqlQuery::query(const QString &sQuery) + { + if (!sQuery.isEmpty()) + { + qAssert(m_lstSqlElement.count() <= 0); + } + + clear(); + m_sQuery << sQuery; + return (*this); + } + + QxSqlQuery &QxSqlQuery::bind(const QVariant &vValue, QSql::ParamType paramType /* = QSql::In */) + { + verifyQuery(); + qAssert(m_lstSqlElement.count() <= 0); + qAssert(!queryAt(0).isEmpty() && (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark)); + + QString sKey = QString::number(m_lstValue.count() + 1); + m_lstValue.insert(sKey, type_bind_value(vValue, paramType)); + return (*this); + } + + QxSqlQuery &QxSqlQuery::bind(const QString &sKey, const QVariant &vValue, QSql::ParamType paramType /* = QSql::In */) + { + verifyQuery(); + qAssert(m_lstSqlElement.count() <= 0); + qAssert(!queryAt(0).isEmpty() && (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() != qx::QxSqlDatabase::ph_style_question_mark)); + + if (sKey.isEmpty() || m_lstValue.exist(sKey)) + { + qAssert(false); + return (*this); + } + if (!queryAt(0).contains(sKey)) + { + qAssert(false); + return (*this); + } + m_lstValue.insert(sKey, type_bind_value(vValue, paramType)); + return (*this); + } + + QVariant QxSqlQuery::boundValue(const QString &sKey) const + { + if (sKey.isEmpty() || !m_lstValue.exist(sKey)) + { + qAssert(false); + return QVariant(); + } + return std::get<0>(m_lstValue.getByKey(sKey)); + } + + QVariant QxSqlQuery::boundValue(int iPosition) const + { + if ((iPosition < 0) || (iPosition >= m_lstValue.count())) + { + qAssert(false); + return QVariant(); + } + return std::get<0>(m_lstValue.getByIndex(iPosition)); + } + + void QxSqlQuery::resolve(QSqlQuery &query, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + verifyQuery(); + + for (int i = 0; i < m_lstJoinQueryToResolve.count(); i++) + { + std::shared_ptr joinQuery = m_lstJoinQueryToResolve.at(i); + joinQuery->resolve(query, pLstExecBatch); + } + + if (m_lstSqlElement.count() > 0) + { + for (int i = 0; i < m_lstSqlElement.count(); i++) + { + m_lstSqlElement.at(i)->resolve(query, pLstExecBatch); + } + return; + } + + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + QxCollectionIterator itr(m_lstValue); + while (itr.next()) + { + if (pLstExecBatch) + { + QString key = itr.key(); + if (!pLstExecBatch->exist(key)) + { + QVariantList empty; + pLstExecBatch->insert(key, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(key)); + values.append(std::get<0>(itr.value())); + } + else + { + if (bQuestionMark) + { + query.addBindValue(std::get<0>(itr.value()), std::get<1>(itr.value())); + } + else + { + query.bindValue(itr.key(), std::get<0>(itr.value()), std::get<1>(itr.value())); + } + } + } + } + + void QxSqlQuery::resolveOutput(QSqlQuery &query, bool bFetchSqlResult) + { + QxCollection lst; + lst.reserve(m_lstValue.count()); + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + for (long l = 0; l < m_lstValue.count(); l++) + { + QVariant outputValue; + QString key = m_lstValue.getKeyByIndex(l); + type_bind_value val = m_lstValue.getByIndex(l); + QSql::ParamType paramType = std::get<1>(val); + if (paramType == QSql::In) + { + lst.insert(key, val); + continue; + } + if (bQuestionMark) + { + outputValue = query.boundValue(l); + } + else + { + outputValue = query.boundValue(key); + } + lst.insert(key, type_bind_value(outputValue, paramType)); + } + if (bFetchSqlResult) + { + fetchSqlResult(query); + } + m_lstValue = lst; + } + + QString QxSqlQuery::getJoinQuery(const QString &relationKey, const QString &relationAlias) + { + if (m_lstJoinQueryUser.contains(relationKey)) + { + std::shared_ptr query = m_lstJoinQueryUser.value(relationKey); + m_lstJoinQueryToResolve.append(query); + return query->query().trimmed(); + } + else if (m_lstJoinQueryUser.contains(relationAlias)) + { + std::shared_ptr query = m_lstJoinQueryUser.value(relationAlias); + m_lstJoinQueryToResolve.append(query); + return query->query().trimmed(); + } + return QString(); + } + + QString QxSqlQuery::getJoinQueryHash() + { + QString hash; + QHashIterator> itr(m_lstJoinQueryUser); + while (itr.hasNext()) + { + itr.next(); + std::shared_ptr tmp = itr.value(); + hash += "|" + itr.key() + "|" + tmp->query(); + } + return hash; + } + + void QxSqlQuery::dumpBoundValues(const QSqlQuery &query) + { + QString sBoundValues = ""; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QVariantList lstBoundValues = query.boundValues(); +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QMap lstBoundValues = query.boundValues(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (lstBoundValues.count() <= 0) + { + return; + } + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + for (int i = 0; i < lstBoundValues.size(); ++i) + { + sBoundValues += "\n - position '" + QString::number(i) + "' : " + lstBoundValues.at(i).toString(); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark) + { + QList lst = lstBoundValues.values(); + for (int i = 0; i < lst.size(); ++i) + { + sBoundValues += "\n - position '" + QString::number(i) + "' : " + lst.at(i).toString(); + } + } + else + { + QMapIterator itr(lstBoundValues); + while (itr.hasNext()) + { + itr.next(); + sBoundValues += "\n - " + itr.key() + " : " + itr.value().toString(); + } + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + + if (!sBoundValues.isEmpty()) + { + qDebug("[QxOrm] dump sql query bound values : %s", qPrintable(sBoundValues)); + } + } + + QxSqlQuery &QxSqlQuery::setFctOnBeforeSqlPrepare(QxSqlQuery::type_fct_on_before_sql_prepare fct) + { + m_fctOnBeforeSqlPrepare = fct; + return (*this); + } + + void QxSqlQuery::onBeforeSqlPrepare(QString &sql) + { + if (m_fctOnBeforeSqlPrepare) + { + m_fctOnBeforeSqlPrepare(sql); + } + } + + void QxSqlQuery::fetchSqlResult(QSqlQuery &query) + { + bool bCheckRecord = true; + m_pSqlResult = std::make_shared(); + if (query.size() > 0) + { + m_pSqlResult->values.reserve(query.size()); + } + while (query.next()) + { + if (bCheckRecord) + { + bCheckRecord = false; + QSqlRecord record = query.record(); + m_pSqlResult->positionByKey.reserve(record.count()); + for (int i = 0; i < record.count(); i++) + { + m_pSqlResult->positionByKey.insert(record.fieldName(i), i); + } + qAssert(record.count() == m_pSqlResult->positionByKey.count()); + } + QVector lst; + lst.reserve(m_pSqlResult->positionByKey.count()); + for (long j = 0; j < m_pSqlResult->positionByKey.count(); j++) + { + lst.append(query.value(j)); + } + qAssert(lst.count() == m_pSqlResult->positionByKey.count()); + m_pSqlResult->values.append(lst); + } + } + + long QxSqlQuery::getSqlResultRowCount() const + { + if (!m_pSqlResult) + { + return 0; + } + return m_pSqlResult->values.count(); + } + + long QxSqlQuery::getSqlResultColumnCount() const + { + if (!m_pSqlResult) + { + return 0; + } + return m_pSqlResult->positionByKey.count(); + } + + QVariant QxSqlQuery::getSqlResultAt(long row, long column) const + { + if (!m_pSqlResult) + { + return QVariant(); + } + if ((row < 0) || (row >= m_pSqlResult->values.count())) + { + return QVariant(); + } + if ((column < 0) || (column >= m_pSqlResult->positionByKey.count())) + { + return QVariant(); + } + return m_pSqlResult->values.at(row).at(column); + } + + QVariant QxSqlQuery::getSqlResultAt(long row, const QString &column, bool caseSensitive /* = false */) const + { + if (!m_pSqlResult) + { + return QVariant(); + } + if ((row < 0) || (row >= m_pSqlResult->values.count())) + { + return QVariant(); + } + + int i(-1); + int col = m_pSqlResult->positionByKey.value(column, i); + if (col >= 0) + { + return m_pSqlResult->values.at(row).at(col); + } + if (caseSensitive) + { + return QVariant(); + } + + if (m_pSqlResult->positionByKeyUpper.count() <= 0) + { + QHashIterator itr(m_pSqlResult->positionByKey); + while (itr.hasNext()) + { + itr.next(); + QString keyUpper = itr.key().toUpper(); + int val = itr.value(); + m_pSqlResult->positionByKeyUpper.insert(keyUpper, val); + } + } + + QString columnUpper = column.toUpper(); + int j(-1); + col = m_pSqlResult->positionByKeyUpper.value(columnUpper, j); + return ((col >= 0) ? m_pSqlResult->values.at(row).at(col) : QVariant()); + } + + QVector QxSqlQuery::getSqlResultAt(long row) const + { + if (!m_pSqlResult) + { + return QVector(); + } + if ((row < 0) || (row >= m_pSqlResult->values.count())) + { + return QVector(); + } + return m_pSqlResult->values.at(row); + } + + QVector QxSqlQuery::getSqlResultAllColumns() const + { + if (!m_pSqlResult) + { + return QVector(); + } + QVector lstAllColumns(m_pSqlResult->positionByKey.count()); + QHashIterator itr(m_pSqlResult->positionByKey); + while (itr.hasNext()) + { + itr.next(); + lstAllColumns[itr.value()] = itr.key(); + } + return lstAllColumns; + } + + void QxSqlQuery::dumpSqlResult() + { + if (!m_pSqlResult) + { + return; + } + QString sql(this->query()), sColumns("#"), sOutput; + qDebug("[QxOrm] start dump sql result : '%s'", qPrintable(sql)); + QVector lstColumns = this->getSqlResultAllColumns(); + for (long i = 0; i < lstColumns.count(); i++) + { + sColumns += "|" + lstColumns.at(i); + } + qDebug("%s", qPrintable(sColumns)); + for (long j = 0; j < m_pSqlResult->values.count(); j++) + { + sOutput = QString::number(j); + for (long k = 0; k < m_pSqlResult->positionByKey.count(); k++) + { + sOutput += "|" + m_pSqlResult->values.at(j).at(k).toString(); + } + qDebug("%s", qPrintable(sOutput)); + } + qDebug("[QxOrm] end dump sql result : '%s'", qPrintable(sql)); + } + + void QxSqlQuery::postProcess(QString &sql) const + { + verifyQuery(); + for (int i = 0; i < m_lstSqlElement.count(); i++) + { + m_lstSqlElement.at(i)->postProcess(sql); + } + } + + QxSqlQuery &QxSqlQuery::distinct() + { + m_bDistinct = true; + return (*this); + } + + QxSqlQuery &QxSqlQuery::where(const QString &column) + { + return addSqlExpression(column, qx::dao::detail::QxSqlExpression::_where); + } + + QxSqlQuery &QxSqlQuery::where_OpenParenthesis(const QString &column) + { + where(column); + return openParenthesis(); + } + + QxSqlQuery &QxSqlQuery::and_(const QString &column) + { + return addSqlExpression(column, qx::dao::detail::QxSqlExpression::_and); + } + + QxSqlQuery &QxSqlQuery::and_OpenParenthesis(const QString &column) + { + and_(column); + return openParenthesis(); + } + + QxSqlQuery &QxSqlQuery::or_(const QString &column) + { + return addSqlExpression(column, qx::dao::detail::QxSqlExpression::_or); + } + + QxSqlQuery &QxSqlQuery::or_OpenParenthesis(const QString &column) + { + or_(column); + return openParenthesis(); + } + + QxSqlQuery &QxSqlQuery::openParenthesis() + { + qx::dao::detail::QxSqlExpression_ptr p; + p = std::make_shared(m_iSqlElementIndex++, qx::dao::detail::QxSqlExpression::_open_parenthesis); + m_lstSqlElement.append(p); + m_iParenthesisCount++; + return (*this); + } + + QxSqlQuery &QxSqlQuery::closeParenthesis() + { + if (m_iParenthesisCount <= 0) + { + return (*this); + } + qx::dao::detail::QxSqlExpression_ptr p; + p = std::make_shared(m_iSqlElementIndex++, qx::dao::detail::QxSqlExpression::_close_parenthesis); + m_lstSqlElement.append(p); + m_iParenthesisCount--; + m_pSqlElementTemp.reset(); + return (*this); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QStringList &columns) + { + return addSqlSort(columns, qx::dao::detail::QxSqlSort::_order_asc); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1) + { + return orderAsc(QStringList() << col1); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2) + { + return orderAsc(QStringList() << col1 << col2); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3) + { + return orderAsc(QStringList() << col1 << col2 << col3); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4 << col5); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8); + } + + QxSqlQuery &QxSqlQuery::orderAsc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) + { + return orderAsc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8 << col9); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QStringList &columns) + { + return addSqlSort(columns, qx::dao::detail::QxSqlSort::_order_desc); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1) + { + return orderDesc(QStringList() << col1); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2) + { + return orderDesc(QStringList() << col1 << col2); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3) + { + return orderDesc(QStringList() << col1 << col2 << col3); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4 << col5); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8); + } + + QxSqlQuery &QxSqlQuery::orderDesc(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) + { + return orderDesc(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8 << col9); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QStringList &columns) + { + return addSqlSort(columns, qx::dao::detail::QxSqlSort::_group_by); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1) + { + return groupBy(QStringList() << col1); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2) + { + return groupBy(QStringList() << col1 << col2); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3) + { + return groupBy(QStringList() << col1 << col2 << col3); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4 << col5); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4 << col5 << col6); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8); + } + + QxSqlQuery &QxSqlQuery::groupBy(const QString &col1, const QString &col2, const QString &col3, const QString &col4, const QString &col5, const QString &col6, const QString &col7, const QString &col8, const QString &col9) + { + return groupBy(QStringList() << col1 << col2 << col3 << col4 << col5 << col6 << col7 << col8 << col9); + } + + QxSqlQuery &QxSqlQuery::limit(int rowsCount, int startRow /* = 0 */, bool withTies /* = false */) + { + qx::dao::detail::QxSqlLimit_ptr p; + p = std::make_shared(m_iSqlElementIndex++); + p->setValues(QVariantList() << QVariant(startRow) << QVariant(rowsCount) << QVariant(withTies)); + m_lstSqlElement.append(p); + return (*this); + } + + QxSqlQuery &QxSqlQuery::like(const QString &val) + { + return addSqlCompare(QVariant(val), qx::dao::detail::QxSqlCompare::_like); + } + + QxSqlQuery &QxSqlQuery::notLike(const QString &val) + { + return addSqlCompare(QVariant(val), qx::dao::detail::QxSqlCompare::_not_like); + } + + QxSqlQuery &QxSqlQuery::startsWith(const QString &val) + { + return addSqlCompare(QVariant(val), qx::dao::detail::QxSqlCompare::_starts_with); + } + + QxSqlQuery &QxSqlQuery::endsWith(const QString &val) + { + return addSqlCompare(QVariant(val), qx::dao::detail::QxSqlCompare::_ends_with); + } + + QxSqlQuery &QxSqlQuery::containsString(const QString &val) + { + return addSqlCompare(QVariant(val), qx::dao::detail::QxSqlCompare::_contains_string); + } + + QxSqlQuery &QxSqlQuery::isEqualTo(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_equal_to); + } + + QxSqlQuery &QxSqlQuery::isNotEqualTo(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_not_equal_to); + } + + QxSqlQuery &QxSqlQuery::isGreaterThan(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_greater_than); + } + + QxSqlQuery &QxSqlQuery::isGreaterThanOrEqualTo(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_greater_than_or_equal_to); + } + + QxSqlQuery &QxSqlQuery::isLessThan(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_less_than); + } + + QxSqlQuery &QxSqlQuery::isLessThanOrEqualTo(const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_is_less_than_or_equal_to); + } + + QxSqlQuery &QxSqlQuery::customOperator(const QString &sCustomOperator, const QVariant &val) + { + return addSqlCompare(val, qx::dao::detail::QxSqlCompare::_custom_operator, sCustomOperator); + } + + QxSqlQuery &QxSqlQuery::in(const QVariantList &values) + { + return addSqlIn(values, qx::dao::detail::QxSqlIn::_in); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1) + { + return in(QVariantList() << val1); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2) + { + return in(QVariantList() << val1 << val2); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3) + { + return in(QVariantList() << val1 << val2 << val3); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4) + { + return in(QVariantList() << val1 << val2 << val3 << val4); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5) + { + return in(QVariantList() << val1 << val2 << val3 << val4 << val5); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6) + { + return in(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7) + { + return in(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8) + { + return in(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7 << val8); + } + + QxSqlQuery &QxSqlQuery::in(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9) + { + return in(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7 << val8 << val9); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariantList &values) + { + return addSqlIn(values, qx::dao::detail::QxSqlIn::_not_in); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1) + { + return notIn(QVariantList() << val1); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2) + { + return notIn(QVariantList() << val1 << val2); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3) + { + return notIn(QVariantList() << val1 << val2 << val3); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4 << val5); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7 << val8); + } + + QxSqlQuery &QxSqlQuery::notIn(const QVariant &val1, const QVariant &val2, const QVariant &val3, const QVariant &val4, const QVariant &val5, const QVariant &val6, const QVariant &val7, const QVariant &val8, const QVariant &val9) + { + return notIn(QVariantList() << val1 << val2 << val3 << val4 << val5 << val6 << val7 << val8 << val9); + } + + QxSqlQuery &QxSqlQuery::in_Select(const QxSqlQuery &query) + { + if (query.m_lstSqlElement.count() <= 0) + { + addSqlIn(QVariantList() << QVariant(query.queryAt(0)), qx::dao::detail::QxSqlIn::_in_select); + } + else + { + addEmbedQuery(query, qx::dao::detail::QxSqlEmbedQuery::_in, true); + } + return (*this); + } + + QxSqlQuery &QxSqlQuery::notIn_Select(const QxSqlQuery &query) + { + if (query.m_lstSqlElement.count() <= 0) + { + addSqlIn(QVariantList() << QVariant(query.queryAt(0)), qx::dao::detail::QxSqlIn::_not_in_select); + } + else + { + addEmbedQuery(query, qx::dao::detail::QxSqlEmbedQuery::_not_in, true); + } + return (*this); + } + + QxSqlQuery &QxSqlQuery::isEqualTo_Select(const QxSqlQuery &query) + { + if (query.m_lstSqlElement.count() <= 0) + { + addSqlCompare(query.queryAt(0), qx::dao::detail::QxSqlCompare::_is_equal_to_select); + } + else + { + addEmbedQuery(query, qx::dao::detail::QxSqlEmbedQuery::_is_equal_to, true); + } + return (*this); + } + + QxSqlQuery &QxSqlQuery::isNotEqualTo_Select(const QxSqlQuery &query) + { + if (query.m_lstSqlElement.count() <= 0) + { + addSqlCompare(query.queryAt(0), qx::dao::detail::QxSqlCompare::_is_not_equal_to_select); + } + else + { + addEmbedQuery(query, qx::dao::detail::QxSqlEmbedQuery::_is_not_equal_to, true); + } + return (*this); + } + + QxSqlQuery &QxSqlQuery::isNull() + { + return addSqlIsNull(qx::dao::detail::QxSqlIsNull::_is_null); + } + + QxSqlQuery &QxSqlQuery::isNotNull() + { + return addSqlIsNull(qx::dao::detail::QxSqlIsNull::_is_not_null); + } + + QxSqlQuery &QxSqlQuery::isBetween(const QVariant &val1, const QVariant &val2) + { + return addSqlIsBetween(val1, val2, qx::dao::detail::QxSqlIsBetween::_is_between); + } + + QxSqlQuery &QxSqlQuery::isNotBetween(const QVariant &val1, const QVariant &val2) + { + return addSqlIsBetween(val1, val2, qx::dao::detail::QxSqlIsBetween::_is_not_between); + } + + QxSqlQuery &QxSqlQuery::freeText(const QString &text, const QVariantList &values /* = QVariantList() */) + { + if (text.isEmpty()) + { + return (*this); + } + return addFreeText(text, values); + } + + QxSqlQuery &QxSqlQuery::addJoinQuery(const QString &relationKeyOrAlias, const QxSqlQuery &joinQuery) + { + std::shared_ptr pQuery = std::make_shared(joinQuery); + m_lstJoinQueryUser.insert(relationKeyOrAlias, pQuery); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlExpression(const QString &column, qx::dao::detail::QxSqlExpression::type type) + { + qx::dao::detail::QxSqlExpression_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + m_lstSqlElement.append(p); + + m_pSqlElementTemp = std::make_shared(); + m_pSqlElementTemp->setColumn(column); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlCompare(const QVariant &val, qx::dao::detail::QxSqlCompare::type type, const QString &sCustomOperator /* = QString() */) + { + if (!m_pSqlElementTemp) + { + qDebug("[QxOrm] qx::QxSqlQuery::addSqlCompare : '%s'", "invalid SQL query, need a column name"); + qAssert(false); + return (*this); + } + + qx::dao::detail::QxSqlCompare_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type, sCustomOperator); + p->clone(m_pSqlElementTemp.get()); + p->setValue(val); + + m_lstSqlElement.append(p); + m_pSqlElementTemp.reset(); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlSort(const QStringList &columns, qx::dao::detail::QxSqlSort::type type) + { + qx::dao::detail::QxSqlSort_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + p->setColumns(columns); + m_lstSqlElement.append(p); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlIn(const QVariantList &values, qx::dao::detail::QxSqlIn::type type) + { + if (!m_pSqlElementTemp) + { + qDebug("[QxOrm] qx::QxSqlQuery::addSqlIn : '%s'", "invalid SQL query, need a column name"); + qAssert(false); + return (*this); + } + + qx::dao::detail::QxSqlIn_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + p->clone(m_pSqlElementTemp.get()); + p->setValues(values); + + m_lstSqlElement.append(p); + m_pSqlElementTemp.reset(); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlIsNull(qx::dao::detail::QxSqlIsNull::type type) + { + if (!m_pSqlElementTemp) + { + qDebug("[QxOrm] qx::QxSqlQuery::addSqlIsNull : '%s'", "invalid SQL query, need a column name"); + qAssert(false); + return (*this); + } + + qx::dao::detail::QxSqlIsNull_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + p->clone(m_pSqlElementTemp.get()); + + m_lstSqlElement.append(p); + m_pSqlElementTemp.reset(); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addSqlIsBetween(const QVariant &val1, const QVariant &val2, qx::dao::detail::QxSqlIsBetween::type type) + { + if (!m_pSqlElementTemp) + { + qDebug("[QxOrm] qx::QxSqlQuery::addSqlIsBetween : '%s'", "invalid SQL query, need a column name"); + qAssert(false); + return (*this); + } + + qx::dao::detail::QxSqlIsBetween_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + p->clone(m_pSqlElementTemp.get()); + p->setValues(QVariantList() << val1 << val2); + + m_lstSqlElement.append(p); + m_pSqlElementTemp.reset(); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addFreeText(const QString &text, const QVariantList &values) + { + qx::dao::detail::QxSqlFreeText_ptr p; + p = std::make_shared(m_iSqlElementIndex++); + p->setText(text); + p->setValues(values); + m_lstSqlElement.append(p); + return (*this); + } + + QxSqlQuery &QxSqlQuery::addEmbedQuery(const QxSqlQuery &query, qx::dao::detail::QxSqlEmbedQuery::type type, bool requirePreviousElement) + { + if ((requirePreviousElement) && (!m_pSqlElementTemp)) + { + qDebug("[QxOrm] qx::QxSqlQuery::addEmbedQuery : '%s'", "invalid SQL query, need a column name"); + qAssert(false); + return (*this); + } + + qx::dao::detail::QxSqlEmbedQuery_ptr p; + p = std::make_shared(m_iSqlElementIndex++, type); + if (requirePreviousElement) + { + p->clone(m_pSqlElementTemp.get()); + } + p->setQuery(query); + + m_lstSqlElement.append(p); + m_pSqlElementTemp.reset(); + return (*this); + } + +} // namespace qx + +namespace qx +{ + namespace dao + { + + QSqlError call_query(qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) { return qx::dao::helper::call_query_helper(query, pDatabase, true); } + + QSqlError call_query_without_prepare(qx::QxSqlQuery &query, QSqlDatabase *pDatabase /* = NULL */) { return qx::dao::helper::call_query_helper(query, pDatabase, false); } + + namespace helper + { + + QSqlError call_query_helper(qx::QxSqlQuery &query, QSqlDatabase *pDatabase, bool bPrepare) + { +#ifdef _QX_ENABLE_MONGODB + if (qx::QxSqlDatabase::getSingleton()->getDriverName() == "QXMONGODB") + { + return qx::dao::mongodb::QxMongoDB_Helper::executeCommand(NULL, NULL, (&query)); + } +#endif // _QX_ENABLE_MONGODB + + QSqlError dbError; + QSqlDatabase d = (pDatabase ? (*pDatabase) : qx::QxSqlDatabase::getDatabase(dbError)); + if (dbError.isValid()) + { + return dbError; + } + bool bBoundValues = qx::QxSqlDatabase::getSingleton()->getTraceSqlBoundValues(); + bool bBoundValuesOnError = qx::QxSqlDatabase::getSingleton()->getTraceSqlBoundValuesOnError(); + QElapsedTimer timer; + timer.start(); + QString sql = query.query(); + QSqlQuery q = QSqlQuery(d); + q.setForwardOnly(true); + + do + { + if (bPrepare && !q.prepare(sql)) + { + dbError = q.lastError(); + break; + } + query.resolve(q); + if (bPrepare) + { + if (!q.exec()) + { + dbError = q.lastError(); + break; + } + } + else + { + if (!q.exec(sql)) + { + dbError = q.lastError(); + break; + } + } + query.resolveOutput(q, true); + } while (0); + + qlonglong ms = static_cast(timer.elapsed()); + if (dbError.isValid()) + { + QString log = "custom sql query failed (" + QString::number(ms) + " ms) : " + sql; + qDebug("[QxOrm] %s", qPrintable(log)); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString serr = dbError.nativeErrorCode(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int ierr = dbError.number(); + QString serr = QString::number(ierr); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString tmp = dbError.driverText(); + qDebug("Database error number '%s' : %s", qPrintable(serr), qPrintable(tmp)); + tmp = dbError.databaseText(); + qDebug("%s", qPrintable(tmp)); + } + else if (qx::QxSqlDatabase::getSingleton()->getTraceSqlQuery()) + { + qlonglong iTraceSqlOnlySlowQueriesDatabase = static_cast(qx::QxSqlDatabase::getSingleton()->getTraceSqlOnlySlowQueriesDatabase()); + qlonglong iTraceSqlOnlySlowQueriesTotal = static_cast(qx::QxSqlDatabase::getSingleton()->getTraceSqlOnlySlowQueriesTotal()); + if ((iTraceSqlOnlySlowQueriesDatabase > 0) && (iTraceSqlOnlySlowQueriesTotal < 0)) + { + iTraceSqlOnlySlowQueriesTotal = 999999999; + } + else if ((iTraceSqlOnlySlowQueriesTotal > 0) && (iTraceSqlOnlySlowQueriesDatabase < 0)) + { + iTraceSqlOnlySlowQueriesDatabase = 999999999; + } + if ((ms >= iTraceSqlOnlySlowQueriesTotal) || (ms >= iTraceSqlOnlySlowQueriesDatabase)) + { + QString log = "custom sql query (" + QString::number(ms) + " ms) : " + sql; + qDebug("[QxOrm] %s", qPrintable(log)); + } + } + + if ((dbError.isValid() && bBoundValuesOnError) || (bBoundValues)) + { + qx::QxSqlQuery::dumpBoundValues(q); + } + return dbError; + } + + } // namespace helper + } // namespace dao +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const qx::QxSqlQuery &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QHash lstResultPosByKey; + QVector> lstResultValues; + qx::dao::detail::IxSqlElement::type_class eNoSqlType = qx::dao::detail::IxSqlElement::_no_type; + + if (t.m_pSqlResult) + { + lstResultPosByKey = t.m_pSqlResult->positionByKey; + lstResultValues = t.m_pSqlResult->values; + } + + ar << boost::serialization::make_nvp("query", t.m_sQuery); + ar << boost::serialization::make_nvp("list_values", t.m_lstValue); + ar << boost::serialization::make_nvp("sql_element_index", t.m_iSqlElementIndex); + ar << boost::serialization::make_nvp("parenthesis_count", t.m_iParenthesisCount); + ar << boost::serialization::make_nvp("distinct", t.m_bDistinct); + ar << boost::serialization::make_nvp("result_position_by_key", lstResultPosByKey); + ar << boost::serialization::make_nvp("result_values", lstResultValues); + ar << boost::serialization::make_nvp("response", t.m_vResponse); + ar << boost::serialization::make_nvp("type", t.m_sType); + ar << boost::serialization::make_nvp("list_join_query_user", t.m_lstJoinQueryUser); + ar << boost::serialization::make_nvp("list_join_query_resolve", t.m_lstJoinQueryToResolve); + + if (!t.m_pSqlElementTemp) + { + ar << boost::serialization::make_nvp("sql_element_temp_type", eNoSqlType); + } + else + { + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = t.m_pSqlElementTemp->getTypeClass(); + ar << boost::serialization::make_nvp("sql_element_temp_type", eTypeSqlElement); + t.m_pSqlElementTemp->qxSave(ar); + } + + long lSqlElementCount = t.m_lstSqlElement.count(); + ar << boost::serialization::make_nvp("sql_element_count", lSqlElementCount); + Q_FOREACH (qx::dao::detail::IxSqlElement_ptr pSqlElement, t.m_lstSqlElement) + { + if (!pSqlElement) + { + ar << boost::serialization::make_nvp("sql_element_type", eNoSqlType); + continue; + } + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = pSqlElement->getTypeClass(); + ar << boost::serialization::make_nvp("sql_element_type", eTypeSqlElement); + pSqlElement->qxSave(ar); + } + } + + template + inline void qx_load(Archive &ar, qx::QxSqlQuery &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QHash lstResultPosByKey; + QVector> lstResultValues; + + ar >> boost::serialization::make_nvp("query", t.m_sQuery); + ar >> boost::serialization::make_nvp("list_values", t.m_lstValue); + ar >> boost::serialization::make_nvp("sql_element_index", t.m_iSqlElementIndex); + ar >> boost::serialization::make_nvp("parenthesis_count", t.m_iParenthesisCount); + ar >> boost::serialization::make_nvp("distinct", t.m_bDistinct); + ar >> boost::serialization::make_nvp("result_position_by_key", lstResultPosByKey); + ar >> boost::serialization::make_nvp("result_values", lstResultValues); + ar >> boost::serialization::make_nvp("response", t.m_vResponse); + ar >> boost::serialization::make_nvp("type", t.m_sType); + ar >> boost::serialization::make_nvp("list_join_query_user", t.m_lstJoinQueryUser); + ar >> boost::serialization::make_nvp("list_join_query_resolve", t.m_lstJoinQueryToResolve); + + t.m_pSqlResult.reset(); + if ((lstResultPosByKey.count() > 0) || (lstResultValues.count() > 0)) + { + t.m_pSqlResult = std::shared_ptr(new qx::QxSqlQuery::QxSqlResult()); + t.m_pSqlResult->positionByKey = lstResultPosByKey; + t.m_pSqlResult->values = lstResultValues; + } + + t.m_pSqlElementTemp.reset(); + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + ar >> boost::serialization::make_nvp("sql_element_temp_type", eTypeSqlElement); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + t.m_pSqlElementTemp = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(t.m_pSqlElementTemp); + if (t.m_pSqlElementTemp) + { + t.m_pSqlElementTemp->qxLoad(ar); + } + } + + t.m_lstSqlElement.clear(); + long lSqlElementCount = 0; + ar >> boost::serialization::make_nvp("sql_element_count", lSqlElementCount); + t.m_lstSqlElement.reserve(lSqlElementCount); + for (long l = 0; l < lSqlElementCount; l++) + { + qx::dao::detail::IxSqlElement_ptr pSqlElement; + eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + ar >> boost::serialization::make_nvp("sql_element_type", eTypeSqlElement); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + pSqlElement = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(pSqlElement); + if (pSqlElement) + { + pSqlElement->qxLoad(ar); + } + } + t.m_lstSqlElement.append(pSqlElement); + } + } + + } // namespace serialization +} // namespace boost + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(qx::QxSqlQuery) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +QDataStream &operator<<(QDataStream &stream, const qx::QxSqlQuery &t) +{ + QHash lstResultPosByKey; + QVector> lstResultValues; + qx::dao::detail::IxSqlElement::type_class eNoSqlType = qx::dao::detail::IxSqlElement::_no_type; + + if (t.m_pSqlResult) + { + lstResultPosByKey = t.m_pSqlResult->positionByKey; + lstResultValues = t.m_pSqlResult->values; + } + + stream << t.m_sQuery; + stream << t.m_lstValue; + stream << t.m_iSqlElementIndex; + stream << t.m_iParenthesisCount; + stream << t.m_bDistinct; + stream << lstResultPosByKey; + stream << lstResultValues; + stream << t.m_vResponse; + stream << t.m_sType; + stream << t.m_lstJoinQueryUser; + stream << t.m_lstJoinQueryToResolve; + + if (!t.m_pSqlElementTemp) + { + stream << (qint32)(eNoSqlType); + } + else + { + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = t.m_pSqlElementTemp->getTypeClass(); + stream << (qint32)(eTypeSqlElement); + stream << (*t.m_pSqlElementTemp); + } + + long lSqlElementCount = t.m_lstSqlElement.count(); + stream << (qint64)(lSqlElementCount); + Q_FOREACH (qx::dao::detail::IxSqlElement_ptr pSqlElement, t.m_lstSqlElement) + { + if (!pSqlElement) + { + stream << (qint32)(eNoSqlType); + continue; + } + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = pSqlElement->getTypeClass(); + stream << (qint32)(eTypeSqlElement); + stream << (*pSqlElement); + } + + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxSqlQuery &t) +{ + QHash lstResultPosByKey; + QVector> lstResultValues; + qint32 i32Temp = 0; + + stream >> t.m_sQuery; + stream >> t.m_lstValue; + stream >> t.m_iSqlElementIndex; + stream >> t.m_iParenthesisCount; + stream >> t.m_bDistinct; + stream >> lstResultPosByKey; + stream >> lstResultValues; + stream >> t.m_vResponse; + stream >> t.m_sType; + stream >> t.m_lstJoinQueryUser; + stream >> t.m_lstJoinQueryToResolve; + + t.m_pSqlResult.reset(); + if ((lstResultPosByKey.count() > 0) || (lstResultValues.count() > 0)) + { + t.m_pSqlResult = std::shared_ptr(new qx::QxSqlQuery::QxSqlResult()); + t.m_pSqlResult->positionByKey = lstResultPosByKey; + t.m_pSqlResult->values = lstResultValues; + } + + t.m_pSqlElementTemp.reset(); + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + stream >> i32Temp; + eTypeSqlElement = static_cast(i32Temp); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + t.m_pSqlElementTemp = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(t.m_pSqlElementTemp); + if (t.m_pSqlElementTemp) + { + stream >> (*t.m_pSqlElementTemp); + } + } + + t.m_lstSqlElement.clear(); + qint64 lSqlElementCount = 0; + stream >> lSqlElementCount; + t.m_lstSqlElement.reserve(static_cast(lSqlElementCount)); + for (long l = 0; l < static_cast(lSqlElementCount); l++) + { + qx::dao::detail::IxSqlElement_ptr pSqlElement; + eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + stream >> i32Temp; + eTypeSqlElement = static_cast(i32Temp); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + pSqlElement = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(pSqlElement); + if (pSqlElement) + { + stream >> (*pSqlElement); + } + } + t.m_lstSqlElement.append(pSqlElement); + } + + return stream; +} diff --git a/src/QxDao/QxSqlRelationLinked.cpp b/src/QxDao/QxSqlRelationLinked.cpp new file mode 100644 index 0000000..91aec20 --- /dev/null +++ b/src/QxDao/QxSqlRelationLinked.cpp @@ -0,0 +1,864 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN QxSqlRelationLinked::QxSqlRelationLinkedImpl + { + + enum e_hierarchy_action + { + e_hierarchy_select, + e_hierarchy_from, + e_hierarchy_join, + e_hierarchy_where_soft_delete + }; + + /* + - qx::dao::sql_join::join_type eJoinType : LEFT OUTER JOIN / INNER JOIN / etc... + - IxSqlRelation * pRelation : relation instance + - QPair, long> lstColumns : list of columns ordered by index + - QString customAlias : custom SQL alias provided by user using syntax + - bool isNullColumn : NULL column (using {NULL} syntax) means : fetch relationships only in LEFT OUTER/INNER JOIN and WHERE clauses (so no columns in SELECT part) + */ + typedef std::tuple, long>, QString, bool> type_relation; + + typedef std::shared_ptr type_ptr; + typedef qx::QxCollection type_lst_relation; + typedef QHash type_lst_relation_linked; + + type_lst_relation m_relationX; //!< List of relationships for current level + type_lst_relation_linked m_relationLinkedX; //!< List of child to build the hierarchy + IxSqlRelationX *m_allRelationX; //!< List of all relationships per level + IxSqlRelationX_ptr m_allRelationXOrdered; //!< List of all relationships per level (order defined by user, used only when necessary, for example with custom join sub-queries) + bool m_bRoot; //!< Root of the hierarchy + QSet m_lstRootColumns; //!< Root columns to fetch (using syntax { col_1, col_2, etc... } ), if empty then fetch all root columns + long m_lRootColumnsOffset; //!< Root columns offset to resolve SQL query output + bool m_bRootColumnsModeRemove; //!< Special syntax to remove root columns instead of adding root columns : -{ column1, column2, etc... } + QString m_sRootCustomAlias; //!< Root custom alias using syntax + + static QMutex m_mutex; //!< Mutex => qx::QxSqlRelationLinked is thread-safe + static QHash, type_ptr> m_relationLinkedSaved; //!< Keep relations linked in memory for optimization (to avoid too many parsing) + + QxSqlRelationLinkedImpl(bool bRoot) : m_allRelationX(NULL), m_bRoot(bRoot), m_lRootColumnsOffset(0), m_bRootColumnsModeRemove(false) { ; } + ~QxSqlRelationLinkedImpl() { ; } + + qx_bool buildHierarchy(IxSqlRelationX *pRelationX, const QStringList &sRelationX, qx::dao::detail::IxDao_Helper *pDaoHelper); + qx_bool insertRelationToHierarchy(const QStringList &sRelationX, const QString &sKey, qx::dao::sql_join::join_type eJoinType, qx::dao::detail::IxDao_Helper *pDaoHelper); + QStringList removeColumns(const QStringList &columnsToRemove, IxSqlRelation *pRelation) const; + + bool checkRootColumns(const QString &s) const { return (m_lstRootColumns.isEmpty() || (m_bRootColumnsModeRemove ? (!m_lstRootColumns.contains(s)) : m_lstRootColumns.contains(s))); } + + void hierarchyAction(QxSqlRelationParams ¶ms, e_hierarchy_action action) + { + if (m_bRoot) + { + params.setIndex(0); + params.setIndexOwner(0); + params.setCustomAlias(m_sRootCustomAlias); + params.setCustomAliasOwner(m_sRootCustomAlias); + } + IxSqlRelationX *pAllRelationX = (m_allRelationXOrdered ? m_allRelationXOrdered.get() : m_allRelationX); + if (!pAllRelationX) + { + qAssert(false); + return; + } + for (auto itr = pAllRelationX->begin(); itr != pAllRelationX->end(); ++itr) + { + IxSqlRelation *p = itr->second; + if (!p) + { + continue; + } + params.setIndex(params.index() + 1); + params.setRelationX(&m_relationLinkedX); + params.setJoinType(qx::dao::sql_join::no_join); + + if (!m_relationX.exist(p->getKey())) + { + if (m_bRoot && checkRootColumns(p->getKey())) + { + switch (action) + { + case e_hierarchy_select: + p->lazySelect(params); + break; + case e_hierarchy_from: + p->lazyFrom(params); + break; + case e_hierarchy_join: + p->lazyJoin(params); + break; + case e_hierarchy_where_soft_delete: + p->lazyWhereSoftDelete(params); + break; + default: + qAssert(false); + break; + } + } + continue; + } + + QxSqlRelationLinkedImpl::type_relation &temp = const_cast(m_relationX.getByKey(p->getKey())); + params.setJoinType(std::get<0>(temp)); + params.setColumns(&std::get<2>(temp)); + params.setCustomAlias(std::get<3>(temp)); + + switch (action) + { + case e_hierarchy_select: + if (!std::get<4>(temp)) + { + p->eagerSelect(params); + } + break; + case e_hierarchy_from: + p->eagerFrom(params); + break; + case e_hierarchy_join: + p->eagerJoin(params); + break; + case e_hierarchy_where_soft_delete: + p->eagerWhereSoftDelete(params); + break; + default: + qAssert(false); + break; + } + + QxSqlRelationLinked_ptr pRelationLinked = m_relationLinkedX.value(p->getKey()); + if (!pRelationLinked) + { + continue; + } + long lOldIndexOwner = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(std::get<3>(temp)); + + switch (action) + { + case e_hierarchy_select: + pRelationLinked->hierarchySelect(params); + break; + case e_hierarchy_from: + pRelationLinked->hierarchyFrom(params); + break; + case e_hierarchy_join: + pRelationLinked->hierarchyJoin(params); + break; + case e_hierarchy_where_soft_delete: + pRelationLinked->hierarchyWhereSoftDelete(params); + break; + default: + qAssert(false); + break; + } + + params.setIndexOwner(lOldIndexOwner); + params.setCustomAliasOwner(sOldCustomAliasOwner); + } + } + + static std::shared_ptr getRelationLinkedSaved(const QPair &key) + { + QMutexLocker locker(&m_mutex); + return m_relationLinkedSaved.value(key); + } + static void insertRelationLinkedSaved(const QPair &key, std::shared_ptr ptr) + { + QMutexLocker locker(&m_mutex); + m_relationLinkedSaved.insert(key, ptr); + } + }; + + QMutex QxSqlRelationLinked::QxSqlRelationLinkedImpl::m_mutex; + QHash, std::shared_ptr> QxSqlRelationLinked::QxSqlRelationLinkedImpl::m_relationLinkedSaved; + + QxSqlRelationLinked::QxSqlRelationLinked() : m_pImpl(new QxSqlRelationLinkedImpl(true)) { ; } + + QxSqlRelationLinked::QxSqlRelationLinked(bool bRoot) : m_pImpl(new QxSqlRelationLinkedImpl(bRoot)) { ; } + + QxSqlRelationLinked::~QxSqlRelationLinked() { ; } + + bool QxSqlRelationLinked::isRoot() const { return m_pImpl->m_bRoot; } + + bool QxSqlRelationLinked::checkRootColumns(const QString &s) const { return m_pImpl->checkRootColumns(s); } + + long QxSqlRelationLinked::getRootColumnsCount() const { return m_pImpl->m_lstRootColumns.count(); } + + long QxSqlRelationLinked::getRootColumnsOffset() const { return m_pImpl->m_lRootColumnsOffset; } + + void QxSqlRelationLinked::setRootColumnsOffset(long l) { m_pImpl->m_lRootColumnsOffset = l; } + + QString QxSqlRelationLinked::getRootCustomAlias() const { return m_pImpl->m_sRootCustomAlias; } + + QxSqlRelationLinked::type_lst_relation_linked QxSqlRelationLinked::getRelationLinkedX() const { return m_pImpl->m_relationLinkedX; } + + QxSqlRelationLinked::type_lst_relation QxSqlRelationLinked::getRelationX() const { return m_pImpl->m_relationX; } + + std::shared_ptr QxSqlRelationLinked::getHierarchy(IxClass *pClass, const QStringList &sRelationX, qx_bool &bOk, qx::dao::detail::IxDao_Helper *pDaoHelper /* = NULL */) + { + if (!pClass) + { + qAssert(false); + bOk = qx_bool(false, "class is empty"); + return std::shared_ptr(); + } + QByteArray hash = sRelationX.join("|").toLatin1(); + QPair key(pClass, hash); + bool bHasJoinSubQuery = (pDaoHelper ? (!pDaoHelper->qxQuery().getJoinQueryHash().isEmpty()) : false); + std::shared_ptr ptr = (bHasJoinSubQuery ? std::shared_ptr() : QxSqlRelationLinked::QxSqlRelationLinkedImpl::getRelationLinkedSaved(key)); + std::shared_ptr result = std::make_shared(); + if (ptr) + { + (*result->m_pImpl) = (*ptr->m_pImpl); + return result; + } + + ptr = std::make_shared(); + bOk = ptr->m_pImpl->buildHierarchy(pClass->getSqlRelationX().get(), sRelationX, pDaoHelper); + if (!bOk) + { + return std::shared_ptr(); + } + if (!bHasJoinSubQuery) + { + QxSqlRelationLinked::QxSqlRelationLinkedImpl::insertRelationLinkedSaved(key, ptr); + } + (*result->m_pImpl) = (*ptr->m_pImpl); + return result; + } + + qx_bool QxSqlRelationLinked::QxSqlRelationLinkedImpl::buildHierarchy(IxSqlRelationX *pRelationX, const QStringList &sRelationX, qx::dao::detail::IxDao_Helper *pDaoHelper) + { + if (!pRelationX) + { + qAssert(false); + return qx_bool(false); + } + if (m_bRoot) + { + m_relationLinkedX.clear(); + m_relationX.clear(); + } + m_allRelationX = pRelationX; + + Q_FOREACH (QString sRelation, sRelationX) + { + QString sKey; + sRelation = sRelation.trimmed(); + int iJoin = QString(QX_LEFT_OUTER_JOIN).size(); + qAssert(iJoin == QString(QX_INNER_JOIN).size()); + qx::dao::sql_join::join_type eJoinType = qx::dao::sql_join::no_join; + + if (sRelation.left(iJoin) == QX_LEFT_OUTER_JOIN) + { + eJoinType = qx::dao::sql_join::left_outer_join; + } + else if (sRelation.left(iJoin) == QX_INNER_JOIN) + { + eJoinType = qx::dao::sql_join::inner_join; + } + int iOffset = ((eJoinType == qx::dao::sql_join::no_join) ? 0 : iJoin); + int iPosLeftOuter = sRelation.indexOf(QX_LEFT_OUTER_JOIN, 1); + int iPosInner = sRelation.indexOf(QX_INNER_JOIN, 1); + int iPos = -1; + + if (iPosLeftOuter < 0) + { + iPos = iPosInner; + } + else if (iPosInner < 0) + { + iPos = iPosLeftOuter; + } + else + { + iPos = ((iPosLeftOuter < iPosInner) ? iPosLeftOuter : iPosInner); + } + + if (iPos >= 0) + { + sKey = sRelation.mid(iOffset, (iPos - iOffset)); + } + else + { + sKey = sRelation.mid(iOffset); + } + sRelation.remove(0, (sKey.size() + iOffset)); + sKey = sKey.trimmed(); + sRelation = sRelation.trimmed(); + if (sKey.isEmpty()) + { + continue; + } + QStringList sNewRelationX = (sRelation.isEmpty() ? QStringList() : (QStringList() << sRelation)); + + if (sKey.startsWith("*")) + { + QString suffix = sKey.right(sKey.size() - 1); + QxCollectionIterator itr(*m_allRelationX); + while (itr.next()) + { + qx_bool bResult = insertRelationToHierarchy(sNewRelationX, (itr.key() + suffix), eJoinType, pDaoHelper); + if (!bResult) + { + return bResult; + } + } + } + else + { + qx_bool bResult = insertRelationToHierarchy(sNewRelationX, sKey, eJoinType, pDaoHelper); + if (!bResult) + { + return bResult; + } + } + } + + bool bRelationXOrdered = (pDaoHelper ? (!pDaoHelper->qxQuery().getJoinQueryHash().isEmpty()) : false); + if (bRelationXOrdered && m_allRelationXOrdered) + { + QxCollectionIterator itr(*m_allRelationX); + while (itr.next()) + { + QString sKey = itr.key(); + if (sKey.isEmpty()) + { + qAssert(false); + continue; + } + IxSqlRelation *pRelation = itr.value(); + if (!pRelation) + { + qAssert(false); + continue; + } + if (!m_allRelationXOrdered->exist(sKey)) + { + m_allRelationXOrdered->insert(sKey, pRelation); + } + } + } + + if (m_allRelationXOrdered) + { + qAssert(m_allRelationXOrdered->count() == m_allRelationX->count()); + } + return qx_bool(true); + } + + qx_bool QxSqlRelationLinked::QxSqlRelationLinkedImpl::insertRelationToHierarchy(const QStringList &sRelationX, const QString &sKey, qx::dao::sql_join::join_type eJoinType, qx::dao::detail::IxDao_Helper *pDaoHelper) + { + bool bModeRemoveColumns = false; + QStringList columns; + QString sKeyTemp = sKey; + if (sKey.contains("{") && sKey.contains("}")) + { + int iPos1 = sKey.indexOf("{"); + int iPos2 = sKey.indexOf("}"); + if (iPos1 >= iPos2) + { + return qx_bool(false, QString("invalid relation : character '}' before than character '{' (") + sKey + ")"); + } + if (iPos1 > 0) + { + bModeRemoveColumns = (sKey.at(iPos1 - 1) == QChar('-')); + } // syntax to remove columns instead of adding columns : -{ column1, column2, etc... } + if (iPos1 > 1) + { + bModeRemoveColumns = (bModeRemoveColumns || ((sKey.at(iPos1 - 2) == QChar('-')) && (sKey.at(iPos1 - 1) == QChar(' ')))); + } // syntax to remove columns instead of adding columns : - { column1, column2, etc... } + sKeyTemp = sKey.left(iPos1); + sKeyTemp = sKeyTemp.trimmed(); + if (sKeyTemp.endsWith("-")) + { + sKeyTemp = sKeyTemp.left(sKeyTemp.length() - 1).trimmed(); + } + QString sColumns = sKey.mid((iPos1 + 1), (iPos2 - iPos1 - 1)); + columns = sColumns.split(","); + for (long l = 0; l < columns.count(); l++) + { + columns[l] = columns.at(l).trimmed(); + } + if ((columns.count() == 1) && ((columns.at(0) == "*") || (columns.at(0) == ""))) + { + columns = QStringList(); + } + } + + QString customAlias, customAliasSuffix, customAliasPrefix; + if (sKeyTemp.contains("<") && sKeyTemp.contains(">")) + { + int iPos1 = sKeyTemp.indexOf("<"); + int iPos2 = sKeyTemp.indexOf(">"); + if (iPos1 >= iPos2) + { + return qx_bool(false, QString("invalid custom alias : character '>' before than character '<' (") + sKeyTemp + ")"); + } + customAlias = sKeyTemp.mid((iPos1 + 1), (iPos2 - iPos1 - 1)).trimmed(); + if (customAlias.startsWith("...")) + { + customAliasSuffix = customAlias.right(customAlias.size() - 3); + customAlias = ""; + } + if (customAlias.endsWith("...")) + { + customAliasPrefix = customAlias.left(customAlias.size() - 3); + customAlias = ""; + } + if (customAlias.contains(" ") || customAliasSuffix.contains(" ") || customAliasPrefix.contains(" ")) + { + return qx_bool(false, QString("invalid custom alias : custom alias cannot contain a space (") + sKeyTemp + ")"); + } + if (customAlias.contains(".") || customAliasSuffix.contains(".") || customAliasPrefix.contains(".")) + { + return qx_bool(false, QString("invalid custom alias : custom alias cannot contain a dot (") + sKeyTemp + ")"); + } + sKeyTemp = sKeyTemp.left(iPos1); + sKeyTemp = sKeyTemp.trimmed(); + } + + if (m_bRoot && sKeyTemp.isEmpty() && (columns.count() > 0)) +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + { + m_lstRootColumns = QSet(columns.begin(), columns.end()); + m_bRootColumnsModeRemove = bModeRemoveColumns; + m_sRootCustomAlias = customAlias; + return qx_bool(true); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + { + m_lstRootColumns = columns.toSet(); + m_bRootColumnsModeRemove = bModeRemoveColumns; + m_sRootCustomAlias = customAlias; + return qx_bool(true); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + else if (m_bRoot && sKeyTemp.isEmpty() && (columns.count() == 0)) + { + m_sRootCustomAlias = customAlias; + return qx_bool(true); + } + + if (!m_allRelationX || !m_allRelationX->exist(sKeyTemp)) + { + qAssert(false); + return qx_bool(false, QString("invalid relation key : '") + sKeyTemp + "' (" + sKey + ")"); + } + IxSqlRelation *pRelation = m_allRelationX->getByKey(sKeyTemp); + if (!pRelation) + { + qAssert(false); + return qx_bool(false, QString("invalid relation pointer : 'NULL pointer'")); + } + if (bModeRemoveColumns && (columns.count() > 0)) + { + columns = removeColumns(columns, pRelation); + } + + bool isNullColumn = ((columns.count() == 1) && (columns.at(0).toUpper() == QString("NULL"))); + if (!isNullColumn) + { + QString sDataIdKey = (pRelation->getDataId() ? pRelation->getDataId()->getKey() : QString()); + Q_FOREACH (QString sColumn, columns) + { + if ((!pRelation->getDataByKey(sColumn)) && (sDataIdKey != sColumn)) + { + return qx_bool(false, QString("invalid relation column : '" + sKeyTemp + "." + sColumn + "' (" + sKey + ")")); + } + } + } + + bool bRelationXOrdered = (pDaoHelper ? (!pDaoHelper->qxQuery().getJoinQueryHash().isEmpty()) : false); + if (bRelationXOrdered && !m_allRelationXOrdered) + { + m_allRelationXOrdered = std::make_shared(); + } + if (bRelationXOrdered && !m_allRelationXOrdered->exist(sKeyTemp)) + { + m_allRelationXOrdered->insert(sKeyTemp, pRelation); + } + + if (!customAliasSuffix.isEmpty() && pRelation->getClass()) + { + customAlias = (pRelation->getClass()->getKey() + customAliasSuffix); + } + if (!customAliasPrefix.isEmpty() && pRelation->getClass()) + { + customAlias = (customAliasPrefix + pRelation->getClass()->getKey()); + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + if (!m_relationX.exist(sKeyTemp)) + { + m_relationX.insert(sKeyTemp, QxSqlRelationLinkedImpl::type_relation(eJoinType, pRelation, qMakePair(QSet(columns.begin(), columns.end()), static_cast(0)), customAlias, isNullColumn)); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + if (!m_relationX.exist(sKeyTemp)) + { + m_relationX.insert(sKeyTemp, QxSqlRelationLinkedImpl::type_relation(eJoinType, pRelation, qMakePair(columns.toSet(), static_cast(0)), customAlias, isNullColumn)); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + if (sRelationX.count() <= 0) + { + return qx_bool(true); + } + + QxSqlRelationLinked_ptr pRelationLinked = m_relationLinkedX.value(sKeyTemp); + if (!pRelationLinked) + { + pRelationLinked = QxSqlRelationLinked_ptr(new QxSqlRelationLinked(false)); + m_relationLinkedX.insert(sKeyTemp, pRelationLinked); + } + + return pRelationLinked->m_pImpl->buildHierarchy(pRelation->getLstRelation(), sRelationX, pDaoHelper); + } + + QStringList QxSqlRelationLinked::QxSqlRelationLinkedImpl::removeColumns(const QStringList &columnsToRemove, IxSqlRelation *pRelation) const + { + if (!pRelation) + { + return QStringList(); + } + IxDataMember *pCurrData = NULL; + IxSqlRelation *pCurrRelation = NULL; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QSet columnsToRemoveSet(columnsToRemove.begin(), columnsToRemove.end()); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QSet columnsToRemoveSet = columnsToRemove.toSet(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList columns; + + long lCurrIndex = 0; + while ((pCurrData = pRelation->nextData(lCurrIndex))) + { + if (!columnsToRemoveSet.contains(pCurrData->getKey())) + { + columns.append(pCurrData->getKey()); + } + } + + lCurrIndex = 0; + while ((pCurrRelation = pRelation->nextRelation(lCurrIndex))) + { + if (!columnsToRemoveSet.contains(pCurrRelation->getKey())) + { + columns.append(pCurrRelation->getKey()); + } + } + + return columns; + } + + void QxSqlRelationLinked::hierarchySelect(QxSqlRelationParams ¶ms) { m_pImpl->hierarchyAction(params, QxSqlRelationLinkedImpl::e_hierarchy_select); } + + void QxSqlRelationLinked::hierarchyFrom(QxSqlRelationParams ¶ms) { m_pImpl->hierarchyAction(params, QxSqlRelationLinkedImpl::e_hierarchy_from); } + + void QxSqlRelationLinked::hierarchyJoin(QxSqlRelationParams ¶ms) { m_pImpl->hierarchyAction(params, QxSqlRelationLinkedImpl::e_hierarchy_join); } + + void QxSqlRelationLinked::hierarchyWhereSoftDelete(QxSqlRelationParams ¶ms) { m_pImpl->hierarchyAction(params, QxSqlRelationLinkedImpl::e_hierarchy_where_soft_delete); } + + void QxSqlRelationLinked::hierarchyResolveOutput(QxSqlRelationParams ¶ms) + { + if (m_pImpl->m_bRoot) + { + params.setIndex(0); + params.setIndexOwner(0); + params.setCustomAlias(m_pImpl->m_sRootCustomAlias); + params.setCustomAliasOwner(m_pImpl->m_sRootCustomAlias); + } + IxSqlRelationX *pAllRelationX = (m_pImpl->m_allRelationXOrdered ? m_pImpl->m_allRelationXOrdered.get() : m_pImpl->m_allRelationX); + if (!pAllRelationX) + { + qAssert(false); + return; + } + QVariant vId, vIdRelation; + bool bByPass(false), bComplex(params.builder().getCartesianProduct()); + for (auto itr = pAllRelationX->begin(); itr != pAllRelationX->end(); ++itr) + { + IxSqlRelation *p = itr->second; + if (!p) + { + continue; + } + if (!isValidDaoHelper(params)) + { + return; + } + params.setIndex(params.index() + 1); + params.setRelationX(&m_pImpl->m_relationLinkedX); + params.setJoinType(qx::dao::sql_join::no_join); + bool bEager = m_pImpl->m_relationX.exist(p->getKey()); + bool bCheckRootColumn = (m_pImpl->m_bRoot && checkRootColumns(p->getKey())); + bool bIsNullColumn = false; + if (bEager) + { + QxSqlRelationLinkedImpl::type_relation &temp = const_cast(m_pImpl->m_relationX.getByKey(p->getKey())); + params.setJoinType(std::get<0>(temp)); + params.setColumns(&std::get<2>(temp)); + params.setCustomAlias(std::get<3>(temp)); + bIsNullColumn = std::get<4>(temp); + } + if (bComplex) + { + vIdRelation = ((bCheckRootColumn || (bEager && (!bIsNullColumn))) ? p->getIdFromQuery(bEager, params, -1, -1) : QVariant()); + } + bool bValidId = (bComplex && qx::trait::is_valid_primary_key(vIdRelation)); + void *pFetched = (bValidId ? params.builder().existIdX(params.index(), params.id(), vIdRelation) : NULL); + bByPass = (bValidId && (pFetched != NULL)); + if (bByPass) + { + p->updateOffset(bEager, params); + } + else + { + if (bEager) + { + if (!bIsNullColumn) + { + pFetched = p->eagerFetch_ResolveOutput(params); + } + } + else if (bCheckRootColumn) + { + p->lazyFetch_ResolveOutput(params); + } + if (bValidId && pFetched) + { + params.builder().insertIdX(params.index(), params.id(), vIdRelation, pFetched); + } + if (!isValidDaoHelper(params)) + { + return; + } + } + if (bEager) + { + QxSqlRelationLinkedImpl::type_relation &temp = const_cast(m_pImpl->m_relationX.getByKey(p->getKey())); + QxSqlRelationLinked_ptr pRelationLinked = m_pImpl->m_relationLinkedX.value(p->getKey()); + if (!pRelationLinked) + { + continue; + } + if (!pFetched) + { + params.setRelationX(NULL); + params.setIndex(params.index() + pRelationLinked->getAllRelationCount()); + pRelationLinked->updateOffset(params); + continue; + } + void *pOldOwner = params.owner(); + params.setOwner(pFetched); + long lOldIndexOwner = params.indexOwner(); + params.setIndexOwner(params.index()); + QString sOldCustomAliasOwner = params.getCustomAliasOwner(); + params.setCustomAliasOwner(std::get<3>(temp)); + QVariant vOldId = params.id(); + params.setId(QVariant(vOldId.toString() + "|" + vIdRelation.toString())); + pRelationLinked->hierarchyResolveOutput(params); + params.setIndexOwner(lOldIndexOwner); + params.setCustomAliasOwner(sOldCustomAliasOwner); + params.setOwner(pOldOwner); + params.setId(vOldId); + } + } + } + + QSqlError QxSqlRelationLinked::hierarchyOnBeforeSave(QxSqlRelationParams ¶ms) + { + for (auto itr = m_pImpl->m_relationX.begin(); itr != m_pImpl->m_relationX.end(); ++itr) + { + const QxSqlRelationLinkedImpl::type_relation &item = itr->second; + if (!std::get<1>(item)) + { + continue; + } + QSqlError err = std::get<1>(item)->onBeforeSave(params); + if (err.isValid()) + { + return err; + } + } + return QSqlError(); + } + + QSqlError QxSqlRelationLinked::hierarchyOnAfterSave(QxSqlRelationParams ¶ms) + { + for (auto itr = m_pImpl->m_relationX.begin(); itr != m_pImpl->m_relationX.end(); ++itr) + { + const QxSqlRelationLinkedImpl::type_relation &item = itr->second; + if (!std::get<1>(item)) + { + continue; + } + QSqlError err = std::get<1>(item)->onAfterSave(params); + if (err.isValid()) + { + return err; + } + } + return QSqlError(); + } + + bool QxSqlRelationLinked::getCartesianProduct() const + { + for (auto itr = m_pImpl->m_relationX.begin(); itr != m_pImpl->m_relationX.end(); ++itr) + { + const QxSqlRelationLinkedImpl::type_relation &item = itr->second; + if (!std::get<1>(item)) + { + continue; + } + if (std::get<1>(item)->getCartesianProduct()) + { + return true; + } + } + + Q_FOREACH (QxSqlRelationLinked_ptr pRelationLinked, m_pImpl->m_relationLinkedX) + { + if (pRelationLinked && pRelationLinked->getCartesianProduct()) + { + return true; + } + } + return false; + } + + long QxSqlRelationLinked::getAllRelationCount() const + { + long lCount = 0; + if (!m_pImpl->m_allRelationX) + { + return 0; + } + Q_FOREACH (QxSqlRelationLinked_ptr pRelationLinked, m_pImpl->m_relationLinkedX) + { + lCount += pRelationLinked->getAllRelationCount(); + } + return (lCount + m_pImpl->m_allRelationX->count()); + } + + long QxSqlRelationLinked::getRelationCount() const + { + long lCount = 0; + Q_FOREACH (QxSqlRelationLinked_ptr pRelationLinked, m_pImpl->m_relationLinkedX) + { + lCount += pRelationLinked->getRelationCount(); + } + return (lCount + m_pImpl->m_relationX.count()); + } + + void QxSqlRelationLinked::updateOffset(QxSqlRelationParams ¶ms) + { + IxSqlRelationX *pAllRelationX = (m_pImpl->m_allRelationXOrdered ? m_pImpl->m_allRelationXOrdered.get() : m_pImpl->m_allRelationX); + if (!pAllRelationX) + { + qAssert(false); + return; + } + for (auto itr = pAllRelationX->begin(); itr != pAllRelationX->end(); ++itr) + { + IxSqlRelation *p = itr->second; + if (!p) + { + continue; + } + params.setRelationX(&m_pImpl->m_relationLinkedX); + bool bEager = m_pImpl->m_relationX.exist(p->getKey()); + bool bIsNullColumn = false; + if (bEager) + { + QxSqlRelationLinkedImpl::type_relation &temp = const_cast(m_pImpl->m_relationX.getByKey(p->getKey())); + params.setColumns(&std::get<2>(temp)); + params.setCustomAlias(std::get<3>(temp)); + bIsNullColumn = std::get<4>(temp); + } + else + { + params.setColumns(NULL); + params.setCustomAlias(""); + } + if (bEager) + { + if (!bIsNullColumn) + { + p->updateOffset(true, params); + } + } + else if (m_pImpl->m_bRoot) + { + p->updateOffset(false, params); + } + QxSqlRelationLinked_ptr pRelationLinked = m_pImpl->m_relationLinkedX.value(p->getKey()); + if (!pRelationLinked) + { + continue; + } + pRelationLinked->updateOffset(params); + } + } + + bool QxSqlRelationLinked::existRelation(const QString &sKey) const + { + return m_pImpl->m_relationX.exist(sKey); + } + + bool QxSqlRelationLinked::isValidDaoHelper(QxSqlRelationParams ¶ms) const + { + if (!params.builder().getDaoHelper()) + { + return true; + } + return params.builder().getDaoHelper()->isValid(); + } + +} // namespace qx diff --git a/src/QxDao/QxSqlRelationParams.cpp b/src/QxDao/QxSqlRelationParams.cpp new file mode 100644 index 0000000..9ef5f34 --- /dev/null +++ b/src/QxDao/QxSqlRelationParams.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include + +namespace qx +{ + + QxSqlRelationParams::QxSqlRelationParams() : m_lIndex(0), m_lIndexOwner(0), m_lOffset(0), m_sql(NULL), m_builder(NULL), m_query(NULL), m_database(NULL), m_pOwner(NULL), m_eJoinType(qx::dao::sql_join::no_join), m_pRelationX(NULL), m_eSaveMode(qx::dao::save_mode::e_check_insert_or_update), m_bRecursiveMode(false), m_pColumns(NULL), m_pLstExecBatch(NULL), m_bIsDistinct(false) { ; } + + QxSqlRelationParams::QxSqlRelationParams(long lIndex, long lOffset, QString *sql, IxSqlQueryBuilder *builder, QSqlQuery *query, void *pOwner, const QVariant &vId /* = QVariant() */, qx::QxCollection *pLstExecBatch /* = NULL */) : m_vId(vId), m_lIndex(lIndex), m_lIndexOwner(0), m_lOffset(lOffset), m_sql(sql), m_builder(builder), m_query(query), m_database(NULL), m_pOwner(pOwner), m_eJoinType(qx::dao::sql_join::no_join), m_pRelationX(NULL), m_eSaveMode(qx::dao::save_mode::e_check_insert_or_update), m_bRecursiveMode(false), m_pColumns(NULL), m_pLstExecBatch(pLstExecBatch), m_bIsDistinct(false) + { + qx::dao::detail::IxDao_Helper *pDaoHelper = (builder ? builder->getDaoHelper() : NULL); + m_bIsDistinct = (pDaoHelper ? pDaoHelper->isDistinct() : false); + } + + QxSqlRelationParams::~QxSqlRelationParams() { ; } + + void QxSqlRelationParams::setBuilder(IxSqlQueryBuilder *builder) + { + m_builder = builder; + m_bIsDistinct = ((builder && builder->getDaoHelper()) ? builder->getDaoHelper()->isDistinct() : false); + } + +} // namespace qx diff --git a/src/QxDao/QxTimeNeutral.cpp b/src/QxDao/QxTimeNeutral.cpp new file mode 100644 index 0000000..ad6477c --- /dev/null +++ b/src/QxDao/QxTimeNeutral.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const qx::QxTimeNeutral &t) +{ + stream << t.m_time; + stream << t.m_neutral; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxTimeNeutral &t) +{ + stream >> t.m_time; + stream >> t.m_neutral; + return stream; +} diff --git a/src/QxDataMember/IxDataMember.cpp b/src/QxDataMember/IxDataMember.cpp new file mode 100644 index 0000000..294c2fa --- /dev/null +++ b/src/QxDataMember/IxDataMember.cpp @@ -0,0 +1,963 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +#include + +#define QX_CONSTRUCT_IX_DATA_MEMBER() \ + m_iPrecision(6), m_iMinLength(-1), m_iMaxLength(-1), m_bRequired(false), \ + m_bReadOnly(false), m_bAutoIncrement(false), m_bNotNull(false), \ + m_bIsPrimaryKey(false), m_bAccessDataPointer(false), m_bIndex(false), \ + m_bUnique(false), m_pName(NULL), m_pParent(NULL), m_pImpl(NULL) + +namespace qx +{ + + struct Q_DECL_HIDDEN IxDataMember::IxDataMemberImpl + { + + typedef QMap> type_fk_part_of_pk; + typedef std::unique_ptr type_fk_part_of_pk_ptr; //!< Type used by primary key to manage the case where a foreign key (relationship) is also a part of primary key (which can contain several columns) + typedef QMap> type_part_of_pk; + typedef std::unique_ptr type_part_of_pk_ptr; //!< Type used by relationship to manage the case where a foreign key (relationship) is also a part of primary key (which can contain several columns) + + QString m_sKey; //!< Data key + QString m_sName; //!< Data name <=> database record name (if empty => data key) + QString m_sNameParent; //!< Data parent name <=> database table name + QString m_sDescription; //!< Data description + QString m_sFormat; //!< Data format ('%04d' for example) + QString m_sSqlType; //!< Data sql type + QString m_sSqlAlias; //!< Data sql alias + long m_lVersion; //!< Data version creation + bool m_bSerialize; //!< Data must be serialized + bool m_bDao; //!< Data is associated with a data source + QVariant m_vDefaultValue; //!< Data default value under QVariant format + QVariant m_vMinValue; //!< Data minimum value under QVariant format + QVariant m_vMaxValue; //!< Data maximum value under QVariant format + int m_iPrecision; //!< Data precision for numerics values (double, float, etc...) + int m_iMinLength; //!< Data minimum length (-1 <=> no min length) + int m_iMaxLength; //!< Data maximum length (-1 <=> no max length) + bool m_bRequired; //!< Data is required or optional + bool m_bReadOnly; //!< Data is read-only + bool m_bAutoIncrement; //!< Data value is auto-generated (auto-increment) + bool m_bNotNull; //!< Data can be null or not + bool m_bIsPrimaryKey; //!< Data is a primary key + bool m_bAccessDataPointer; //!< Can access to the data-member pointer + bool m_bIndex; //!< Data is an index to optimize SQL queries + bool m_bUnique; //!< Data is unique : 2 rows cannot have the same value for this column + + QByteArray m_byteName; //!< Optimization to retrieve name under "const char *" format + const char *m_pName; //!< Optimization to retrieve name under "const char *" format + QStringList m_lstNames; //!< Particular case of "boost::tuple<>" data member (multi-column primary key, composite key) + + std::unique_ptr m_pSqlRelation; //!< Sql relation to build/resolve sql query + IxDataMemberX *m_pParent; //!< 'IxDataMemberX' parent + IxDataMember *m_pImpl; //!< If not NULL then this data member is owned by a private implementation idiom instance + + type_fk_part_of_pk_ptr m_pListRelationPartOfPrimaryKey; //!< Used by primary key to manage the case where a foreign key (relationship) is also a part of primary key (which can contain several columns) + type_part_of_pk_ptr m_pListPartOfPrimaryKey; //!< Used by relationship to manage the case where a foreign key (relationship) is also a part of primary key (which can contain several columns) + + IxDataMember::type_fct_sql_callback m_fctCustomGetSqlName; //!< Custom callback function called building SQL queries (GetSqlName method) + IxDataMember::type_fct_sql_callback m_fctCustomGetSqlTablePointNameAsAlias; //!< Custom callback function called building SQL queries (GetSqlTablePointNameAsAlias method) + IxDataMember::type_fct_sql_callback m_fctCustomGetSqlNameEqualToPlaceHolder; //!< Custom callback function called building SQL queries (GetSqlNameEqualToPlaceHolder method) + IxDataMember::type_fct_sql_callback m_fctCustomGetSqlAliasEqualToPlaceHolder; //!< Custom callback function called building SQL queries (GetSqlAliasEqualToPlaceHolder method) + IxDataMember::type_fct_sql_callback m_fctCustomGetSqlAlias; //!< Custom callback function called building SQL queries (GetSqlAlias method) + + IxDataMemberImpl(const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl) : m_sKey(sKey), m_lVersion(lVersion), m_bSerialize(bSerialize), m_bDao(bDao), QX_CONSTRUCT_IX_DATA_MEMBER() + { + qAssert(!m_sKey.isEmpty()); + m_pImpl = pImpl; + updateNamePtr(); + } + ~IxDataMemberImpl() { ; } + + void updateNamePtr() + { + QString sNamePtr = (m_sName.isEmpty() ? m_sKey : m_sName); + sNamePtr.replace("|", "-"); // valid xml tag + m_byteName = sNamePtr.toLatin1(); + m_pName = m_byteName.constData(); + m_lstNames = (m_sName.isEmpty() ? m_sKey.split("|") : m_sName.split("|")); + } + }; + + QMutex IxDataMember::m_mutex; + + IxDataMember::IxDataMember(const QString &sKey, long lVersion, bool bSerialize, bool bDao, IxDataMember *pImpl) : qx::QxPropertyBag(), m_pImpl(new IxDataMemberImpl(sKey, lVersion, bSerialize, bDao, pImpl)) { ; } + + IxDataMember::~IxDataMember() { ; } + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + template + void IxDataMember::serialize(Archive &ar, const unsigned int version) + { + Q_UNUSED(version); + ar &boost::serialization::make_nvp("key", m_pImpl->m_sKey); + ar &boost::serialization::make_nvp("name", m_pImpl->m_sName); + ar &boost::serialization::make_nvp("nameParent", m_pImpl->m_sNameParent); + ar &boost::serialization::make_nvp("desc", m_pImpl->m_sDescription); + ar &boost::serialization::make_nvp("format", m_pImpl->m_sFormat); + ar &boost::serialization::make_nvp("sqlType", m_pImpl->m_sSqlType); + ar &boost::serialization::make_nvp("sqlAlias", m_pImpl->m_sSqlAlias); + ar &boost::serialization::make_nvp("version", m_pImpl->m_lVersion); + ar &boost::serialization::make_nvp("serialize", m_pImpl->m_bSerialize); + ar &boost::serialization::make_nvp("dao", m_pImpl->m_bDao); + ar &boost::serialization::make_nvp("defaultValue", m_pImpl->m_vDefaultValue); + ar &boost::serialization::make_nvp("minValue", m_pImpl->m_vMinValue); + ar &boost::serialization::make_nvp("maxValue", m_pImpl->m_vMaxValue); + ar &boost::serialization::make_nvp("precision", m_pImpl->m_iPrecision); + ar &boost::serialization::make_nvp("minLength", m_pImpl->m_iMinLength); + ar &boost::serialization::make_nvp("maxLength", m_pImpl->m_iMaxLength); + ar &boost::serialization::make_nvp("required", m_pImpl->m_bRequired); + ar &boost::serialization::make_nvp("readOnly", m_pImpl->m_bReadOnly); + ar &boost::serialization::make_nvp("autoIncrement", m_pImpl->m_bAutoIncrement); + ar &boost::serialization::make_nvp("notNull", m_pImpl->m_bNotNull); + ar &boost::serialization::make_nvp("isPrimaryKey", m_pImpl->m_bIsPrimaryKey); + ar &boost::serialization::make_nvp("isIndex", m_pImpl->m_bIndex); + ar &boost::serialization::make_nvp("isUnique", m_pImpl->m_bUnique); + } +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + QString IxDataMember::getKey() const { return m_pImpl->m_sKey; } + + QString IxDataMember::getName() const { return (m_pImpl->m_sName.isEmpty() ? m_pImpl->m_sKey : m_pImpl->m_sName); } + + int IxDataMember::getNameCount() const { return m_pImpl->m_lstNames.count(); } + + QString IxDataMember::getNameParent() const { return m_pImpl->m_sNameParent; } + + const char *IxDataMember::getNamePtr() const { return m_pImpl->m_pName; } + + QString IxDataMember::getDescription() const { return m_pImpl->m_sDescription; } + + QString IxDataMember::getFormat() const { return m_pImpl->m_sFormat; } + + long IxDataMember::getVersion() const { return m_pImpl->m_lVersion; } + + bool IxDataMember::getSerialize() const { return m_pImpl->m_bSerialize; } + + bool IxDataMember::getDao() const { return m_pImpl->m_bDao; } + + QVariant IxDataMember::getDefaultValue() const { return m_pImpl->m_vDefaultValue; } + + QVariant IxDataMember::getMinValue() const { return m_pImpl->m_vMinValue; } + + QVariant IxDataMember::getMaxValue() const { return m_pImpl->m_vMaxValue; } + + int IxDataMember::getPrecision() const { return m_pImpl->m_iPrecision; } + + int IxDataMember::getMinLength() const { return m_pImpl->m_iMinLength; } + + int IxDataMember::getMaxLength() const { return m_pImpl->m_iMaxLength; } + + bool IxDataMember::getRequired() const { return m_pImpl->m_bRequired; } + + bool IxDataMember::getReadOnly() const { return m_pImpl->m_bReadOnly; } + + bool IxDataMember::getAutoIncrement() const { return m_pImpl->m_bAutoIncrement; } + + bool IxDataMember::getNotNull() const { return m_pImpl->m_bNotNull; } + + bool IxDataMember::getIsPrimaryKey() const { return m_pImpl->m_bIsPrimaryKey; } + + bool IxDataMember::getIsIndex() const { return m_pImpl->m_bIndex; } + + bool IxDataMember::getIsUnique() const { return m_pImpl->m_bUnique; } + + IxDataMemberX *IxDataMember::getParent() const { return m_pImpl->m_pParent; } + + IxSqlRelation *IxDataMember::getSqlRelation() const { return m_pImpl->m_pSqlRelation.get(); } + + bool IxDataMember::hasSqlRelation() const { return (m_pImpl->m_pSqlRelation.get() != NULL); } + + bool IxDataMember::getAccessDataPointer() const { return m_pImpl->m_bAccessDataPointer; } + + QString IxDataMember::getType() const { return ""; } + + QString IxDataMember::getTypeParent() const + { + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + return (pClass ? pClass->getKey() : QString()); + } + + IxDataMember *IxDataMember::getPImpl() const { return m_pImpl->m_pImpl; } + + void IxDataMember::setName(const QString &sName) + { + m_pImpl->m_sName = sName; + m_pImpl->updateNamePtr(); + } + + void IxDataMember::setNameParent(const QString &sName) { m_pImpl->m_sNameParent = sName; } + + void IxDataMember::setDescription(const QString &sDesc) { m_pImpl->m_sDescription = sDesc; } + + void IxDataMember::setFormat(const QString &sFormat) { m_pImpl->m_sFormat = sFormat; } + + void IxDataMember::setSqlType(const QString &sSqlType) { m_pImpl->m_sSqlType = sSqlType; } + + void IxDataMember::setSqlAlias(const QString &sSqlAlias) { m_pImpl->m_sSqlAlias = sSqlAlias; } + + void IxDataMember::setVersion(long lVersion) { m_pImpl->m_lVersion = lVersion; } + + void IxDataMember::setSerialize(bool bSerialize) { m_pImpl->m_bSerialize = bSerialize; } + + void IxDataMember::setDao(bool bDao) { m_pImpl->m_bDao = bDao; } + + void IxDataMember::setDefaultValue(const QVariant &var) { m_pImpl->m_vDefaultValue = var; } + + void IxDataMember::setPrecision(int iPrecision) { m_pImpl->m_iPrecision = iPrecision; } + + void IxDataMember::setRequired(bool bRequired) { m_pImpl->m_bRequired = bRequired; } + + void IxDataMember::setReadOnly(bool bReadOnly) { m_pImpl->m_bReadOnly = bReadOnly; } + + void IxDataMember::setAutoIncrement(bool bAutoIncrement) { m_pImpl->m_bAutoIncrement = bAutoIncrement; } + + void IxDataMember::setIsPrimaryKey(bool bIsPrimaryKey) { m_pImpl->m_bIsPrimaryKey = bIsPrimaryKey; } + + void IxDataMember::setIsIndex(bool bIsIndex) { m_pImpl->m_bIndex = bIsIndex; } + + void IxDataMember::setIsUnique(bool bIsUnique) { m_pImpl->m_bUnique = bIsUnique; } + + void IxDataMember::setParent(IxDataMemberX *pParent) { m_pImpl->m_pParent = pParent; } + + void IxDataMember::setSqlRelation(IxSqlRelation *pSqlRelation) { m_pImpl->m_pSqlRelation.reset(pSqlRelation); } + + void IxDataMember::setAccessDataPointer(bool b) { m_pImpl->m_bAccessDataPointer = b; } + + QVariant IxDataMember::toVariant(const void *pOwner, int iIndexName /* = -1 */, qx::cvt::context::ctx_type ctx /* = qx::cvt::context::e_no_context */) const { return this->toVariant(pOwner, m_pImpl->m_sFormat, iIndexName, ctx); } + + qx_bool IxDataMember::fromVariant(void *pOwner, const QVariant &v, int iIndexName /* = -1 */, qx::cvt::context::ctx_type ctx /* = qx::cvt::context::e_no_context */) { return this->fromVariant(pOwner, v, m_pImpl->m_sFormat, iIndexName, ctx); } + +#ifndef _QX_NO_JSON + + QJsonValue IxDataMember::toJson(const void *pOwner) const { return this->toJson(pOwner, m_pImpl->m_sFormat); } + + qx_bool IxDataMember::fromJson(void *pOwner, const QJsonValue &j) { return this->fromJson(pOwner, j, m_pImpl->m_sFormat); } + +#endif // _QX_NO_JSON + + void IxDataMember::setMinValue(long lMinValue, const QString &sMessage /* = QString() */) + { + m_pImpl->m_vMinValue = (qlonglong)lMinValue; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MinValue(m_pImpl->m_sKey, lMinValue, sMessage); + } + + void IxDataMember::setMinValue(double dMinValue, const QString &sMessage /* = QString() */) + { + m_pImpl->m_vMinValue = dMinValue; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MinDecimal(m_pImpl->m_sKey, dMinValue, sMessage); + } + + void IxDataMember::setMaxValue(long lMaxValue, const QString &sMessage /* = QString() */) + { + m_pImpl->m_vMaxValue = (qlonglong)lMaxValue; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MaxValue(m_pImpl->m_sKey, lMaxValue, sMessage); + } + + void IxDataMember::setMaxValue(double dMaxValue, const QString &sMessage /* = QString() */) + { + m_pImpl->m_vMaxValue = dMaxValue; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MaxDecimal(m_pImpl->m_sKey, dMaxValue, sMessage); + } + + void IxDataMember::setMinLength(int iMinLength, const QString &sMessage /* = QString() */) + { + m_pImpl->m_iMinLength = iMinLength; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MinLength(m_pImpl->m_sKey, (long)m_pImpl->m_iMinLength, sMessage); + } + + void IxDataMember::setMaxLength(int iMaxLength, const QString &sMessage /* = QString() */) + { + m_pImpl->m_iMaxLength = iMaxLength; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + pAllValidator->add_MaxLength(m_pImpl->m_sKey, (long)m_pImpl->m_iMaxLength, sMessage); + } + + void IxDataMember::setNotNull(bool bNotNull, const QString &sMessage /* = QString() */) + { + m_pImpl->m_bNotNull = bNotNull; + IxClass *pClass = (m_pImpl->m_pParent ? m_pImpl->m_pParent->getClass() : NULL); + if (!pClass) + { + return; + } + IxValidatorX *pAllValidator = pClass->getAllValidator(); + if (!pAllValidator) + { + return; + } + if (m_pImpl->m_bNotNull) + { + pAllValidator->add_NotNull(m_pImpl->m_sKey, sMessage); + } + } + + bool IxDataMember::isThereRelationPartOfPrimaryKey(int iIndexNamePK, IxSqlRelation *&pRelation, int &iIndexNameFK) const + { + pRelation = NULL; + iIndexNameFK = -1; + if (!m_pImpl->m_pListRelationPartOfPrimaryKey) + { + return false; + } + if (!m_pImpl->m_pListRelationPartOfPrimaryKey->contains(iIndexNamePK)) + { + return false; + } + QPair pair = m_pImpl->m_pListRelationPartOfPrimaryKey->value(iIndexNamePK); + pRelation = pair.first; + iIndexNameFK = pair.second; + return true; + } + + bool IxDataMember::isPartOfPrimaryKey(int iIndexNameFK, IxDataMember *&pPrimaryKey, int &iIndexNamePK) const + { + pPrimaryKey = NULL; + iIndexNamePK = -1; + if (!m_pImpl->m_pListPartOfPrimaryKey) + { + return false; + } + if (!m_pImpl->m_pListPartOfPrimaryKey->contains(iIndexNameFK)) + { + return false; + } + QPair pair = m_pImpl->m_pListPartOfPrimaryKey->value(iIndexNameFK); + pPrimaryKey = pair.first; + iIndexNamePK = pair.second; + return true; + } + + void IxDataMember::setRelationPartOfPrimaryKey(int iIndexNamePK, IxSqlRelation *pRelation, int iIndexNameFK) + { + if (!m_pImpl->m_pListRelationPartOfPrimaryKey) + { + m_pImpl->m_pListRelationPartOfPrimaryKey.reset(new IxDataMemberImpl::type_fk_part_of_pk()); + } + if (m_pImpl->m_pListRelationPartOfPrimaryKey->contains(iIndexNamePK)) + { + return; + } + QPair pair; + pair.first = pRelation; + pair.second = iIndexNameFK; + m_pImpl->m_pListRelationPartOfPrimaryKey->insert(iIndexNamePK, pair); + } + + void IxDataMember::setPartOfPrimaryKey(int iIndexNameFK, IxDataMember *pPrimaryKey, int iIndexNamePK) + { + if (!m_pImpl->m_pListPartOfPrimaryKey) + { + m_pImpl->m_pListPartOfPrimaryKey.reset(new IxDataMemberImpl::type_part_of_pk()); + } + if (m_pImpl->m_pListPartOfPrimaryKey->contains(iIndexNameFK)) + { + return; + } + QPair pair; + pair.first = pPrimaryKey; + pair.second = iIndexNamePK; + m_pImpl->m_pListPartOfPrimaryKey->insert(iIndexNameFK, pair); + } + + QString IxDataMember::getName(int iIndex, const QString &sOtherName /* = QString() */) const + { + if (!sOtherName.isEmpty()) + { + QStringList lstOtherNames = sOtherName.split("|"); + qAssert(m_pImpl->m_lstNames.count() == lstOtherNames.count()); + return (((iIndex >= 0) && (iIndex < lstOtherNames.count())) ? lstOtherNames.at(iIndex) : QString()); + } + + return (((iIndex >= 0) && (iIndex < m_pImpl->m_lstNames.count())) ? m_pImpl->m_lstNames.at(iIndex) : QString()); + } + + QString IxDataMember::getSqlAlias(const QString &sTable /* = QString() */, bool bClauseWhere /* = false */, int iIndexName /* = 0 */, qx::IxSqlQueryBuilder *pSqlQueryBuilder /* = NULL */) const + { + QString sSqlAlias; + QString sTableAlias = sTable; + sTableAlias.replace(".", "_"); + + do + { + // Standard SQL disallows references to column aliases in a WHERE clause + // cf. + if (bClauseWhere && !sTableAlias.isEmpty()) + { + sSqlAlias = (getSqlTableName(sTableAlias) + "." + getSqlColumnName(getName(iIndexName))); + break; + } + + sSqlAlias = m_pImpl->m_sSqlAlias; + if (!sSqlAlias.isEmpty()) + { + break; + } + if (!sTableAlias.isEmpty()) + { + sSqlAlias = (sTableAlias + "_" + getName(iIndexName) + "_0"); + } + else + { + sSqlAlias = (m_pImpl->m_sNameParent + "_" + getName(iIndexName) + "_0"); + } + + // Special database keywords using '[', ']' or '"' characters + sSqlAlias.replace("[", ""); + sSqlAlias.replace("]", ""); + sSqlAlias.replace("\"", ""); + sSqlAlias.replace(".", "_"); + } while (0); + + if (m_pImpl->m_fctCustomGetSqlAlias) + { + IxDataMemberSqlCallbackParams callbackParams(this, sSqlAlias); + callbackParams.sTable = sTable; + callbackParams.bClauseWhere = bClauseWhere; + callbackParams.iIndexName = iIndexName; + callbackParams.pDaoHelper = (pSqlQueryBuilder ? pSqlQueryBuilder->getDaoHelper() : NULL); + callbackParams.pSqlQueryBuilder = pSqlQueryBuilder; + m_pImpl->m_fctCustomGetSqlAlias(callbackParams); + } + + return sSqlAlias; + } + + QString IxDataMember::getSqlType(int iIndexName /* = -1 */) const + { + if ((iIndexName == -1) || (getNameCount() <= 1)) + { + return m_pImpl->m_sSqlType; + } + QStringList lst = m_pImpl->m_sSqlType.split("|"); + return (((iIndexName >= 0) && (iIndexName < lst.count())) ? lst.at(iIndexName) : QString()); + } + + QString IxDataMember::getSqlTypeAndParams(int iIndexName /* = -1 */) const + { + QString sResult = getSqlType(iIndexName); + sResult += (m_pImpl->m_bNotNull ? " NOT NULL" : ""); + sResult += ((m_pImpl->m_bIsPrimaryKey && (getNameCount() <= 1)) ? " PRIMARY KEY" : ""); + + if (m_pImpl->m_bAutoIncrement) + { + qx::dao::detail::IxSqlGenerator *pSqlGenerator = QxSqlDatabase::getSingleton()->getSqlGenerator(); + if (!pSqlGenerator) + { + qAssert(false); + sResult += " AUTOINCREMENT"; + } + else + { + sResult += " " + pSqlGenerator->getAutoIncrement(); + } + } + + return sResult; + } + + QString IxDataMember::getSqlPlaceHolder(const QString &sAppend /* = QString() */, int iIndexName /* = 0 */, const QString &sSep /* = QString(", ") */, const QString &sOtherName /* = QString() */, bool bCheckFKPartOfPK /* = false */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + + if (iIndexName == -1) + { + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += getSqlPlaceHolder(sAppend, i, sSep, sOtherName) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + return sResult; + } + + // Special database keywords using '[', ']' or '"' characters + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(iIndexName, pRelation, iIndexNameFK)) + { + return ""; + } + QString sSqlPlaceHolder = getName(iIndexName, sOtherName) + sAppend; + sSqlPlaceHolder.replace("[", ""); + sSqlPlaceHolder.replace("]", ""); + sSqlPlaceHolder.replace("\"", ""); + + switch (QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle()) + { + case QxSqlDatabase::ph_style_question_mark: + sResult = "?"; + break; + case QxSqlDatabase::ph_style_2_point_name: + sResult = ":" + sSqlPlaceHolder; + break; + case QxSqlDatabase::ph_style_at_name: + sResult = "@" + sSqlPlaceHolder; + break; + default: + sResult = ":" + sSqlPlaceHolder; + break; + } + + return sResult; + } + + void IxDataMember::setSqlPlaceHolder(QSqlQuery &query, void *pOwner, const QString &sAppend /* = QString() */, const QString &sOtherName /* = QString() */, bool bCheckFKPartOfPK /* = false */, qx::QxCollection *pLstExecBatch /* = NULL */) const + { + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + bool bQuestionMark = (qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle() == qx::QxSqlDatabase::ph_style_question_mark); + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + QString key = (bQuestionMark ? QString() : getSqlPlaceHolder(sAppend, i, "", sOtherName)); + QVariant val = toVariant(pOwner, i, qx::cvt::context::e_database); + if (pLstExecBatch) + { + if (bQuestionMark) + { + key = getName(i, sOtherName); + } + if (!pLstExecBatch->exist(key)) + { + QVariantList empty; + pLstExecBatch->insert(key, empty); + } + QVariantList &values = const_cast(pLstExecBatch->getByKey(key)); + values.append(val); + } + else + { + if (bQuestionMark) + { + query.addBindValue(val); + } + else + { + query.bindValue(key, val); + } + } + } + } + + QString IxDataMember::getSqlAliasEqualToPlaceHolder(const QString &sTable /* = QString() */, bool bClauseWhere /* = false */, const QString &sAppend /* = QString() */, const QString &sSep /* = QString(" AND ") */, bool bCheckFKPartOfPK /* = false */, qx::IxSqlQueryBuilder *pSqlQueryBuilder /* = NULL */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += getSqlAlias(sTable, bClauseWhere, i, pSqlQueryBuilder) + " = " + getSqlPlaceHolder(sAppend, i) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + + if (m_pImpl->m_fctCustomGetSqlAliasEqualToPlaceHolder) + { + IxDataMemberSqlCallbackParams callbackParams(this, sResult); + callbackParams.sTable = sTable; + callbackParams.bClauseWhere = bClauseWhere; + callbackParams.sAppend = sAppend; + callbackParams.sSep = sSep; + callbackParams.bCheckFKPartOfPK = bCheckFKPartOfPK; + callbackParams.pDaoHelper = (pSqlQueryBuilder ? pSqlQueryBuilder->getDaoHelper() : NULL); + callbackParams.pSqlQueryBuilder = pSqlQueryBuilder; + m_pImpl->m_fctCustomGetSqlAliasEqualToPlaceHolder(callbackParams); + } + + return sResult; + } + + QString IxDataMember::getSqlNameEqualToPlaceHolder(const QString &sAppend /* = QString() */, const QString &sSep /* = QString(" AND ") */, bool bCheckFKPartOfPK /* = false */, qx::IxSqlQueryBuilder *pSqlQueryBuilder /* = NULL */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += getSqlColumnName(getName(i)) + " = " + getSqlPlaceHolder(sAppend, i) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + + if (m_pImpl->m_fctCustomGetSqlNameEqualToPlaceHolder) + { + IxDataMemberSqlCallbackParams callbackParams(this, sResult); + callbackParams.sAppend = sAppend; + callbackParams.sSep = sSep; + callbackParams.bCheckFKPartOfPK = bCheckFKPartOfPK; + callbackParams.pDaoHelper = (pSqlQueryBuilder ? pSqlQueryBuilder->getDaoHelper() : NULL); + callbackParams.pSqlQueryBuilder = pSqlQueryBuilder; + m_pImpl->m_fctCustomGetSqlNameEqualToPlaceHolder(callbackParams); + } + + return sResult; + } + + QString IxDataMember::getSqlTablePointNameAsAlias(const QString &sTable, const QString &sSep /* = QString(", ") */, const QString &sSuffixAlias /* = QString() */, bool bCheckFKPartOfPK /* = false */, const QString &sCustomAlias /* = QString() */, qx::IxSqlQueryBuilder *pSqlQueryBuilder /* = NULL */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + QString sTableAlias = (sCustomAlias.isEmpty() ? sTable : sCustomAlias); + sTableAlias.replace(".", "_"); + sTableAlias = getSqlTableName(sTableAlias); + + QString sTableAliasSep = " AS "; + qx::dao::detail::IxSqlGenerator *pSqlGenerator = QxSqlDatabase::getSingleton()->getSqlGenerator(); + if (pSqlGenerator) + { + sTableAliasSep = pSqlGenerator->getTableAliasSep(); + } + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += sTableAlias + "." + getSqlColumnName(getName(i)) + sTableAliasSep + getSqlColumnNameAlias(getSqlAlias((sCustomAlias.isEmpty() ? sTable : sCustomAlias), false, i, pSqlQueryBuilder) + sSuffixAlias) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + + if (m_pImpl->m_fctCustomGetSqlTablePointNameAsAlias) + { + IxDataMemberSqlCallbackParams callbackParams(this, sResult); + callbackParams.sTable = sTable; + callbackParams.sSep = sSep; + callbackParams.sSuffixAlias = sSuffixAlias; + callbackParams.bCheckFKPartOfPK = bCheckFKPartOfPK; + callbackParams.sCustomAlias = sCustomAlias; + callbackParams.pDaoHelper = (pSqlQueryBuilder ? pSqlQueryBuilder->getDaoHelper() : NULL); + callbackParams.pSqlQueryBuilder = pSqlQueryBuilder; + m_pImpl->m_fctCustomGetSqlTablePointNameAsAlias(callbackParams); + } + + return sResult; + } + + QString IxDataMember::getSqlName(const QString &sSep /* = QString(", ") */, const QString &sOtherName /* = QString() */, bool bCheckFKPartOfPK /* = false */, qx::IxSqlQueryBuilder *pSqlQueryBuilder /* = NULL */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += getSqlColumnName(getName(i, sOtherName)) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + + if (m_pImpl->m_fctCustomGetSqlName) + { + IxDataMemberSqlCallbackParams callbackParams(this, sResult); + callbackParams.sSep = sSep; + callbackParams.sOtherName = sOtherName; + callbackParams.bCheckFKPartOfPK = bCheckFKPartOfPK; + callbackParams.pDaoHelper = (pSqlQueryBuilder ? pSqlQueryBuilder->getDaoHelper() : NULL); + callbackParams.pSqlQueryBuilder = pSqlQueryBuilder; + m_pImpl->m_fctCustomGetSqlName(callbackParams); + } + + return sResult; + } + + QString IxDataMember::getSqlNameAndTypeAndParams(const QString &sSep /* = QString(", ") */, const QString &sOtherName /* = QString() */, bool bCheckFKPartOfPK /* = false */) const + { + QString sResult; + int iIndexNameFK = 0; + IxSqlRelation *pRelation = NULL; + + for (int i = 0; i < m_pImpl->m_lstNames.count(); i++) + { + if (bCheckFKPartOfPK && m_pImpl->m_bIsPrimaryKey && isThereRelationPartOfPrimaryKey(i, pRelation, iIndexNameFK)) + { + continue; + } + sResult += getSqlColumnName(getName(i, sOtherName)) + " " + getSqlTypeAndParams(i) + sSep; + } + + if (!sResult.isEmpty()) + { + sResult = sResult.left(sResult.length() - sSep.length()); + } // Remove last separator + return sResult; + } + + void IxDataMember::customGetSqlName(IxDataMember::type_fct_sql_callback fct) { m_pImpl->m_fctCustomGetSqlName = fct; } + + void IxDataMember::customGetSqlTablePointNameAsAlias(IxDataMember::type_fct_sql_callback fct) { m_pImpl->m_fctCustomGetSqlTablePointNameAsAlias = fct; } + + void IxDataMember::customGetSqlNameEqualToPlaceHolder(IxDataMember::type_fct_sql_callback fct) { m_pImpl->m_fctCustomGetSqlNameEqualToPlaceHolder = fct; } + + void IxDataMember::customGetSqlAliasEqualToPlaceHolder(IxDataMember::type_fct_sql_callback fct) { m_pImpl->m_fctCustomGetSqlAliasEqualToPlaceHolder = fct; } + + void IxDataMember::customGetSqlAlias(IxDataMember::type_fct_sql_callback fct) { m_pImpl->m_fctCustomGetSqlAlias = fct; } + + QString IxDataMember::getSqlFromTable(const QString &sTable, const QString &sCustomAlias /* = QString() */) + { + if (sCustomAlias.isEmpty() && !sTable.contains(".")) + { + return getSqlTableName(sTable); + } + QString sTableAlias = (sCustomAlias.isEmpty() ? sTable : sCustomAlias); + sTableAlias.replace(".", "_"); + + QString sTableAliasSep = " AS "; + qx::dao::detail::IxSqlGenerator *pSqlGenerator = QxSqlDatabase::getSingleton()->getSqlGenerator(); + if (pSqlGenerator) + { + sTableAliasSep = pSqlGenerator->getTableAliasSep(); + } + + return (getSqlTableName(sTable) + sTableAliasSep + sTableAlias); + } + + QString IxDataMember::getSqlTableName(const QString &sTable) + { + QStringList lstDelimiter = QxSqlDatabase::getSingleton()->getSqlDelimiterForTableName(); + bool bAddSquareBracketsForTableName = QxSqlDatabase::getSingleton()->getAddSqlSquareBracketsForTableName(); + QString sStart = (bAddSquareBracketsForTableName ? QString("[") : QString()); + QString sEnd = (bAddSquareBracketsForTableName ? QString("]") : QString()); + if (lstDelimiter.count() > 0) + { + sStart = lstDelimiter.at(0); + sEnd = lstDelimiter.at(0); + } + if (lstDelimiter.count() > 1) + { + sEnd = lstDelimiter.at(1); + } + if (sStart.isEmpty() || sEnd.isEmpty() || sTable.contains(sStart) || sTable.contains(sEnd)) + { + return sTable; + } + QString sResult = (sStart + sTable + sEnd); + sResult.replace(".", (sEnd + "." + sStart)); + return sResult; + } + + QString IxDataMember::getSqlColumnName(const QString &sColumn) + { + QStringList lstDelimiter = QxSqlDatabase::getSingleton()->getSqlDelimiterForColumnName(); + bool bAddSquareBracketsForColumnName = QxSqlDatabase::getSingleton()->getAddSqlSquareBracketsForColumnName(); + QString sStart = (bAddSquareBracketsForColumnName ? QString("[") : QString()); + QString sEnd = (bAddSquareBracketsForColumnName ? QString("]") : QString()); + if (lstDelimiter.count() > 0) + { + sStart = lstDelimiter.at(0); + sEnd = lstDelimiter.at(0); + } + if (lstDelimiter.count() > 1) + { + sEnd = lstDelimiter.at(1); + } + if (sStart.isEmpty() || sEnd.isEmpty() || sColumn.contains(sStart) || sColumn.contains(sEnd)) + { + return sColumn; + } + QString sResult = (sStart + sColumn + sEnd); + sResult.replace(".", (sEnd + "." + sStart)); + return sResult; + } + + QString IxDataMember::getSqlTableNameAlias(const QString &sTable) + { + QStringList lstDelimiter = QxSqlDatabase::getSingleton()->getSqlDelimiterForTableNameAlias(); + QString sStart = QString(); + QString sEnd = QString(); + if (lstDelimiter.count() > 0) + { + sStart = lstDelimiter.at(0); + sEnd = lstDelimiter.at(0); + } + if (lstDelimiter.count() > 1) + { + sEnd = lstDelimiter.at(1); + } + if (sStart.isEmpty() || sEnd.isEmpty() || sTable.contains(sStart) || sTable.contains(sEnd)) + { + return sTable; + } + QString sResult = (sStart + sTable + sEnd); + sResult.replace(".", (sEnd + "." + sStart)); + return sResult; + } + + QString IxDataMember::getSqlColumnNameAlias(const QString &sColumn) + { + QStringList lstDelimiter = QxSqlDatabase::getSingleton()->getSqlDelimiterForColumnNameAlias(); + QString sStart = QString(); + QString sEnd = QString(); + if (lstDelimiter.count() > 0) + { + sStart = lstDelimiter.at(0); + sEnd = lstDelimiter.at(0); + } + if (lstDelimiter.count() > 1) + { + sEnd = lstDelimiter.at(1); + } + if (sStart.isEmpty() || sEnd.isEmpty() || sColumn.contains(sStart) || sColumn.contains(sEnd)) + { + return sColumn; + } + QString sResult = (sStart + sColumn + sEnd); + sResult.replace(".", (sEnd + "." + sStart)); + return sResult; + } + + IxDataMemberSqlCallbackParams::IxDataMemberSqlCallbackParams(const IxDataMember *p, QString &sql) : pDataMember(p), sSQL(sql), bClauseWhere(false), bCheckFKPartOfPK(false), iIndexName(0), pDaoHelper(NULL), pSqlQueryBuilder(NULL) { qAssert(pDataMember); } + + IxDataMemberSqlCallbackParams::~IxDataMemberSqlCallbackParams() { ; } + +} // namespace qx + +inline bool operator<(const qx::IxDataMember &i1, const qx::IxDataMember &i2) { return (i1.getKey() < i2.getKey()); } +inline bool operator>(const qx::IxDataMember &i1, const qx::IxDataMember &i2) { return (i1.getKey() > i2.getKey()); } diff --git a/src/QxDataMember/IxDataMemberX.cpp b/src/QxDataMember/IxDataMemberX.cpp new file mode 100644 index 0000000..435b9c2 --- /dev/null +++ b/src/QxDataMember/IxDataMemberX.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN IxDataMemberX::IxDataMemberXImpl + { + + QxCollection m_lstDataMember; //!< Collection of IxDataMember + QxCollection m_lstPImpl; //!< Collection of private implementation idiom instances + IxClass *m_pClass; //!< Class definition + IxDataMember *m_pDataMemberId; //!< Data member id with primary key type + + IxDataMemberXImpl() : m_pClass(NULL), m_pDataMemberId(NULL) { ; } + ~IxDataMemberXImpl() { ; } + + void deleteAllIxDataMember() + { + for (auto itr = m_lstDataMember.begin(); itr != m_lstDataMember.end(); ++itr) + { + delete itr->second; + } + for (auto itr = m_lstPImpl.begin(); itr != m_lstPImpl.end(); ++itr) + { + delete itr->second; + } + } + }; + + IxDataMemberX::IxDataMemberX() : m_pImpl(new IxDataMemberXImpl()) { ; } + + IxDataMemberX::~IxDataMemberX() { m_pImpl->deleteAllIxDataMember(); } + + IxClass *IxDataMemberX::getClass() const { return m_pImpl->m_pClass; } + + void IxDataMemberX::setClass(IxClass *p) { m_pImpl->m_pClass = p; } + + QString IxDataMemberX::getName() const { return (m_pImpl->m_pClass ? m_pImpl->m_pClass->getName() : ""); } + + const char *IxDataMemberX::getNamePtr() const { return (m_pImpl->m_pClass ? m_pImpl->m_pClass->getNamePtr() : NULL); } + + QString IxDataMemberX::getDescription() const { return (m_pImpl->m_pClass ? m_pImpl->m_pClass->getDescription() : ""); } + + long IxDataMemberX::getVersion() const { return (m_pImpl->m_pClass ? m_pImpl->m_pClass->getVersion() : -1); } + + qx::dao::strategy::inheritance IxDataMemberX::getDaoStrategy() const { return (m_pImpl->m_pClass ? m_pImpl->m_pClass->getDaoStrategy() : qx::dao::strategy::concrete_table_inheritance); } + + long IxDataMemberX::count() const { return m_pImpl->m_lstDataMember.count(); } + + long IxDataMemberX::size() const { return this->count(); } + + bool IxDataMemberX::exist(const QString &sKey) const { return m_pImpl->m_lstDataMember.exist(sKey); } + + IxDataMember *IxDataMemberX::get(long l) const { return m_pImpl->m_lstDataMember.getByIndex(l); } + + IxDataMember *IxDataMemberX::get(const QString &s) const { return m_pImpl->m_lstDataMember.getByKey(s); } + + IxDataMember *IxDataMemberX::getId() const { return m_pImpl->m_pDataMemberId; } + + void IxDataMemberX::setId(IxDataMember *p) { m_pImpl->m_pDataMemberId = p; } + + QxCollection &IxDataMemberX::getListDataMemberRef() { return m_pImpl->m_lstDataMember; } + + const QxCollection &IxDataMemberX::getListDataMemberRef() const { return m_pImpl->m_lstDataMember; } + + QxCollection &IxDataMemberX::getListPImplRef() { return m_pImpl->m_lstPImpl; } + + const QxCollection &IxDataMemberX::getListPImplRef() const { return m_pImpl->m_lstPImpl; } + +} // namespace qx diff --git a/src/QxDataMember/QxDataMember_QObject.cpp b/src/QxDataMember/QxDataMember_QObject.cpp new file mode 100644 index 0000000..94d6506 --- /dev/null +++ b/src/QxDataMember/QxDataMember_QObject.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include +#include + +#include + +#define QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(ArchiveInput, ArchiveOutput) \ + namespace qx \ + { \ + void QxDataMember_QObject::toArchive(const void *pOwner, ArchiveOutput &ar) const \ + { \ + QVariant v = m_metaProperty.read(static_cast(pOwner)); \ + ar << boost::serialization::make_nvp(getNamePtr(), v); \ + } \ + void QxDataMember_QObject::fromArchive(void *pOwner, ArchiveInput &ar) \ + { \ + QVariant v; \ + ar >> boost::serialization::make_nvp(getNamePtr(), v); \ + m_metaProperty.write(static_cast(pOwner), v); \ + } \ + } + +namespace qx +{ + + QxDataMember_QObject::QxDataMember_QObject(const QMetaObject *pMetaObject, const QString &sKey) : IxDataMember(sKey, 0, true, true, NULL), m_metaObject(pMetaObject) + { + setAccessDataPointer(false); + if (!m_metaObject) + { + qAssert(false); + return; + } + int index = m_metaObject->indexOfProperty(qPrintable(sKey)); + if (index == -1) + { + qAssert(false); + return; + } + m_metaProperty = m_metaObject->property(index); + setSqlType(QxClassX::getSqlTypeByClassName(m_metaProperty.typeName())); + } + + bool QxDataMember_QObject::isEqual(const void *pOwner1, const void *pOwner2) const + { + if ((pOwner1 == NULL) || (pOwner2 == NULL)) + { + return false; + } + if (pOwner1 == pOwner2) + { + return true; + } + QVariant var1 = m_metaProperty.read(static_cast(pOwner1)); + QVariant var2 = m_metaProperty.read(static_cast(pOwner2)); + return (var1 == var2); + } + + QVariant QxDataMember_QObject::toVariant(const void *pOwner, const QString &sFormat, int iIndexName /* = -1 */, qx::cvt::context::ctx_type ctx /* = qx::cvt::context::e_no_context */) const + { + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return m_metaProperty.read(static_cast(pOwner)); + } + + qx_bool QxDataMember_QObject::fromVariant(void *pOwner, const QVariant &v, const QString &sFormat, int iIndexName /* = -1 */, qx::cvt::context::ctx_type ctx /* = qx::cvt::context::e_no_context */) + { + Q_UNUSED(sFormat); + Q_UNUSED(iIndexName); + Q_UNUSED(ctx); + return m_metaProperty.write(static_cast(pOwner), v); + } + + QString QxDataMember_QObject::getType() const + { + return QString(m_metaProperty.typeName()); + } + +#ifndef _QX_NO_JSON + + QJsonValue QxDataMember_QObject::toJson(const void *pOwner, const QString &sFormat) const + { + Q_UNUSED(sFormat); + QVariant val = m_metaProperty.read(static_cast(pOwner)); + +#ifdef _QX_ENABLE_MONGODB + if (getIsPrimaryKey() && sFormat.startsWith("mongodb")) + { + QString tmp = val.toString(); + if (tmp.startsWith("qx_oid:")) + { + QJsonObject obj; + obj.insert("$oid", QJsonValue(tmp.right(tmp.size() - 7))); + return QJsonValue(obj); + } + } +#endif // _QX_ENABLE_MONGODB + + return QJsonValue::fromVariant(val); + } + + qx_bool QxDataMember_QObject::fromJson(void *pOwner, const QJsonValue &j, const QString &sFormat) + { + Q_UNUSED(sFormat); + QVariant val = j.toVariant(); + +#ifdef _QX_ENABLE_MONGODB + if (getIsPrimaryKey() && val.toString().isEmpty() && j.isObject() && sFormat.startsWith("mongodb")) + { + QJsonObject obj = j.toObject(); + QString tmp; + if (obj.contains("$oid")) + { + tmp = obj.value("$oid").toString(); + } + if (!tmp.isEmpty()) + { + tmp = ("qx_oid:" + tmp); + val = tmp; + } + } +#endif // _QX_ENABLE_MONGODB + + return m_metaProperty.write(static_cast(pOwner), val); + } + +#endif // _QX_NO_JSON + + qx::any QxDataMember_QObject::getDataPtr(const void *pOwner) const + { + Q_UNUSED(pOwner); + qDebug("[QxOrm] qx::QxDataMember_QObject::getDataPtr() : '%s'", "cannot access to the data-member pointer with Qt introspection engine"); + qAssert(false); + return qx::any(); + } + + qx::any QxDataMember_QObject::getDataPtr(void *pOwner) + { + Q_UNUSED(pOwner); + qDebug("[QxOrm] qx::QxDataMember_QObject::getDataPtr() : '%s'", "cannot access to the data-member pointer with Qt introspection engine"); + qAssert(false); + return qx::any(); + } + + void *QxDataMember_QObject::getDataVoidPtr(const void *pOwner) const + { + Q_UNUSED(pOwner); + qDebug("[QxOrm] qx::QxDataMember_QObject::getDataVoidPtr() : '%s'", "cannot access to the data-member pointer with Qt introspection engine"); + qAssert(false); + return NULL; + } + + void *QxDataMember_QObject::getDataVoidPtr(void *pOwner) + { + Q_UNUSED(pOwner); + qDebug("[QxOrm] qx::QxDataMember_QObject::getDataVoidPtr() : '%s'", "cannot access to the data-member pointer with Qt introspection engine"); + qAssert(false); + return NULL; + } + +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#if _QX_SERIALIZE_POLYMORPHIC +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +QX_DATA_MEMBER_QOBJECT_IMPL_VIRTUAL_ARCHIVE_CPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxFactory/IxFactory.cpp b/src/QxFactory/IxFactory.cpp new file mode 100644 index 0000000..cef575f --- /dev/null +++ b/src/QxFactory/IxFactory.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +namespace qx +{ + + IxFactory::IxFactory(const QString &sKey) : m_sKeyFactory(sKey) + { +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::IxFactory constructor '%s'", qPrintable(m_sKeyFactory)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + + QxFactoryX::getSingleton()->registerFactory(m_sKeyFactory, this); + } + + IxFactory::~IxFactory() + { +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::IxFactory destructor '%s'", qPrintable(m_sKeyFactory)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + + if (!QxFactoryX::isSingletonNull()) + { + QxFactoryX::getSingleton()->unregisterFactory(m_sKeyFactory); + } + } + +} // namespace qx diff --git a/src/QxFactory/QxFactoryX.cpp b/src/QxFactory/QxFactoryX.cpp new file mode 100644 index 0000000..35bb660 --- /dev/null +++ b/src/QxFactory/QxFactoryX.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxFactoryX) + +namespace qx +{ + + void QxFactoryX::registerFactory(const QString &sKey, IxFactory *pFactory) + { + QMutexLocker locker(&m_oMutexFactoryX); + qAssert(!sKey.isEmpty() && !m_mapFactoryX.contains(sKey)); + + if (!pFactory || sKey.isEmpty() || m_mapFactoryX.contains(sKey)) + return; + + m_mapFactoryX.insert(sKey, pFactory); + } + + void QxFactoryX::unregisterFactory(const QString &sKey) + { + QMutexLocker locker(&m_oMutexFactoryX); + m_mapFactoryX.remove(sKey); + } + + qx::any QxFactoryX::createObject(const QString &sKey, bool bRawPointer /* = false */) const + { + IxFactory *pFactory = (m_mapFactoryX.contains(sKey) ? m_mapFactoryX.value(sKey) : NULL); + if (!pFactory) + { + qDebug("[QxOrm] cannot create an instance of type '%s'", qPrintable(sKey)); + } + + return (pFactory ? pFactory->createObject(bRawPointer) : qx::any()); + } + + void *QxFactoryX::createObjectNudePtr(const QString &sKey) const + { + IxFactory *pFactory = (m_mapFactoryX.contains(sKey) ? m_mapFactoryX.value(sKey) : NULL); + if (!pFactory) + { + qDebug("[QxOrm] cannot create an instance of type '%s'", qPrintable(sKey)); + } + + return (pFactory ? pFactory->createObjectNudePtr() : NULL); + } + +#ifndef _QX_NO_RTTI + const std::type_info &QxFactoryX::typeInfo(const QString &sKey) const + { + IxFactory *pFactory = (m_mapFactoryX.contains(sKey) ? m_mapFactoryX.value(sKey) : NULL); + if (!pFactory) + { + qDebug("[QxOrm] cannot get informations about type '%s'", qPrintable(sKey)); + } + + return (pFactory ? pFactory->typeInfo() : typeid(void)); + } +#endif // _QX_NO_RTTI + +} // namespace qx diff --git a/src/QxHttpServer/QxHttpCookie.cpp b/src/QxHttpServer/QxHttpCookie.cpp new file mode 100644 index 0000000..d0c66a2 --- /dev/null +++ b/src/QxHttpServer/QxHttpCookie.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +namespace qx +{ + + QxHttpCookie::QxHttpCookie() : path("/"), maxAge(0), secure(false), httpOnly(false) { ; } + + QxHttpCookie::QxHttpCookie(const QByteArray &name_, const QByteArray &value_, const QByteArray &domain_ /* = QByteArray() */, const QByteArray &path_ /* = QByteArray("/") */, qlonglong maxAge_ /* = 0 */, bool secure_ /* = false */, bool httpOnly_ /* = false */) : name(name_), value(value_), domain(domain_), path(path_), maxAge(maxAge_), secure(secure_), httpOnly(httpOnly_) { ; } + + QxHttpCookie::~QxHttpCookie() { ; } + + QByteArray QxHttpCookie::toString() const + { + QByteArray result = name; + if (!value.isEmpty()) + { + result += "=" + value; + } + if (!domain.isEmpty()) + { + result += "; Domain=" + domain; + } + if (!path.isEmpty()) + { + result += "; Path=" + path; + } + if (maxAge != 0) + { + result += "; Max-Age=" + QByteArray::number(maxAge); + } + if (secure) + { + result += "; Secure"; + } + if (httpOnly) + { + result += "; HttpOnly"; + } + return result; + } + + QHash QxHttpCookie::parse(const QByteArray &cookies) + { + QHash result; + QList lst = cookies.split(';'); + Q_FOREACH (QByteArray data, lst) + { + QByteArray name, value; + int pos = data.indexOf('='); + if (pos <= 0) + { + name = data.trimmed(); + } + else + { + name = data.left(pos).trimmed(); + value = data.mid(pos + 1).trimmed(); + } + if (name.isEmpty()) + { + continue; + } + + QxHttpCookie cookie(name, value); + result.insert(cookie.name, cookie); + } + return result; + } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpRequest.cpp b/src/QxHttpServer/QxHttpRequest.cpp new file mode 100644 index 0000000..71bd855 --- /dev/null +++ b/src/QxHttpServer/QxHttpRequest.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN QxHttpRequest::QxHttpRequestImpl + { + + QUrl m_url; //!< HTTP request path + QString m_command; //!< HTTP request method : GET, POST, HEAD, PUT, DELETE, etc... + QString m_version; //!< HTTP request version + QByteArray m_data; //!< HTTP request body content + QHash m_headers; //!< HTTP request headers + QHash m_cookies; //!< HTTP request cookies + QHash m_dispatchParams; //!< HTTP request dynamic URL parameters from server dispatcher + QHash m_params; //!< HTTP request parameters (from URL and from body if content-type is 'application/x-www-form-urlencoded', which means web-form submit) + QString m_address; //!< HTTP client IP address + long m_port; //!< HTTP client port + QxHttpTransaction *m_transaction; //!< HTTP transaction + QString m_guid; //!< HTTP request internal GUID (can be used for logging for example) + + QxHttpRequestImpl(QxHttpTransaction *transaction) : m_port(0), m_transaction(transaction) + { + qAssert(m_transaction != NULL); + m_guid = QUuid::createUuid().toString(); + } + ~QxHttpRequestImpl() { ; } + }; + + QxHttpRequest::QxHttpRequest(QxHttpTransaction *transaction) : m_pImpl(new QxHttpRequestImpl(transaction)) { ; } + + QxHttpRequest::~QxHttpRequest() { ; } + + QUrl &QxHttpRequest::url() { return m_pImpl->m_url; } + + QString &QxHttpRequest::command() { return m_pImpl->m_command; } + + QString &QxHttpRequest::version() { return m_pImpl->m_version; } + + QByteArray &QxHttpRequest::data() { return m_pImpl->m_data; } + + QHash &QxHttpRequest::headers() { return m_pImpl->m_headers; } + + QByteArray QxHttpRequest::header(const QByteArray &key) + { + QHashIterator itr(m_pImpl->m_headers); + while (itr.hasNext()) + { + itr.next(); + if (itr.key().trimmed().toLower() == key.trimmed().toLower()) + { + return itr.value(); + } + } + return QByteArray(); + } + + QHash &QxHttpRequest::cookies() { return m_pImpl->m_cookies; } + + QxHttpCookie QxHttpRequest::cookie(const QByteArray &name) { return m_pImpl->m_cookies.value(name); } + + QHash &QxHttpRequest::dispatchParams() { return m_pImpl->m_dispatchParams; } + + QHash &QxHttpRequest::params() { return m_pImpl->m_params; } + + QString QxHttpRequest::param(const QString &key) { return m_pImpl->m_params.value(key); } + + QString &QxHttpRequest::sourceAddress() { return m_pImpl->m_address; } + + long &QxHttpRequest::sourcePort() { return m_pImpl->m_port; } + + QString QxHttpRequest::guid() const { return m_pImpl->m_guid; } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpResponse.cpp b/src/QxHttpServer/QxHttpResponse.cpp new file mode 100644 index 0000000..748dc3a --- /dev/null +++ b/src/QxHttpServer/QxHttpResponse.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include + +#include + +#include + +#ifndef QByteArrayLiteral +#define QByteArrayLiteral QByteArray +#endif // QByteArrayLiteral + +namespace qx +{ + + struct Q_DECL_HIDDEN QxHttpResponse::QxHttpResponseImpl + { + + int m_status; //!< HTTP response status (200 OK, 400 Bad Request, 401 Unauthorized, 500 Internal Server Error, etc...) + QByteArray m_data; //!< HTTP response body content + QHash m_headers; //!< HTTP response headers + QHash m_cookies; //!< HTTP response cookies + QxHttpTransaction *m_transaction; //!< HTTP transaction + bool m_isChunked; //!< HTTP response is chunked (useful for streaming for example) + + QxHttpResponseImpl(QxHttpTransaction *transaction) : m_status(200), m_transaction(transaction), m_isChunked(false) + { + qAssert(m_transaction != NULL); + initHeaders(); + } + ~QxHttpResponseImpl() { ; } + + void initHeaders() + { + m_headers.insert("Server", "QxOrm HTTP server"); + m_headers.insert("Date", currentDateTimeGMT()); + m_headers.insert("Content-Type", "text/plain; charset=iso-8859-1"); + if (qx::service::QxConnect::getSingleton()->getKeepAlive() != 0) + { + m_headers.insert("Connection", "keep-alive"); + } + else + { + m_headers.insert("Connection", "close"); + } + } + + qx_bool writeChunked(const QByteArray &data) + { + if (data.isEmpty()) + { + return qx_bool(true); + } + if (!m_transaction) + { + qAssert(false); + return qx_bool(false, "No HTTP transaction associated to the response"); + } + qx_bool bWriteChunked = m_transaction->writeChunked(data); + if (bWriteChunked) + { + m_isChunked = true; + } + return bWriteChunked; + } + + QByteArray currentDateTimeGMT() + { + QByteArray day, month; + QDateTime dt = QDateTime::currentDateTimeUtc(); + switch (dt.date().dayOfWeek()) + { + case 1: + day = QByteArrayLiteral("Mon"); + break; + case 2: + day = QByteArrayLiteral("Tue"); + break; + case 3: + day = QByteArrayLiteral("Wed"); + break; + case 4: + day = QByteArrayLiteral("Thu"); + break; + case 5: + day = QByteArrayLiteral("Fri"); + break; + case 6: + day = QByteArrayLiteral("Sat"); + break; + case 7: + day = QByteArrayLiteral("Sun"); + break; + default: + qAssert(false); + break; + } + switch (dt.date().month()) + { + case 1: + month = QByteArrayLiteral("Jan"); + break; + case 2: + month = QByteArrayLiteral("Feb"); + break; + case 3: + month = QByteArrayLiteral("Mar"); + break; + case 4: + month = QByteArrayLiteral("Apr"); + break; + case 5: + month = QByteArrayLiteral("May"); + break; + case 6: + month = QByteArrayLiteral("Jun"); + break; + case 7: + month = QByteArrayLiteral("Jul"); + break; + case 8: + month = QByteArrayLiteral("Aug"); + break; + case 9: + month = QByteArrayLiteral("Sep"); + break; + case 10: + month = QByteArrayLiteral("Oct"); + break; + case 11: + month = QByteArrayLiteral("Nov"); + break; + case 12: + month = QByteArrayLiteral("Dec"); + break; + default: + qAssert(false); + break; + } + QByteArray day_ = QString("%1").arg(dt.date().day(), 2, 10, QChar('0')).toLatin1(); + QByteArray year = QString("%1").arg(dt.date().year(), 4, 10, QChar('0')).toLatin1(); + QByteArray hour = QString("%1").arg(dt.time().hour(), 2, 10, QChar('0')).toLatin1(); + QByteArray minute = QString("%1").arg(dt.time().minute(), 2, 10, QChar('0')).toLatin1(); + QByteArray second = QString("%1").arg(dt.time().second(), 2, 10, QChar('0')).toLatin1(); + return (day + ", " + day_ + " " + month + " " + year + " " + hour + ":" + minute + ":" + second + " GMT"); + } + }; + + QxHttpResponse::QxHttpResponse(QxHttpTransaction *transaction) : m_pImpl(new QxHttpResponseImpl(transaction)) { ; } + + QxHttpResponse::~QxHttpResponse() { ; } + + int &QxHttpResponse::status() { return m_pImpl->m_status; } + + QByteArray &QxHttpResponse::data() { return m_pImpl->m_data; } + + QHash &QxHttpResponse::headers() { return m_pImpl->m_headers; } + + QByteArray QxHttpResponse::header(const QByteArray &key) + { + QHashIterator itr(m_pImpl->m_headers); + while (itr.hasNext()) + { + itr.next(); + if (itr.key().trimmed().toLower() == key.trimmed().toLower()) + { + return itr.value(); + } + } + return QByteArray(); + } + + QHash &QxHttpResponse::cookies() { return m_pImpl->m_cookies; } + + QxHttpCookie QxHttpResponse::cookie(const QByteArray &name) { return m_pImpl->m_cookies.value(name); } + + qx_bool QxHttpResponse::writeChunked(const QByteArray &data) { return m_pImpl->writeChunked(data); } + + bool QxHttpResponse::isChunked() const { return m_pImpl->m_isChunked; } + + QByteArray QxHttpResponse::statusDesc() + { + QByteArray desc; + switch (m_pImpl->m_status) + { + case 100: + desc = QByteArrayLiteral("Continue"); + break; + case 101: + desc = QByteArrayLiteral("Switching Protocols"); + break; + case 102: + desc = QByteArrayLiteral("Processing"); + break; + case 103: + desc = QByteArrayLiteral("Early Hints"); + break; + case 200: + desc = QByteArrayLiteral("OK"); + break; + case 201: + desc = QByteArrayLiteral("Created"); + break; + case 202: + desc = QByteArrayLiteral("Accepted"); + break; + case 203: + desc = QByteArrayLiteral("Non-Authoritative Information"); + break; + case 204: + desc = QByteArrayLiteral("No Content"); + break; + case 205: + desc = QByteArrayLiteral("Reset Content"); + break; + case 206: + desc = QByteArrayLiteral("Partial Content"); + break; + case 207: + desc = QByteArrayLiteral("Multi-Status"); + break; + case 208: + desc = QByteArrayLiteral("Already Reported"); + break; + case 210: + desc = QByteArrayLiteral("Content Different"); + break; + case 226: + desc = QByteArrayLiteral("IM Used"); + break; + case 300: + desc = QByteArrayLiteral("Multiple Choices"); + break; + case 301: + desc = QByteArrayLiteral("Moved Permanently"); + break; + case 302: + desc = QByteArrayLiteral("Found"); + break; + case 303: + desc = QByteArrayLiteral("See Other"); + break; + case 304: + desc = QByteArrayLiteral("Not Modified"); + break; + case 305: + desc = QByteArrayLiteral("Use Proxy"); + break; + case 306: + desc = QByteArrayLiteral("Switch Proxy"); + break; + case 307: + desc = QByteArrayLiteral("Temporary Redirect"); + break; + case 308: + desc = QByteArrayLiteral("Permanent Redirect"); + break; + case 310: + desc = QByteArrayLiteral("Too many Redirects"); + break; + case 400: + desc = QByteArrayLiteral("Bad Request"); + break; + case 401: + desc = QByteArrayLiteral("Unauthorized"); + break; + case 402: + desc = QByteArrayLiteral("Payment Required"); + break; + case 403: + desc = QByteArrayLiteral("Forbidden"); + break; + case 404: + desc = QByteArrayLiteral("Not Found"); + break; + case 405: + desc = QByteArrayLiteral("Method Not Allowed"); + break; + case 406: + desc = QByteArrayLiteral("Not Acceptable"); + break; + case 407: + desc = QByteArrayLiteral("Proxy Authentication Required"); + break; + case 408: + desc = QByteArrayLiteral("Request Time-out"); + break; + case 409: + desc = QByteArrayLiteral("Conflict"); + break; + case 410: + desc = QByteArrayLiteral("Gone"); + break; + case 411: + desc = QByteArrayLiteral("Length Required"); + break; + case 412: + desc = QByteArrayLiteral("Precondition Failed"); + break; + case 413: + desc = QByteArrayLiteral("Request Entity Too Large"); + break; + case 414: + desc = QByteArrayLiteral("Request-URI Too Long"); + break; + case 415: + desc = QByteArrayLiteral("Unsupported Media Type"); + break; + case 416: + desc = QByteArrayLiteral("Requested range unsatisfiable"); + break; + case 417: + desc = QByteArrayLiteral("Expectation failed"); + break; + case 418: + desc = QByteArrayLiteral("I’m a teapot"); + break; + case 421: + desc = QByteArrayLiteral("Bad mapping / Misdirected Request"); + break; + case 422: + desc = QByteArrayLiteral("Unprocessable entity"); + break; + case 423: + desc = QByteArrayLiteral("Locked"); + break; + case 424: + desc = QByteArrayLiteral("Method failure"); + break; + case 425: + desc = QByteArrayLiteral("Unordered Collection"); + break; + case 426: + desc = QByteArrayLiteral("Upgrade Required"); + break; + case 428: + desc = QByteArrayLiteral("Precondition Required"); + break; + case 429: + desc = QByteArrayLiteral("Too Many Requests"); + break; + case 431: + desc = QByteArrayLiteral("Request Header Fields Too Large"); + break; + case 449: + desc = QByteArrayLiteral("Retry With"); + break; + case 450: + desc = QByteArrayLiteral("Blocked by Windows Parental Controls"); + break; + case 451: + desc = QByteArrayLiteral("Unavailable For Legal Reasons"); + break; + case 456: + desc = QByteArrayLiteral("Unrecoverable Error"); + break; + case 444: + desc = QByteArrayLiteral("No Response"); + break; + case 495: + desc = QByteArrayLiteral("SSL Certificate Error"); + break; + case 496: + desc = QByteArrayLiteral("SSL Certificate Required"); + break; + case 497: + desc = QByteArrayLiteral("HTTP Request Sent to HTTPS Port"); + break; + case 498: + desc = QByteArrayLiteral("Token expired/invalid"); + break; + case 499: + desc = QByteArrayLiteral("Client Closed Request"); + break; + case 500: + desc = QByteArrayLiteral("Internal Server Error"); + break; + case 501: + desc = QByteArrayLiteral("Not Implemented"); + break; + case 502: + desc = QByteArrayLiteral("Bad Gateway ou Proxy Error"); + break; + case 503: + desc = QByteArrayLiteral("Service Unavailable"); + break; + case 504: + desc = QByteArrayLiteral("Gateway Time-out"); + break; + case 505: + desc = QByteArrayLiteral("HTTP Version not supported"); + break; + case 506: + desc = QByteArrayLiteral("Variant Also Negotiates"); + break; + case 507: + desc = QByteArrayLiteral("Insufficient storage"); + break; + case 508: + desc = QByteArrayLiteral("Loop detected"); + break; + case 509: + desc = QByteArrayLiteral("Bandwidth Limit Exceeded"); + break; + case 510: + desc = QByteArrayLiteral("Not extended"); + break; + case 511: + desc = QByteArrayLiteral("Network authentication required"); + break; + case 520: + desc = QByteArrayLiteral("Unknown Error"); + break; + case 521: + desc = QByteArrayLiteral("Web Server Is Down"); + break; + case 522: + desc = QByteArrayLiteral("Connection Timed Out"); + break; + case 523: + desc = QByteArrayLiteral("Origin Is Unreachable"); + break; + case 524: + desc = QByteArrayLiteral("A Timeout Occurred"); + break; + case 525: + desc = QByteArrayLiteral("SSL Handshake Failed"); + break; + case 526: + desc = QByteArrayLiteral("Invalid SSL Certificate"); + break; + case 527: + desc = QByteArrayLiteral("Railgun Error"); + break; + default: + desc = QByteArrayLiteral("Unknown status code"); + break; + } + return desc; + } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpServer.cpp b/src/QxHttpServer/QxHttpServer.cpp new file mode 100644 index 0000000..5def479 --- /dev/null +++ b/src/QxHttpServer/QxHttpServer.cpp @@ -0,0 +1,769 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#include +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +namespace qx +{ + + struct QxHttpServerDispatchSegment + { + + enum type_segment + { + _static, + _variable, + _variable_and_type, + _variable_and_regexp, + _wildcard + }; + + type_segment m_type; //!< HTTP server dispatcher segment type + QString m_path; //!< HTTP server dispatcher segment path (part of item path splitted by '/' character) + qx_hash_result m_pathHash; //!< HTTP server dispatcher segment path hash (for optimization) + QString m_varName; //!< HTTP server dispatcher segment variable name + QString m_varType; //!< HTTP server dispatcher segment variable type (or regular expression) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegularExpression m_regExp; //!< HTTP server dispatcher segment regular expression +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegExp m_regExp; //!< HTTP server dispatcher segment regular expression (Qt4 version) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + QxHttpServerDispatchSegment() : m_type(_static), m_pathHash(0) { ; } + ~QxHttpServerDispatchSegment() { ; } + + bool parse(); + bool check(const QString &path, qx_hash_result hash) const; + void fillParam(const QString &path, QHash ¶meters) const; + }; + + struct QxHttpServerDispatchItem + { + + QString m_command; //!< HTTP server dispatcher item command (GET, POST, DELETE, PUT, etc...) + qx_hash_result m_commandHash; //!< HTTP server dispatcher item command hash (for optimization) + bool m_commandWildcard; //!< HTTP server dispatcher item wildcard command (means accept all commands) + QString m_path; //!< HTTP server dispatcher item path (example : /foo/bar///*) + QList> m_segments; //!< HTTP server dispatcher item list of segments (path splitted by '/' character) + QxHttpServer::type_fct_custom_request_handler m_fct; //!< HTTP server dispatcher item callback (executed in its dedicated thread) + + QxHttpServerDispatchItem() : m_commandHash(0), m_commandWildcard(false) { ; } + ~QxHttpServerDispatchItem() { ; } + + bool parse(); + }; + + struct QxHttpServerDispatcher + { + + qx::QxCollection> m_lstDispatchItems; //!< HTTP server dispatcher items (associate url to callback) + + QxHttpServerDispatcher() { ; } + ~QxHttpServerDispatcher() { ; } + + void dispatch(const QString &command, const QString &path, QxHttpServer::type_fct_custom_request_handler fct, long position); + std::shared_ptr find(qx::QxHttpRequest &request) const; + }; + + struct Q_DECL_HIDDEN QxHttpServer::QxHttpServerImpl + { + + typedef std::shared_ptr type_fct_ptr; + + QMutex m_mutex; //!< Mutex => 'QxHttpServer' is thread-safe (callbacks can be changed even if server is running) + qx::service::QxThreadPool_ptr m_pThreadPool; //!< HTTP server is managed by a thread pool + type_fct_ptr m_fctCustomRequestHandler; //!< Callback to manage requests and build responses (executed in its dedicated thread) + std::unique_ptr m_pDispatcher; //!< HTTP server dispatcher (each callback is executed in its dedicated thread) + type_fct_ptr m_fctBeforeDispatching; //!< Callback function called before handling the request (executed in its dedicated thread), can be used for logging for example + type_fct_ptr m_fctAfterDispatching; //!< Callback function called after handling the request and generating the response (executed in its dedicated thread), can be used for logging for example + QAbstractEventDispatcher *m_pEventDispatcher; //!< Can be used to optimize socket implementation (using epoll on Linux for example), for example : https://github.com/sjinks/qt_eventdispatcher_epoll or https://github.com/connectedtable/qeventdispatcher_epoll + + QxHttpServerImpl() : m_pDispatcher(new QxHttpServerDispatcher()), m_pEventDispatcher(NULL) { ; } + ~QxHttpServerImpl() { ; } + }; + + QxHttpServer::QxHttpServer(QObject *parent /* = NULL */) : QObject(parent), m_pImpl(new QxHttpServerImpl()) + { + qRegisterMetaType("qx::QxHttpTransaction_ptr"); + qRegisterMetaType("QxHttpTransaction_ptr"); + } + + QxHttpServer::~QxHttpServer() { stopServer(); } + + void QxHttpServer::startServer() + { + if (m_pImpl->m_pThreadPool) + { + stopServer(); + } + qx::service::QxConnect::getSingleton()->setModeHTTP(true); + m_pImpl->m_pThreadPool.reset(new qx::service::QxThreadPool()); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + if (m_pImpl->m_pEventDispatcher) + { + m_pImpl->m_pThreadPool->setEventDispatcher(m_pImpl->m_pEventDispatcher); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + QObject::connect(m_pImpl->m_pThreadPool.get(), SIGNAL(error(const QString &, qx::service::QxTransaction_ptr)), this, SLOT(onError(const QString &, qx::service::QxTransaction_ptr))); + QObject::connect(m_pImpl->m_pThreadPool.get(), SIGNAL(serverIsRunning(bool, qx::service::QxServer *)), this, SLOT(onServerIsRunning(bool, qx::service::QxServer *))); + QObject::connect(m_pImpl->m_pThreadPool.get(), SIGNAL(transactionStarted(qx::service::QxTransaction_ptr)), this, SLOT(onTransactionStarted(qx::service::QxTransaction_ptr))); + QObject::connect(m_pImpl->m_pThreadPool.get(), SIGNAL(transactionFinished(qx::service::QxTransaction_ptr)), this, SLOT(onTransactionFinished(qx::service::QxTransaction_ptr))); + QObject::connect(m_pImpl->m_pThreadPool.get(), SIGNAL(customRequestHandler(qx::service::QxTransaction_ptr)), this, SLOT(onCustomRequestHandler(qx::service::QxTransaction_ptr)), Qt::DirectConnection); + m_pImpl->m_pThreadPool->start(); + } + + void QxHttpServer::stopServer() + { + if (!m_pImpl->m_pThreadPool) + { + return; + } + m_pImpl->m_pThreadPool.reset(); + Q_EMIT serverStatusChanged(false); + } + + void QxHttpServer::setCustomRequestHandler(QxHttpServer::type_fct_custom_request_handler fct) + { + QMutexLocker locker(&m_pImpl->m_mutex); + if (!fct) + { + m_pImpl->m_fctCustomRequestHandler.reset(); + return; + } + m_pImpl->m_fctCustomRequestHandler = std::make_shared(); + (*m_pImpl->m_fctCustomRequestHandler) = fct; + } + + QxHttpServer &QxHttpServer::dispatch(const QString &command, const QString &path, QxHttpServer::type_fct_custom_request_handler fct, long position /* = -1 */) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_pDispatcher->dispatch(command.toUpper(), path, fct, position); + return (*this); + } + + void QxHttpServer::beforeDispatching(QxHttpServer::type_fct_custom_request_handler fct) + { + QMutexLocker locker(&m_pImpl->m_mutex); + if (!fct) + { + m_pImpl->m_fctBeforeDispatching.reset(); + return; + } + m_pImpl->m_fctBeforeDispatching = std::make_shared(); + (*m_pImpl->m_fctBeforeDispatching) = fct; + } + + void QxHttpServer::afterDispatching(QxHttpServer::type_fct_custom_request_handler fct) + { + QMutexLocker locker(&m_pImpl->m_mutex); + if (!fct) + { + m_pImpl->m_fctAfterDispatching.reset(); + return; + } + m_pImpl->m_fctAfterDispatching = std::make_shared(); + (*m_pImpl->m_fctAfterDispatching) = fct; + } + + void QxHttpServer::clearDispatcher() + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_pDispatcher.reset(new QxHttpServerDispatcher()); + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void QxHttpServer::setEventDispatcher(QAbstractEventDispatcher *pEventDispatcher) + { + m_pImpl->m_pEventDispatcher = pEventDispatcher; + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + void QxHttpServer::onError(const QString &err, qx::service::QxTransaction_ptr transaction) + { + qx::QxHttpTransaction_ptr httpTransaction = std::dynamic_pointer_cast(transaction); + if (transaction && (!httpTransaction)) + { + qAssertMsg(false, "[QxOrm] qx::QxHttpServer::onError", "unable to get HTTP transaction using std::dynamic_pointer_cast"); + } + Q_EMIT error(err, httpTransaction); + } + + void QxHttpServer::onServerIsRunning(bool bIsRunning, qx::service::QxServer *pServer) + { + Q_UNUSED(pServer); + if (bIsRunning) + { + qx::service::QxConnect *serverSettings = qx::service::QxConnect::getSingleton(); + QString msg = "HTTP server is running ("; + msg += "port: " + QString::number(serverSettings->getPort()); + msg += ", threads: " + QString::number(serverSettings->getThreadCount()); +#ifndef QT_NO_SSL + msg += ", SSL: " + (serverSettings->getSSLEnabled() ? QString("enabled") : QString("disabled")); +#else // QT_NO_SSL + msg += ", SSL: disabled"; +#endif // QT_NO_SSL + msg += ")"; + qDebug("[QxOrm] %s", qPrintable(msg)); + } + else + { + qDebug("[QxOrm] %s", "HTTP server has been stopped"); + } + Q_EMIT serverStatusChanged(bIsRunning); + } + + void QxHttpServer::onTransactionStarted(qx::service::QxTransaction_ptr transaction) + { + qx::QxHttpTransaction_ptr httpTransaction = std::dynamic_pointer_cast(transaction); + if (transaction && (!httpTransaction)) + { + qAssertMsg(false, "[QxOrm] qx::QxHttpServer::onTransactionStarted", "unable to get HTTP transaction using std::dynamic_pointer_cast"); + } + Q_EMIT transactionStarted(httpTransaction); + } + + void QxHttpServer::onTransactionFinished(qx::service::QxTransaction_ptr transaction) + { + qx::QxHttpTransaction_ptr httpTransaction = std::dynamic_pointer_cast(transaction); + if (transaction && (!httpTransaction)) + { + qAssertMsg(false, "[QxOrm] qx::QxHttpServer::onTransactionFinished", "unable to get HTTP transaction using std::dynamic_pointer_cast"); + } + Q_EMIT transactionFinished(httpTransaction); + } + + void QxHttpServer::onCustomRequestHandler(qx::service::QxTransaction_ptr transaction) + { + // Check if transaction is valid + qx::QxHttpTransaction_ptr httpTransaction = std::dynamic_pointer_cast(transaction); + if (transaction && (!httpTransaction)) + { + qAssertMsg(false, "[QxOrm] qx::QxHttpServer::onCustomRequestHandler", "unable to get HTTP transaction using std::dynamic_pointer_cast"); + return; + } + if (!httpTransaction) + { + qAssertMsg(false, "[QxOrm] qx::QxHttpServer::onCustomRequestHandler", "HTTP transaction is empty"); + return; + } + + // Get request and response instances + qx::QxHttpRequest &request = httpTransaction->request(); + qx::QxHttpResponse &response = httpTransaction->response(); + + // Get custom request handler + before/after dispatching callbacks (thread-safe) + std::shared_ptr fctCustomHandler; + std::shared_ptr fctBeforeDispatching; + std::shared_ptr fctAfterDispatching; + { + QMutexLocker locker(&m_pImpl->m_mutex); + fctCustomHandler = m_pImpl->m_fctCustomRequestHandler; + fctBeforeDispatching = m_pImpl->m_fctBeforeDispatching; + fctAfterDispatching = m_pImpl->m_fctAfterDispatching; + } + + // Execute before dispatching callback + if (fctBeforeDispatching && (*fctBeforeDispatching)) + { + try + { + (*fctBeforeDispatching)(request, response); + } + catch (const qx::exception &x) + { + qx_bool xb = x.toQxBool(); + httpTransaction->setMessageReturn(xb); + } + catch (const std::exception &e) + { + httpTransaction->setMessageReturn(qx_bool(500, e.what())); + } + catch (...) + { + httpTransaction->setMessageReturn(qx_bool(500, "[QxOrm] Unknown server error (before dispatching)")); + } + } + + // Get dispatcher item callback (thread-safe) + std::shared_ptr itemDispatch; + { + QMutexLocker locker(&m_pImpl->m_mutex); + itemDispatch = m_pImpl->m_pDispatcher->find(request); + } + + try + { + // Execute dispatcher item callback or custom request handler + if (itemDispatch && itemDispatch->m_fct) + { + itemDispatch->m_fct(request, response); + } + else if (fctCustomHandler && (*fctCustomHandler)) + { + (*fctCustomHandler)(request, response); + } + else + { + httpTransaction->setMessageReturn(qx_bool(501, "[QxOrm] Not implemented : no route found for URL (" + request.command() + " - " + request.url().path() + ") : you must provide a request handler (callback) using qx::QxHttpServer::dispatch() or qx::QxHttpServer::setCustomRequestHandler() method")); + } + } + catch (const qx::exception &x) + { + qx_bool xb = x.toQxBool(); + httpTransaction->setMessageReturn(xb); + } + catch (const std::exception &e) + { + httpTransaction->setMessageReturn(qx_bool(500, e.what())); + } + catch (...) + { + httpTransaction->setMessageReturn(qx_bool(500, "[QxOrm] Unknown server error")); + } + + // Execute after dispatching callback + if (fctAfterDispatching && (*fctAfterDispatching)) + { + try + { + (*fctAfterDispatching)(request, response); + } + catch (const qx::exception &x) + { + qx_bool xb = x.toQxBool(); + httpTransaction->setMessageReturn(xb); + } + catch (const std::exception &e) + { + httpTransaction->setMessageReturn(qx_bool(500, e.what())); + } + catch (...) + { + httpTransaction->setMessageReturn(qx_bool(500, "[QxOrm] Unknown server error (after dispatching)")); + } + } + } + + void QxHttpServerDispatcher::dispatch(const QString &command, const QString &path, QxHttpServer::type_fct_custom_request_handler fct, long position) + { + QString key = command + "|" + path; + if (m_lstDispatchItems.exist(key)) + { + m_lstDispatchItems.removeByKey(key); + } + if ((!fct) || (path.isEmpty()) || (command.isEmpty())) + { + return; + } + + std::shared_ptr item = std::make_shared(); + item->m_command = command; + item->m_path = ((path == "/") ? QString("/*") : path); + item->m_fct = fct; + if (!item->parse()) + { + qAssert(false); + return; + } + if (item->m_segments.count() <= 0) + { + return; + } + if (position < 0) + { + m_lstDispatchItems.insert(key, item); + } + else + { + m_lstDispatchItems.insert(position, key, item); + } + } + + std::shared_ptr QxHttpServerDispatcher::find(qx::QxHttpRequest &request) const + { + // Check and prepare input data + if (m_lstDispatchItems.count() <= 0) + { + return std::shared_ptr(); + } + QString requestCommand = request.command().toUpper(); + qx_hash_result requestCommandHash = qHash(requestCommand); + QString requestPath = request.url().path(); + if (requestPath == "/") + { + requestPath = "/*"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList requestSegments = requestPath.split("/", Qt::SkipEmptyParts); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList requestSegments = requestPath.split("/", QString::SkipEmptyParts); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QList requestSegmentsHash; + requestSegmentsHash.reserve(requestSegments.count()); + Q_FOREACH (QString data, requestSegments) + { + requestSegmentsHash.append(qHash(data)); + } + if (requestSegments.count() <= 0) + { + return std::shared_ptr(); + } + + // Iterate over all dispatcher items + qx::QxCollectionIterator> itr(m_lstDispatchItems); + while (itr.next()) + { + // Check dispatcher item command and segments count + const std::shared_ptr &item = itr.value(); + if (!item) + { + qAssert(false); + continue; + } + if ((item->m_commandHash != requestCommandHash) && (!item->m_commandWildcard)) + { + continue; + } + if (item->m_segments.count() > requestSegments.count()) + { + continue; + } + if (!item->m_fct) + { + continue; + } + + // Iterate over all dispatcher item segments to check if everything matched + bool bAllSegmentsOk = true; + for (int i = 0; i < item->m_segments.count(); i++) + { + const std::shared_ptr &segment = item->m_segments.at(i); + if (!segment) + { + qAssert(false); + continue; + } + if (!segment->check(requestSegments.at(i), requestSegmentsHash.at(i))) + { + bAllSegmentsOk = false; + break; + } + } + if (!bAllSegmentsOk) + { + continue; + } + + // Iterate over all dispatcher item segments to fill URL parameters + QHash parameters; + for (int i = 0; i < item->m_segments.count(); i++) + { + const std::shared_ptr &segment = item->m_segments.at(i); + if (!segment) + { + qAssert(false); + continue; + } + segment->fillParam(requestSegments.at(i), parameters); + } + + // We have found our dispatcher item + request.dispatchParams() = parameters; + return item; + } + return std::shared_ptr(); + } + + bool QxHttpServerDispatchItem::parse() + { + m_segments.clear(); + m_commandHash = qHash(m_command); + m_commandWildcard = (m_command == "*"); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList segments = m_path.split("/", Qt::SkipEmptyParts); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + QStringList segments = m_path.split("/", QString::SkipEmptyParts); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + Q_FOREACH (QString data, segments) + { + data = data.trimmed(); + if (data.isEmpty()) + { + continue; + } + std::shared_ptr segment = std::make_shared(); + segment->m_path = data; + if (!segment->parse()) + { + qAssert(false); + return false; + } + m_segments.append(segment); + } + return true; + } + + bool QxHttpServerDispatchSegment::parse() + { + if (m_path.isEmpty()) + { + return true; + } + if (m_path.startsWith("<") && m_path.endsWith(">")) + { + QString path = m_path; + path.remove(0, 1); + path.chop(1); + int pos = path.indexOf(":"); + if (pos >= 0) + { + m_varName = path.left(pos).trimmed(); + m_varType = path.mid(pos + 1).trimmed(); + m_type = QxHttpServerDispatchSegment::_variable_and_type; + if (m_varType.startsWith("{") && m_varType.endsWith("}")) + { + m_varType.remove(0, 1); + m_varType.chop(1); + m_regExp.setPattern(m_varType); + m_type = QxHttpServerDispatchSegment::_variable_and_regexp; + } + } + else + { + m_varName = path.trimmed(); + m_type = QxHttpServerDispatchSegment::_variable; + } + } + else if (m_path == "*") + { + m_type = QxHttpServerDispatchSegment::_wildcard; + } + else + { + m_type = QxHttpServerDispatchSegment::_static; + m_pathHash = qHash(m_path); + } + return true; + } + + bool QxHttpServerDispatchSegment::check(const QString &path, qx_hash_result hash) const + { + bool result = false; + switch (m_type) + { + case QxHttpServerDispatchSegment::_static: + qAssert((hash != 0) && (m_pathHash != 0)); + result = (hash == m_pathHash); + break; + case QxHttpServerDispatchSegment::_variable: + qAssert(!m_varName.isEmpty()); + result = (!path.isEmpty()); + break; + case QxHttpServerDispatchSegment::_variable_and_type: + qAssert(!m_varName.isEmpty() && !m_varType.isEmpty()); + if ((m_varType == "int") || (m_varType == "long")) + { + qlonglong val = path.toLongLong(&result, 10); + Q_UNUSED(val); + } + if ((m_varType == "float") || (m_varType == "double")) + { + double val = path.toDouble(&result); + Q_UNUSED(val); + } + else if (m_varType == "string") + { + result = (!path.isEmpty()); + } + break; + case QxHttpServerDispatchSegment::_variable_and_regexp: + qAssert(!m_varName.isEmpty() && !m_varType.isEmpty()); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + result = ((!path.isEmpty()) && (m_regExp.match(path).hasMatch())); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + result = ((!path.isEmpty()) && (m_regExp.exactMatch(path))); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + break; + case QxHttpServerDispatchSegment::_wildcard: + result = true; + break; + default: + break; + } + return result; + } + + void QxHttpServerDispatchSegment::fillParam(const QString &path, QHash ¶meters) const + { + QVariant vParamValue; + bool bAddParam = true; + switch (m_type) + { + case QxHttpServerDispatchSegment::_variable: + vParamValue = QVariant(path); + break; + case QxHttpServerDispatchSegment::_variable_and_type: + vParamValue = QVariant(path); + break; + case QxHttpServerDispatchSegment::_variable_and_regexp: + vParamValue = QVariant(path); + break; + default: + bAddParam = false; + break; + } + if ((bAddParam) && (!m_varName.isEmpty())) + { + parameters.insert(m_varName, vParamValue); + } + } + + void QxHttpServer::buildResponseStaticFile(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QString &serverPath, qlonglong chunkedSize /* = 0 */) + { + // Check HTTP method GET + QByteArray requestPath = request.url().path().toLatin1(); + if (request.command() != "GET") + { + response.status() = 400; + response.data() = "Unknown command '" + request.command().toLatin1() + "' to get server static file '" + requestPath + "'"; + return; + } + + // Check root server path to deliver static files + QDir dirServerPath(serverPath); + if (!dirServerPath.exists()) + { + response.status() = 404; + response.data() = "Server path for static files not found : " + serverPath.toLatin1(); + return; + } + + // Check if requested static file exists on server + QString filePath = dirServerPath.filePath(requestPath.right(requestPath.size() - 1)); + if (!QFile::exists(filePath)) + { + response.status() = 404; + response.data() = "Server static file not found : " + requestPath; + return; + } + + // Check if requested static file is inside root server path (to avoid ../) + QDir dirFilePath(filePath); + QString canonicalServerPath = dirServerPath.canonicalPath(); + QString canonicalFilePath = dirFilePath.canonicalPath(); + if (!canonicalFilePath.startsWith(canonicalServerPath)) + { + response.status() = 403; + response.data() = "Cannot access to server static file : " + requestPath; + return; + } + + // Try to open static file in read-only mode + QFile file(filePath); + if (!file.open(QFile::ReadOnly)) + { + response.status() = 403; + response.data() = "Cannot open server static file : " + requestPath; + return; + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QMimeDatabase mimeDatabase; + QMimeType mimeType = mimeDatabase.mimeTypeForFile(filePath); + response.headers().insert("Content-Type", mimeType.name().toLatin1()); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + // Read file content + if (chunkedSize > 0) + { + while (!file.atEnd()) + { + if (!response.writeChunked(file.read(chunkedSize))) + { + return; + } + } + } + else + { + response.data() = file.readAll(); + } + file.close(); + } + + void QxHttpServer::buildResponseQxRestApi(qx::QxHttpRequest &request, qx::QxHttpResponse &response) + { + qx::QxRestApi api; + QString result = api.processRequest(request.data()); + response.headers().insert("Content-Type", "application/json; charset=utf-8"); + response.data() = result.toUtf8(); + } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpSession.cpp b/src/QxHttpServer/QxHttpSession.cpp new file mode 100644 index 0000000..9924955 --- /dev/null +++ b/src/QxHttpServer/QxHttpSession.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN QxHttpSession::QxHttpSessionImpl + { + + QMutex m_mutex; //!< Mutex => 'QxHttpSession' is thread-safe + QHash m_storage; //!< Session storage based on key/values + QByteArray m_id; //!< Session unique identifier + QDateTime m_lastAccess; //!< Session last access date-time to check if expired + + QxHttpSessionImpl() + { + m_id = QUuid::createUuid().toString().toLatin1(); + m_lastAccess = QDateTime::currentDateTime(); + } + ~QxHttpSessionImpl() { ; } + }; + + QxHttpSession::QxHttpSession() : m_pImpl(new QxHttpSessionImpl()) { ; } + + QxHttpSession::~QxHttpSession() { ; } + + QByteArray QxHttpSession::id() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_id; + } + + QDateTime QxHttpSession::lastAccess() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_lastAccess; + } + + void QxHttpSession::lastAccess(const QDateTime &dt) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_lastAccess = dt; + } + + QVariant QxHttpSession::get(const QByteArray &key) + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_storage.value(key); + } + + void QxHttpSession::set(const QByteArray &key, const QVariant &value) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_storage.insert(key, value); + } + + QHash QxHttpSession::getAll() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_storage; + } + + void QxHttpSession::remove(const QByteArray &key) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_storage.remove(key); + } + + void QxHttpSession::clear() + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_storage.clear(); + } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpSessionManager.cpp b/src/QxHttpServer/QxHttpSessionManager.cpp new file mode 100644 index 0000000..e49ebd5 --- /dev/null +++ b/src/QxHttpServer/QxHttpSessionManager.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxHttpSessionManager) + +namespace qx +{ + + struct Q_DECL_HIDDEN QxHttpSessionManager::QxHttpSessionManagerImpl + { + + QMutex m_mutex; //!< Mutex => 'QxHttpSessionManager' is thread-safe + QTimer m_timer; //!< Timer to remove automatically expired sessions + QHash m_sessions; //!< List of sessions + + QxHttpSessionManagerImpl() { ; } + ~QxHttpSessionManagerImpl() { ; } + + QByteArray getSessionId(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName) + { + QByteArray id = response.cookie(cookieName).value; + if (id.isEmpty()) + { + id = request.cookie(cookieName).value; + } + if ((!id.isEmpty()) && (!m_sessions.contains(id))) + { + id = QByteArray(); + } + return id; + } + + qx::QxHttpSession_ptr getSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName, bool autoCreateSession) + { + do + { + QMutexLocker locker(&m_mutex); + QByteArray id = getSessionId(request, response, cookieName); + if (id.isEmpty() || (!m_sessions.contains(id))) + { + break; + } + qx::QxHttpSession_ptr session = m_sessions.value(id); + if (session) + { + session->lastAccess(QDateTime::currentDateTime()); + } + return session; + } while (false); + if (autoCreateSession) + { + return createSession(request, response, cookieName); + } + return qx::QxHttpSession_ptr(); + } + + qx::QxHttpSession_ptr createSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName) + { + removeSession(request, response, cookieName); + QMutexLocker locker(&m_mutex); + qx::QxHttpSession_ptr session(new qx::QxHttpSession(), (&QxHttpSessionManager::deleteSession)); + QByteArray id = session->id(); + m_sessions.insert(id, session); + + qx::QxHttpCookie cookie; + cookie.name = cookieName; + cookie.value = id; + response.cookies().insert(cookieName, cookie); + return session; + } + + void removeSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName) + { + QMutexLocker locker(&m_mutex); + QByteArray id = getSessionId(request, response, cookieName); + if (id.isEmpty() || (!m_sessions.contains(id))) + { + return; + } + m_sessions.remove(id); + } + }; + + QxHttpSessionManager::QxHttpSessionManager() : QObject(), qx::QxSingleton("qx::QxHttpSessionManager"), m_pImpl(new QxHttpSessionManagerImpl()) + { + QObject::connect((&m_pImpl->m_timer), SIGNAL(timeout()), this, SLOT(onCheckSessionTimeOut())); + m_pImpl->m_timer.start(60000); + } + + QxHttpSessionManager::~QxHttpSessionManager() { m_pImpl->m_timer.stop(); } + + void QxHttpSessionManager::deleteSession(qx::QxHttpSession *p) { delete p; } + + qx::QxHttpSession_ptr QxHttpSessionManager::getSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName /* = QByteArray("qx_session_id") */, bool autoCreateSession /* = true */) + { + return QxHttpSessionManager::getSingleton()->m_pImpl->getSession(request, response, cookieName, autoCreateSession); + } + + qx::QxHttpSession_ptr QxHttpSessionManager::createSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName /* = QByteArray("qx_session_id") */) + { + return QxHttpSessionManager::getSingleton()->m_pImpl->createSession(request, response, cookieName); + } + + void QxHttpSessionManager::removeSession(qx::QxHttpRequest &request, qx::QxHttpResponse &response, const QByteArray &cookieName /* = QByteArray("qx_session_id") */) + { + QxHttpSessionManager::getSingleton()->m_pImpl->removeSession(request, response, cookieName); + } + + void QxHttpSessionManager::onCheckSessionTimeOut() + { + QMutexLocker locker(&m_pImpl->m_mutex); + qlonglong lTimeOut = qx::service::QxConnect::getSingleton()->getSessionTimeOut(); + QMutableHashIterator itr(m_pImpl->m_sessions); + QDateTime dt = QDateTime::currentDateTime(); + + while (itr.hasNext()) + { + itr.next(); + qx::QxHttpSession_ptr session = itr.value(); + if (!session) + { + itr.remove(); + continue; + } + QDateTime lastAccess = session->lastAccess(); + if (!lastAccess.isValid()) + { + qAssert(false); + itr.remove(); + continue; + } + if (lastAccess.addMSecs(lTimeOut) < dt) + { + itr.remove(); + continue; + } + } + } + +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxHttpServer/QxHttpTransaction.cpp b/src/QxHttpServer/QxHttpTransaction.cpp new file mode 100644 index 0000000..a3cf074 --- /dev/null +++ b/src/QxHttpServer/QxHttpTransaction.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + + namespace compress + { + QByteArray to_gzip(const QByteArray &data); + quint32 crc32(const QByteArray &data); + } // namespace compress + + struct Q_DECL_HIDDEN QxHttpTransaction::QxHttpTransactionImpl + { + + qx::QxHttpRequest m_request; //!< HTTP transaction request + qx::QxHttpResponse m_response; //!< HTTP transaction response + QTcpSocket *m_socket; //!< HTTP transaction socket + bool m_headersWritten; //!< HTTP response headers already written (used to write chunked data) + bool m_chunkAllowed; //!< If we receive a HTTP 1.0 request, then chunked responses are not supported by client + + QxHttpTransactionImpl(QxHttpTransaction *parent) : m_request(parent), m_response(parent), m_socket(NULL), m_headersWritten(false), m_chunkAllowed(true) { qAssert(parent != NULL); } + ~QxHttpTransactionImpl() { ; } + + bool waitForReadSocket(QTcpSocket &socket) + { + if (socket.bytesAvailable() > 0) + { + return true; + } + long lMaxWait = qx::service::QxConnect::getSingleton()->getMaxWait(); + long lCurrRetry = 0; + do + { + if (socket.waitForReadyRead(1)) + { + return true; + } + if (socket.bytesAvailable() > 0) + { + return true; + } + QCoreApplication::processEvents(); + lCurrRetry++; + } while ((lMaxWait == -1) || (lCurrRetry < lMaxWait)); + return false; + } + + bool writeToSocket(QTcpSocket &socket, const QByteArray &data) + { + if (data.isEmpty()) + { + return true; + } + const char *pData = data.constData(); + qint64 iTotalWritten = 0; + qint64 iTotalToWrite = static_cast(data.count()); + while (iTotalWritten < iTotalToWrite) + { + qint64 iWritten = socket.write((pData + iTotalWritten), (iTotalToWrite - iTotalWritten)); + if (iWritten == -1) + { + break; + } + iTotalWritten += iWritten; + } + return (iTotalWritten == iTotalToWrite); + } + + qx_bool writeHeaders(QTcpSocket &socket) + { + // Check if headers/cookies has already been written + if (m_headersWritten) + { + return qx_bool(true); + } + m_headersWritten = true; + + // HTTP response first line + QByteArray line = "HTTP/1.1 " + QByteArray::number(m_response.status()) + " " + m_response.statusDesc() + "\r\n"; + if (!writeToSocket(socket, line)) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP response first line '" + line + "' (" + socket.errorString() + ")"); + } + + // HTTP response headers + QHashIterator itrHeaders(m_response.headers()); + while (itrHeaders.hasNext()) + { + itrHeaders.next(); + if (itrHeaders.key().trimmed().isEmpty()) + { + continue; + } + line = itrHeaders.key() + ": " + itrHeaders.value() + "\r\n"; + if (!writeToSocket(socket, line)) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP response header '" + line + "' (" + socket.errorString() + ")"); + } + } + + // HTTP response cookies + QHashIterator itrCookies(m_response.cookies()); + while (itrCookies.hasNext()) + { + itrCookies.next(); + if (itrCookies.value().name.trimmed().isEmpty()) + { + continue; + } + line = "Set-Cookie: " + itrCookies.value().toString() + "\r\n"; + if (!writeToSocket(socket, line)) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP response cookie '" + line + "' (" + socket.errorString() + ")"); + } + } + + // Empty line : means end of headers/cookies + if (!writeToSocket(socket, "\r\n")) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP response header end line (" + socket.errorString() + ")"); + } + return qx_bool(true); + } + }; + + QxHttpTransaction::QxHttpTransaction() : qx::service::QxTransaction(), m_pImpl(new QxHttpTransactionImpl(this)) { ; } + + QxHttpTransaction::~QxHttpTransaction() { ; } + + void QxHttpTransaction::clear() + { + qx::service::QxTransaction::clear(); + m_pImpl.reset(new QxHttpTransactionImpl(this)); + } + + qx::QxHttpRequest &QxHttpTransaction::request() { return m_pImpl->m_request; } + + qx::QxHttpResponse &QxHttpTransaction::response() { return m_pImpl->m_response; } + + void QxHttpTransaction::executeServer() + { + if (getMessageReturn()) + { + Q_EMIT onCustomRequestHandler(); + } + } + + qx_bool QxHttpTransaction::writeSocketServer(QTcpSocket &socket) + { + // Check HTTP transaction message return + qx_bool bTransactionMsg = getMessageReturn(); + if (!bTransactionMsg) + { + m_pImpl->m_response.headers().insert("Content-Type", "text/plain; charset=utf-8"); + m_pImpl->m_response.status() = static_cast(bTransactionMsg.getCode()); + m_pImpl->m_response.data() = bTransactionMsg.getDesc().toUtf8(); + } + + // Check if we can compress response data + bool chunked = (m_pImpl->m_response.isChunked() && m_pImpl->m_chunkAllowed); + bool compress = qx::service::QxConnect::getSingleton()->getCompressData(); + QString contentType = m_pImpl->m_response.header("Content-Type").toLower(); + compress = (compress && (contentType.startsWith("text/") || contentType.startsWith("application/json") || contentType.startsWith("application/javascript"))); + compress = (compress && (m_pImpl->m_request.header("Accept-Encoding").toLower().contains("gzip"))); + compress = (compress && (m_pImpl->m_response.data().size() > 99)); + compress = (compress && (m_pImpl->m_response.status() == 200)); + compress = (compress && (!chunked)); + + // Compress response data + if (compress) + { + m_pImpl->m_response.headers().insert("Content-Encoding", "gzip"); + m_pImpl->m_response.data() = qx::compress::to_gzip(m_pImpl->m_response.data()); + } + + // Insert 'Content-Length' header + QByteArray &body = m_pImpl->m_response.data(); + QByteArray contentLength = QByteArray::number(body.count()); + if (!chunked) + { + m_pImpl->m_response.headers().insert("Content-Length", contentLength); + } + + // Check if we have to force to close connection + if (m_pImpl->m_request.header("Connection").toLower() == "close") + { + setForceConnectionStatus(qx::service::QxTransaction::conn_close); + } + + // HTTP response headers and cookies + qx_bool bWriteHeaders = m_pImpl->writeHeaders(socket); + if (!bWriteHeaders) + { + return bWriteHeaders; + } + + // HTTP response body content + if (chunked) + { + if (!m_pImpl->writeToSocket(socket, "0\r\n\r\n")) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP last empty chunked data (" + socket.errorString() + ")"); + } + } + else if (!m_pImpl->writeToSocket(socket, body)) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP response body content of " + QString::number(body.count()) + " bytes (" + socket.errorString() + ")"); + } + return qx_bool(true); + } + + qx_bool QxHttpTransaction::readSocketServer(QTcpSocket &socket) + { + // Fetch source client details + setIpSource(socket.peerAddress().toString()); + setPortSource(static_cast(socket.peerPort())); + m_pImpl->m_request.sourceAddress() = socket.peerAddress().toString(); + m_pImpl->m_request.sourcePort() = static_cast(socket.peerPort()); + m_pImpl->m_socket = (&socket); + + // HTTP request first line + setMessageReturn(qx_bool(true)); + if (!m_pImpl->waitForReadSocket(socket)) + { + setMessageReturn(qx_bool(500, "Internal server error : cannot read socket to parse HTTP request first line (" + socket.errorString() + ")")); + return qx_bool(true); + } + QByteArray line = socket.readLine().trimmed(); + QStringList lst = QString::fromUtf8(line).split(" "); + if (lst.count() < 3) + { + QString errMsg = ("Bad request : invalid HTTP request first line : " + line); + setMessageReturn(qx_bool(400, errMsg)); + return qx_bool(true); + } + if (!lst.at(2).contains("HTTP")) + { + QString errMsg = ("Bad request : invalid HTTP request first line, third parameter must contain 'HTTP' : " + line); + setMessageReturn(qx_bool(400, errMsg)); + return qx_bool(true); + } + m_pImpl->m_request.command() = lst.at(0).toUpper(); + m_pImpl->m_request.url() = QUrl(lst.at(1)); + m_pImpl->m_request.version() = lst.at(2); + + // HTTP request headers and cookies + int iContentLength = 0; + do + { + if (!m_pImpl->waitForReadSocket(socket)) + { + setMessageReturn(qx_bool(500, "Internal server error : cannot read socket to parse HTTP headers (" + socket.errorString() + ")")); + return qx_bool(true); + } + line = socket.readLine().trimmed(); + if (line.isEmpty()) + { + break; + } + int pos = line.indexOf(':'); + if (pos <= 0) + { + QString errMsg = ("Bad request : invalid HTTP header : " + line); + setMessageReturn(qx_bool(400, errMsg)); + return qx_bool(true); + } + QByteArray key = line.left(pos).trimmed(); + QByteArray value = line.mid(pos + 1).trimmed(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + if (key.toLower() == "cookie") + { + m_pImpl->m_request.cookies().insert(QxHttpCookie::parse(value)); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + if (key.toLower() == "cookie") + { + m_pImpl->m_request.cookies().unite(QxHttpCookie::parse(value)); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + else + { + m_pImpl->m_request.headers().insert(key, value); + } + if (key.toLower() == "content-length") + { + iContentLength = value.toInt(); + } + } while (1); + + // Check HTTP 1.0 compatibility + if (m_pImpl->m_request.version().contains("1.0")) + { + m_pImpl->m_chunkAllowed = false; + if (m_pImpl->m_request.header("Connection").toLower() != "keep-alive") + { + setForceConnectionStatus(qx::service::QxTransaction::conn_close); + } + } + + QByteArray body; + if (iContentLength > 0) + { + // HTTP request body content + body.reserve(iContentLength); + do + { + if (!m_pImpl->waitForReadSocket(socket)) + { + setMessageReturn(qx_bool(500, "Internal server error : cannot read socket to get HTTP body content (" + socket.errorString() + ")")); + return qx_bool(true); + } + body += socket.readAll(); + } while (body.count() < iContentLength); + m_pImpl->m_request.data() = body; + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QByteArray params = m_pImpl->m_request.url().query(QUrl::FullyEncoded).toLatin1(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QByteArray params = m_pImpl->m_request.url().encodedQuery(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + // HTTP request parameters (from URL and from body if content-type is 'application/x-www-form-urlencoded', which means web-form submit) + if ((!body.isEmpty()) && (m_pImpl->m_request.header("content-type").toLower() == "application/x-www-form-urlencoded")) + { + params += (params.isEmpty() ? QByteArray() : QByteArray("&")) + body; + } + QList listParams = params.split('&'); + Q_FOREACH (QByteArray param, listParams) + { + int pos = param.indexOf('='); + if (pos > 0) + { + QByteArray key = param.left(pos).trimmed(); + QByteArray value = param.mid(pos + 1).trimmed(); + m_pImpl->m_request.params().insert(QUrl::fromPercentEncoding(key), QUrl::fromPercentEncoding(value)); + } + else if (!param.isEmpty()) + { + m_pImpl->m_request.params().insert(QUrl::fromPercentEncoding(param), ""); + } + } + + return qx_bool(true); + } + + qx_bool QxHttpTransaction::writeChunked(const QByteArray &data) + { + // Check input data + if (data.isEmpty()) + { + return qx_bool(true); + } + if (!m_pImpl->m_socket) + { + return qx_bool(false, "No socket to write HTTP chunked data"); + } + if (!m_pImpl->m_chunkAllowed) + { + m_pImpl->m_response.data() += data; + return qx_bool(true); + } + + // HTTP response headers and cookies + if (!m_pImpl->m_headersWritten) + { + m_pImpl->m_response.headers().insert("Transfer-Encoding", "chunked"); + qx_bool bWriteHeaders = m_pImpl->writeHeaders(*m_pImpl->m_socket); + if (!bWriteHeaders) + { + return bWriteHeaders; + } + } + + // Write chunked data + QByteArray chunked = (QByteArray::number(data.count(), 16) + "\r\n" + data + "\r\n"); + if (!m_pImpl->writeToSocket((*m_pImpl->m_socket), chunked)) + { + return qx_bool(500, "Internal server error : cannot write to socket HTTP chunked data of " + QString::number(data.count()) + " bytes (" + m_pImpl->m_socket->errorString() + ")"); + } + return qx_bool(true); + } + + namespace compress + { + + // Code from : https://stackoverflow.com/questions/20734831/compress-string-with-gzip-using-qcompress + QByteArray to_gzip(const QByteArray &data) + { + QByteArray compressedData = qCompress(data); + compressedData.remove(0, 6); + compressedData.chop(4); + + QByteArray header; + QDataStream ds1(&header, QIODevice::WriteOnly); + ds1 << quint16(0x1f8b) << quint16(0x0800) << quint16(0x0000) << quint16(0x0000) << quint16(0x000b); + + QByteArray footer; + QDataStream ds2(&footer, QIODevice::WriteOnly); + ds2.setByteOrder(QDataStream::LittleEndian); + ds2 << qx::compress::crc32(data) << quint32(data.size()); + + return (header + compressedData + footer); + } + + static const quint32 crc32_tab[] = {/* CRC polynomial 0xedb88320 */ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + + quint32 update_crc32(unsigned char ch, quint32 crc) + { + return (crc32_tab[((crc) ^ ((quint8)ch)) & 0xff] ^ ((crc) >> 8)); + } + + quint32 crc32(const QByteArray &data) + { + quint32 crc = 0xFFFFFFFFL; + for (int i = 0; i < data.size(); i++) + { + crc = update_crc32(data[i], crc); + } + return ~crc; + } + + } // namespace compress +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxMemLeak/bool_array.cpp b/src/QxMemLeak/bool_array.cpp new file mode 100644 index 0000000..b1120b5 --- /dev/null +++ b/src/QxMemLeak/bool_array.cpp @@ -0,0 +1,228 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/** + * @file bool_array.cpp + * + * Code for class bool_array (packed boolean array). + * + * @version 3.1, 2005/08/25 + * @author Wu Yongwei + * + */ + +#include + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#include +#include + +#include + +namespace qx { +namespace memory { + +BYTE bool_array::_S_bit_count[256] = +{ + 0, /* 0 */ 1, /* 1 */ 1, /* 2 */ 2, /* 3 */ 1, /* 4 */ + 2, /* 5 */ 2, /* 6 */ 3, /* 7 */ 1, /* 8 */ 2, /* 9 */ + 2, /* 10 */ 3, /* 11 */ 2, /* 12 */ 3, /* 13 */ 3, /* 14 */ + 4, /* 15 */ 1, /* 16 */ 2, /* 17 */ 2, /* 18 */ 3, /* 19 */ + 2, /* 20 */ 3, /* 21 */ 3, /* 22 */ 4, /* 23 */ 2, /* 24 */ + 3, /* 25 */ 3, /* 26 */ 4, /* 27 */ 3, /* 28 */ 4, /* 29 */ + 4, /* 30 */ 5, /* 31 */ 1, /* 32 */ 2, /* 33 */ 2, /* 34 */ + 3, /* 35 */ 2, /* 36 */ 3, /* 37 */ 3, /* 38 */ 4, /* 39 */ + 2, /* 40 */ 3, /* 41 */ 3, /* 42 */ 4, /* 43 */ 3, /* 44 */ + 4, /* 45 */ 4, /* 46 */ 5, /* 47 */ 2, /* 48 */ 3, /* 49 */ + 3, /* 50 */ 4, /* 51 */ 3, /* 52 */ 4, /* 53 */ 4, /* 54 */ + 5, /* 55 */ 3, /* 56 */ 4, /* 57 */ 4, /* 58 */ 5, /* 59 */ + 4, /* 60 */ 5, /* 61 */ 5, /* 62 */ 6, /* 63 */ 1, /* 64 */ + 2, /* 65 */ 2, /* 66 */ 3, /* 67 */ 2, /* 68 */ 3, /* 69 */ + 3, /* 70 */ 4, /* 71 */ 2, /* 72 */ 3, /* 73 */ 3, /* 74 */ + 4, /* 75 */ 3, /* 76 */ 4, /* 77 */ 4, /* 78 */ 5, /* 79 */ + 2, /* 80 */ 3, /* 81 */ 3, /* 82 */ 4, /* 83 */ 3, /* 84 */ + 4, /* 85 */ 4, /* 86 */ 5, /* 87 */ 3, /* 88 */ 4, /* 89 */ + 4, /* 90 */ 5, /* 91 */ 4, /* 92 */ 5, /* 93 */ 5, /* 94 */ + 6, /* 95 */ 2, /* 96 */ 3, /* 97 */ 3, /* 98 */ 4, /* 99 */ + 3, /* 100 */ 4, /* 101 */ 4, /* 102 */ 5, /* 103 */ 3, /* 104 */ + 4, /* 105 */ 4, /* 106 */ 5, /* 107 */ 4, /* 108 */ 5, /* 109 */ + 5, /* 110 */ 6, /* 111 */ 3, /* 112 */ 4, /* 113 */ 4, /* 114 */ + 5, /* 115 */ 4, /* 116 */ 5, /* 117 */ 5, /* 118 */ 6, /* 119 */ + 4, /* 120 */ 5, /* 121 */ 5, /* 122 */ 6, /* 123 */ 5, /* 124 */ + 6, /* 125 */ 6, /* 126 */ 7, /* 127 */ 1, /* 128 */ 2, /* 129 */ + 2, /* 130 */ 3, /* 131 */ 2, /* 132 */ 3, /* 133 */ 3, /* 134 */ + 4, /* 135 */ 2, /* 136 */ 3, /* 137 */ 3, /* 138 */ 4, /* 139 */ + 3, /* 140 */ 4, /* 141 */ 4, /* 142 */ 5, /* 143 */ 2, /* 144 */ + 3, /* 145 */ 3, /* 146 */ 4, /* 147 */ 3, /* 148 */ 4, /* 149 */ + 4, /* 150 */ 5, /* 151 */ 3, /* 152 */ 4, /* 153 */ 4, /* 154 */ + 5, /* 155 */ 4, /* 156 */ 5, /* 157 */ 5, /* 158 */ 6, /* 159 */ + 2, /* 160 */ 3, /* 161 */ 3, /* 162 */ 4, /* 163 */ 3, /* 164 */ + 4, /* 165 */ 4, /* 166 */ 5, /* 167 */ 3, /* 168 */ 4, /* 169 */ + 4, /* 170 */ 5, /* 171 */ 4, /* 172 */ 5, /* 173 */ 5, /* 174 */ + 6, /* 175 */ 3, /* 176 */ 4, /* 177 */ 4, /* 178 */ 5, /* 179 */ + 4, /* 180 */ 5, /* 181 */ 5, /* 182 */ 6, /* 183 */ 4, /* 184 */ + 5, /* 185 */ 5, /* 186 */ 6, /* 187 */ 5, /* 188 */ 6, /* 189 */ + 6, /* 190 */ 7, /* 191 */ 2, /* 192 */ 3, /* 193 */ 3, /* 194 */ + 4, /* 195 */ 3, /* 196 */ 4, /* 197 */ 4, /* 198 */ 5, /* 199 */ + 3, /* 200 */ 4, /* 201 */ 4, /* 202 */ 5, /* 203 */ 4, /* 204 */ + 5, /* 205 */ 5, /* 206 */ 6, /* 207 */ 3, /* 208 */ 4, /* 209 */ + 4, /* 210 */ 5, /* 211 */ 4, /* 212 */ 5, /* 213 */ 5, /* 214 */ + 6, /* 215 */ 4, /* 216 */ 5, /* 217 */ 5, /* 218 */ 6, /* 219 */ + 5, /* 220 */ 6, /* 221 */ 6, /* 222 */ 7, /* 223 */ 3, /* 224 */ + 4, /* 225 */ 4, /* 226 */ 5, /* 227 */ 4, /* 228 */ 5, /* 229 */ + 5, /* 230 */ 6, /* 231 */ 4, /* 232 */ 5, /* 233 */ 5, /* 234 */ + 6, /* 235 */ 5, /* 236 */ 6, /* 237 */ 6, /* 238 */ 7, /* 239 */ + 4, /* 240 */ 5, /* 241 */ 5, /* 242 */ 6, /* 243 */ 5, /* 244 */ + 6, /* 245 */ 6, /* 246 */ 7, /* 247 */ 5, /* 248 */ 6, /* 249 */ + 6, /* 250 */ 7, /* 251 */ 6, /* 252 */ 7, /* 253 */ 7, /* 254 */ + 8 /* 255 */ +}; // End _S_bit_count + +/** + * Creates the packed boolean array with a specific size. + * + * @param __size size of the array + * @return \c false if \a __size equals \c 0 or is too big, or + * if memory is insufficient; \c true if \a __size has + * a suitable value and memory allocation is + * successful. + */ +bool bool_array::create(unsigned long __size) +{ + if (__size == 0) + return false; + // Will be optimized away by a decent compiler if ULONG_MAX == UINT_MAX + if (ULONG_MAX > UINT_MAX && ((__size - 1) / 8 + 1) > UINT_MAX) + return false; + + size_t __byte_cnt = (size_t)((__size - 1) / 8 + 1); + if (_M_byte_ptr) + free(_M_byte_ptr); + _M_length = 0; + + // Uses malloc/free instead of new/delete to avoid exception handling + // differences between compilers + if (!(_M_byte_ptr = (BYTE*)malloc(__byte_cnt))) + return false; + + _M_length = __size; + return true; +} + +/** + * Initializes all array elements to a specific value optimally. + * + * @param ___value the boolean value to assign to all elements + */ +void bool_array::initialize(bool ___value) +{ + assert(_M_byte_ptr); + size_t __byte_cnt = (size_t)((_M_length - 1) / 8) + 1; + memset(_M_byte_ptr, ___value ? ~0 : 0, __byte_cnt); + if (___value) + { + int __valid_bits_in_last_byte = (_M_length - 1) % 8 + 1; + _M_byte_ptr[__byte_cnt - 1] &= ~(~0 << __valid_bits_in_last_byte); + } +} + +/** + * Counts elements with a \c true value. + * + * @return the count of \c true elements + */ +unsigned long bool_array::count() const +{ + assert(_M_byte_ptr); + unsigned long __true_cnt = 0; + size_t __byte_cnt = (size_t)((_M_length - 1) / 8) + 1; + for (size_t __i = 0; __i < __byte_cnt; ++__i) + __true_cnt += _S_bit_count[_M_byte_ptr[__i]]; + return __true_cnt; +} + +/** + * Counts elements with a \c true value in a specified range. + * + * @param __beg beginning of the range + * @param __end end of the range (exclusive) + * @return the count of \c true elements + */ +unsigned long bool_array::count(unsigned long __beg, unsigned long __end) const +{ + assert(_M_byte_ptr); + unsigned long __true_cnt = 0; + size_t __byte_idx_beg, __byte_idx_end; + BYTE __byte_val; + + if (__beg >= __end) + return 0; + if (__end > _M_length) + throw std::out_of_range("invalid bool_array subscript"); + --__end; + + __byte_idx_beg = (size_t)(__beg / 8); + __byte_val = _M_byte_ptr[__byte_idx_beg]; + __byte_val &= ~0 << (__beg % 8); + + __byte_idx_end = (size_t)(__end / 8); + if (__byte_idx_beg < __byte_idx_end) + { + __true_cnt = _S_bit_count[__byte_val]; + __byte_val = _M_byte_ptr[__byte_idx_end]; + } + __byte_val &= ~(~0 << (__end % 8 + 1)); + __true_cnt += _S_bit_count[__byte_val]; + + for (++__byte_idx_beg; __byte_idx_beg < __byte_idx_end; ++__byte_idx_beg) + __true_cnt += _S_bit_count[_M_byte_ptr[__byte_idx_beg]]; + return __true_cnt; +} + +/** + * Changes all \c true elements to \c false, and \c false ones to \c true. + */ +void bool_array::flip() +{ + assert(_M_byte_ptr); + size_t __byte_cnt = (size_t)((_M_length - 1) / 8) + 1; + for (size_t __i = 0; __i < __byte_cnt; ++__i) + _M_byte_ptr[__i] = ~_M_byte_ptr[__i]; + int __valid_bits_in_last_byte = (_M_length - 1) % 8 + 1; + _M_byte_ptr[__byte_cnt - 1] &= ~(~0 << __valid_bits_in_last_byte); +} + +} // namespace memory +} // namespace qx + +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/src/QxMemLeak/debug_new.cpp b/src/QxMemLeak/debug_new.cpp new file mode 100644 index 0000000..295343f --- /dev/null +++ b/src/QxMemLeak/debug_new.cpp @@ -0,0 +1,618 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/** + * @file debug_new.cpp + * + * Implementation of debug versions of new and delete to check leakage. + * + * @version 4.14, 2008/10/20 + * @author Wu Yongwei + * + */ + +#include +#include + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __unix__ +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#include + +#include +#include + +#ifndef _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE +#define _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE 0 +#endif // _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE + +#if !_FAST_MUTEX_CHECK_INITIALIZATION && !defined(_NOTHREADS) +#error "_FAST_MUTEX_CHECK_INITIALIZATION not set: check_leaks may not work" +#endif + +/** + * @def _DEBUG_NEW_ALIGNMENT + * + * The alignment requirement of allocated memory blocks. It must be a + * power of two. + */ +#ifndef _DEBUG_NEW_ALIGNMENT +#define _DEBUG_NEW_ALIGNMENT 16 +#endif + +/** + * @def _DEBUG_NEW_ERROR_ACTION + * + * The action to take when an error occurs. The default behaviour is to + * call \e abort, unless \c _DEBUG_NEW_ERROR_CRASH is defined, in which + * case a segmentation fault will be triggered instead (which can be + * useful on platforms like Windows that do not generate a core dump + * when \e abort is called). + */ +#ifndef _DEBUG_NEW_ERROR_ACTION +#ifndef _DEBUG_NEW_ERROR_CRASH +#define _DEBUG_NEW_ERROR_ACTION abort() +#else +#define _DEBUG_NEW_ERROR_ACTION do { *((char*)0) = 0; abort(); } while (0) +#endif +#endif + +/** + * @def _DEBUG_NEW_FILENAME_LEN + * + * The length of file name stored if greater than zero. If it is zero, + * only a const char pointer will be stored. Currently the default + * behaviour is to copy the file name, because I found that the exit + * leakage check cannot access the address of the file name sometimes + * (in my case, a core dump will occur when trying to access the file + * name in a shared library after a \c SIGINT). The current default + * value makes the size of new_ptr_list_t 64 on 32-bit platforms. + */ +#ifndef _DEBUG_NEW_FILENAME_LEN +#define _DEBUG_NEW_FILENAME_LEN 44 +#endif + +/** + * @def _DEBUG_NEW_PROGNAME + * + * The program (executable) name to be set at compile time. It is + * better to assign the full program path to #new_progname in \e main + * (at run time) than to use this (compile-time) macro, but this macro + * serves well as a quick hack. Note also that double quotation marks + * need to be used around the program name, i.e., one should specify a + * command-line option like -D_DEBUG_NEW_PROGNAME=\"a.out\" + * in \e bash, or -D_DEBUG_NEW_PROGNAME=\"a.exe\" in the + * Windows command prompt. + */ +#ifndef _DEBUG_NEW_PROGNAME +#define _DEBUG_NEW_PROGNAME NULL +#endif + +/** + * @def _DEBUG_NEW_STD_OPER_NEW + * + * Macro to indicate whether the standard-conformant behaviour of + * operator new is wanted. It is on by default now, but + * the user may set it to \c 0 to revert to the old behaviour. + */ +#ifndef _DEBUG_NEW_STD_OPER_NEW +#define _DEBUG_NEW_STD_OPER_NEW 1 +#endif + +/** + * @def _DEBUG_NEW_TAILCHECK + * + * Macro to indicate whether a writing-past-end check will be performed. + * Define it to a positive integer as the number of padding bytes at the + * end of a memory block for checking. + */ +#ifndef _DEBUG_NEW_TAILCHECK +#define _DEBUG_NEW_TAILCHECK 0 +#endif + +/** + * @def _DEBUG_NEW_TAILCHECK_CHAR + * + * Value of the padding bytes at the end of a memory block. + */ +#ifndef _DEBUG_NEW_TAILCHECK_CHAR +#define _DEBUG_NEW_TAILCHECK_CHAR 0xCC +#endif + +/** + * @def _DEBUG_NEW_USE_ADDR2LINE + * + * Whether to use \e addr2line to convert a caller address to file/line + * information. Defining it to a non-zero value will enable the + * conversion (automatically done if GCC is detected). Defining it to + * zero will disable the conversion. + */ +#ifndef _DEBUG_NEW_USE_ADDR2LINE +#ifdef __GNUC__ +#define _DEBUG_NEW_USE_ADDR2LINE 1 +#else +#define _DEBUG_NEW_USE_ADDR2LINE 0 +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(disable: 4073) // #pragma init_seg(lib) used +#pragma warning(disable: 4290) // C++ exception specification ignored +#pragma init_seg(lib) +#endif + +#undef _DEBUG_NEW_EMULATE_MALLOC +#undef _DEBUG_NEW_REDEFINE_NEW +/** + * Macro to indicate whether redefinition of \c new is wanted. Here it + * is defined to \c 0 to disable the redefinition of \c new. + */ +#define _DEBUG_NEW_REDEFINE_NEW 0 +#include + +/** + * Gets the aligned value of memory block size. + */ +#define align(s) \ + (((s) + _DEBUG_NEW_ALIGNMENT - 1) & ~(_DEBUG_NEW_ALIGNMENT - 1)) + +namespace qx { +namespace memory { + +/** + * Structure to store the position information where \c new occurs. + */ +struct new_ptr_list_t +{ + new_ptr_list_t* next; + new_ptr_list_t* prev; + size_t size; + union + { +#if _DEBUG_NEW_FILENAME_LEN == 0 + const char* file; +#else + char file[_DEBUG_NEW_FILENAME_LEN]; +#endif + void* addr; + }; + unsigned line :31; + unsigned is_array :1; + unsigned magic; +}; + +/** + * Magic number for error detection. + */ +const unsigned MAGIC = 0x4442474E; + +/** + * The extra memory allocated by operator new. + */ +const int ALIGNED_LIST_ITEM_SIZE = align(sizeof(new_ptr_list_t)); + +/** + * List of all new'd pointers. + */ +static new_ptr_list_t new_ptr_list = { + &new_ptr_list, + &new_ptr_list, + 0, + { +#if _DEBUG_NEW_FILENAME_LEN == 0 + NULL +#else + "" +#endif + }, + 0, + 0, + MAGIC +}; + +/** + * The mutex guard to protect simultaneous access to the pointer list. + */ +static fast_mutex new_ptr_lock; + +/** + * The mutex guard to protect simultaneous output to #new_output_fp. + */ +static fast_mutex new_output_lock; + +/** + * Total memory allocated in bytes. + */ +static size_t total_mem_alloc = 0; + +/** + * Flag to control whether #check_leaks will be automatically called on + * program exit. + */ +bool new_autocheck_flag = true; + +/** + * Flag to control whether verbose messages are output. + */ +bool new_verbose_flag = false; + +/** + * Pointer to the output stream. The default output is \e stderr, and + * one may change it to a user stream if needed (say, #new_verbose_flag + * is \c true and there are a lot of (de)allocations). + */ +FILE* new_output_fp = stderr; + +/** + * Pointer to the program name. Its initial value is the macro + * #_DEBUG_NEW_PROGNAME. You should try to assign the program path to + * it early in your application. Assigning argv[0] to it + * in \e main is one way. If you use \e bash or \e ksh (or similar), + * the following statement is probably what you want: + * `new_progname = getenv("_");'. + */ +const char* new_progname = _DEBUG_NEW_PROGNAME; + +#if _DEBUG_NEW_TAILCHECK +/** + * Checks whether the padding bytes at the end of a memory block is + * tampered with. + * + * @param ptr pointer to a new_ptr_list_t struct + * @return \c true if the padding bytes are untouched; \c false + * otherwise + */ +static bool check_tail(new_ptr_list_t* ptr) +{ + const unsigned char* const pointer = (unsigned char*)ptr + + ALIGNED_LIST_ITEM_SIZE + ptr->size; + for (int i = 0; i < _DEBUG_NEW_TAILCHECK; ++i) + if (pointer[i] != _DEBUG_NEW_TAILCHECK_CHAR) + return false; + return true; +} +#endif + +/** + * Allocates memory and initializes control data. + * + * @param size size of the required memory block + * @param file null-terminated string of the file name + * @param line line number + * @param is_array boolean value whether this is an array operation + * @return pointer to the user-requested memory area; \c NULL + * if memory allocation is not successful + */ +static void* alloc_mem(size_t size, const char* file, int line, bool is_array) +{ + assert(line >= 0); + STATIC_ASSERT((_DEBUG_NEW_ALIGNMENT & (_DEBUG_NEW_ALIGNMENT - 1)) == 0, Alignment_must_be_power_of_two); + STATIC_ASSERT(_DEBUG_NEW_TAILCHECK >= 0, Invalid_tail_check_length); + size_t s = size + ALIGNED_LIST_ITEM_SIZE + _DEBUG_NEW_TAILCHECK; + new_ptr_list_t* ptr = (new_ptr_list_t*)malloc(s); + if (ptr == NULL) + { +#if _DEBUG_NEW_STD_OPER_NEW + return NULL; +#else + fast_mutex_autolock lock(new_output_lock); + qDebug("[QxOrm] Out of memory when allocating %u bytes", size); + fflush(new_output_fp); + _DEBUG_NEW_ERROR_ACTION; +#endif + } + void* pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; +#if _DEBUG_NEW_FILENAME_LEN == 0 + ptr->file = file; +#else + if (line) + { + QX_STRNCPY(ptr->file, file, _DEBUG_NEW_FILENAME_LEN - 1); + ptr->file[_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; + } + else + ptr->addr = (void*)file; +#endif + ptr->line = line; + ptr->is_array = is_array; + ptr->size = size; + ptr->magic = MAGIC; + { + fast_mutex_autolock lock(new_ptr_lock); + ptr->prev = new_ptr_list.prev; + ptr->next = &new_ptr_list; + new_ptr_list.prev->next = ptr; + new_ptr_list.prev = ptr; + } +#if _DEBUG_NEW_TAILCHECK + memset((char*)pointer + size, _DEBUG_NEW_TAILCHECK_CHAR, + _DEBUG_NEW_TAILCHECK); +#endif + if (new_verbose_flag) + { + fast_mutex_autolock lock(new_output_lock); + const char * msg_out_file = "[QxOrm] new%s: allocated %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); + const char * msg_out_no_file = "[QxOrm] new%s: allocated %p (size %u, )"; Q_UNUSED(msg_out_no_file); + if (line != 0) { qDebug(msg_out_file, (is_array ? "[]" : ""), pointer, size, ptr->file, ptr->line); } +#if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + else { qDebug(msg_out_no_file, (is_array ? "[]" : ""), pointer, size); } +#endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + } + total_mem_alloc += size; + return pointer; +} + +/** + * Frees memory and adjusts pointers. + * + * @param pointer pointer to delete + * @param addr pointer to the caller + * @param is_array flag indicating whether it is invoked by a + * delete[] call + */ +void __debug_new_recorder::free_pointer(void* pointer, void* addr, bool is_array) +{ + if (pointer == NULL) { return; } + new_ptr_list_t* ptr = (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); + if (ptr->magic != MAGIC) + { + { + fast_mutex_autolock lock(new_output_lock); + const char * msg_out = "[QxOrm] delete%s: invalid pointer %p"; Q_UNUSED(msg_out); + qDebug(msg_out, (is_array ? "[]" : ""), pointer); + } + check_mem_corruption(); + fflush(new_output_fp); + _DEBUG_NEW_ERROR_ACTION; + } + if (is_array != ptr->is_array) + { + const char * msg; + if (is_array) { msg = "[QxOrm] delete[] after new"; } + else { msg = "[QxOrm] delete after new[]"; } + fast_mutex_autolock lock(new_output_lock); + const char * msg_out_file = "[QxOrm] %s: pointer %p (size %u)\n\tat %p\n\toriginally allocated at %s:%d"; Q_UNUSED(msg_out_file); + const char * msg_out_no_file = "[QxOrm] %s: pointer %p (size %u)\n\tat %p\n\toriginally allocated at "; Q_UNUSED(msg_out_no_file); + if (ptr->line != 0) { qDebug(msg_out_file, msg, ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, addr, ptr->file, ptr->line); } +#if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + else { qDebug(msg_out_no_file, msg, ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, addr); } +#endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + fflush(new_output_fp); + _DEBUG_NEW_ERROR_ACTION; + } +#if _DEBUG_NEW_TAILCHECK + if (!check_tail(ptr)) + { + check_mem_corruption(); + fflush(new_output_fp); + _DEBUG_NEW_ERROR_ACTION; + } +#endif + { + fast_mutex_autolock lock(new_ptr_lock); + total_mem_alloc -= ptr->size; + ptr->magic = 0; + ptr->prev->next = ptr->next; + ptr->next->prev = ptr->prev; + } + if (new_verbose_flag) + { + fast_mutex_autolock lock(new_output_lock); + const char * msg_out = "[QxOrm] delete%s: freed %p (size %u, %u bytes still allocated)"; Q_UNUSED(msg_out); + qDebug(msg_out, (is_array ? "[]" : ""), ((char*)ptr + ALIGNED_LIST_ITEM_SIZE), ptr->size, total_mem_alloc); + } + free(ptr); + return; +} + +/** + * Checks for memory leaks. + * + * @return zero if no leakage is found; the number of leaks otherwise + */ +int check_leaks() +{ + int leak_cnt = 0; + fast_mutex_autolock lock_ptr(new_ptr_lock); + fast_mutex_autolock lock_output(new_output_lock); + new_ptr_list_t* ptr = new_ptr_list.next; + while (ptr != &new_ptr_list) + { + const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; + if (ptr->magic != MAGIC) + { + const char * msg_out = "[QxOrm] warning: heap data corrupt near %p"; Q_UNUSED(msg_out); + qDebug(msg_out, pointer); + } +#if _DEBUG_NEW_TAILCHECK + if (!check_tail(ptr)) + { + const char * msg_out = "[QxOrm] warning: overwritten past end of object at %p"; Q_UNUSED(msg_out); + qDebug(msg_out, pointer); + } +#endif + const char * msg_out_file = "[QxOrm] Leaked object at %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); + const char * msg_out_no_file = "[QxOrm] Leaked object at %p (size %u, )"; Q_UNUSED(msg_out_no_file); + if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++leak_cnt; } +#if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + else { qDebug(msg_out_no_file, pointer, ptr->size); ++leak_cnt; } +#endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + ptr = ptr->next; + } + if (new_verbose_flag || leak_cnt) + { + const char * msg_out_leak_cnt = "[QxOrm] **** %d memory leaks found ****"; Q_UNUSED(msg_out_leak_cnt); + qDebug(msg_out_leak_cnt, leak_cnt); + } + return leak_cnt; +} + +/** + * Checks for heap corruption. + * + * @return zero if no problem is found; the number of found memory + * corruptions otherwise + */ +int check_mem_corruption() +{ + int corrupt_cnt = 0; + fast_mutex_autolock lock_ptr(new_ptr_lock); + fast_mutex_autolock lock_output(new_output_lock); + const char * msg_out_check_mem_start = "[QxOrm] **** Checking for memory corruption: START ****"; Q_UNUSED(msg_out_check_mem_start); + qDebug("%s", msg_out_check_mem_start); + for (new_ptr_list_t* ptr = new_ptr_list.next; ptr != &new_ptr_list; ptr = ptr->next) + { + const char* const pointer = (char*)ptr + ALIGNED_LIST_ITEM_SIZE; + if (ptr->magic == MAGIC +#if _DEBUG_NEW_TAILCHECK + && check_tail(ptr) +#endif + ) + continue; +#if _DEBUG_NEW_TAILCHECK + if (ptr->magic != MAGIC) + { +#endif + const char * msg_out_file = "[QxOrm] Heap data corrupt near %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); + const char * msg_out_no_file = "[QxOrm] Heap data corrupt near %p (size %u, )"; Q_UNUSED(msg_out_no_file); + if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++corrupt_cnt; } +#if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + else { qDebug(msg_out_no_file, pointer, ptr->size); ++corrupt_cnt; } +#endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) +#if _DEBUG_NEW_TAILCHECK + } + else + { + const char * msg_out_file = "[QxOrm] Overwritten past end of object at %p (size %u, %s:%d)"; Q_UNUSED(msg_out_file); + const char * msg_out_no_file = "[QxOrm] Overwritten past end of object at %p (size %u, )"; Q_UNUSED(msg_out_no_file); + if (ptr->line != 0) { qDebug(msg_out_file, pointer, ptr->size, ptr->file, ptr->line); ++corrupt_cnt; } +#if (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + else { qDebug(msg_out_no_file, pointer, ptr->size); ++corrupt_cnt; } +#endif // (! _QX_MEM_LEAK_ONLY_KNOWN_SRC_FILE) + } +#endif + } + const char * msg_out_check_mem_end = "[QxOrm] **** Checking for memory corruption: %d FOUND ****"; Q_UNUSED(msg_out_check_mem_end); + qDebug(msg_out_check_mem_end, corrupt_cnt); + return corrupt_cnt; +} + +void __debug_new_recorder::_M_process(void* pointer) +{ + if (pointer == NULL) { return; } + new_ptr_list_t* ptr = (new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE); + if (ptr->magic != MAGIC || ptr->line != 0) + { + fast_mutex_autolock lock(new_output_lock); + const char * msg_out = "[QxOrm] warning: debug_new used with placement new (%s:%d)"; Q_UNUSED(msg_out); + qDebug(msg_out, _M_file, _M_line); + return; + } +#if _DEBUG_NEW_FILENAME_LEN == 0 + ptr->file = _M_file; +#else + QX_STRNCPY(ptr->file, _M_file, _DEBUG_NEW_FILENAME_LEN - 1); + ptr->file[_DEBUG_NEW_FILENAME_LEN - 1] = '\0'; +#endif + ptr->line = _M_line; +} + +int __debug_new_counter::_S_count = 0; +__debug_new_counter::__debug_new_counter() { ++_S_count; } +__debug_new_counter::~__debug_new_counter() { if ((--_S_count == 0) && new_autocheck_flag) { check_leaks(); } } + +} // namespace memory +} // namespace qx + +void* operator new(size_t size, const char* file, int line) +{ + void* ptr = qx::memory::alloc_mem(size, file, line, false); +#if _DEBUG_NEW_STD_OPER_NEW + if (ptr) { return ptr; } + else { throw std::bad_alloc(); } +#else + return ptr; +#endif +} + +void* operator new[](size_t size, const char* file, int line) +{ + void* ptr = qx::memory::alloc_mem(size, file, line, true); +#if _DEBUG_NEW_STD_OPER_NEW + if (ptr) { return ptr; } + else { throw std::bad_alloc(); } +#else + return ptr; +#endif +} + +#if HAVE_PLACEMENT_DELETE +void operator delete(void* pointer, const char* file, int line) throw() +{ + if (qx::memory::new_verbose_flag) + { + qx::memory::fast_mutex_autolock lock(qx::memory::new_output_lock); + const char * msg_out = "[QxOrm] info: exception thrown on initializing object at %p (%s:%d)"; Q_UNUSED(msg_out); + qDebug(msg_out, pointer, file, line); + } + operator delete(pointer); +} + +void operator delete[](void* pointer, const char* file, int line) throw() +{ + if (qx::memory::new_verbose_flag) + { + qx::memory::fast_mutex_autolock lock(qx::memory::new_output_lock); + const char * msg_out = "[QxOrm] info: exception thrown on initializing objects at %p (%s:%d)"; Q_UNUSED(msg_out); + qDebug(msg_out, pointer, file, line); + } + operator delete[](pointer); +} +#endif // HAVE_PLACEMENT_DELETE + +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/src/QxMemLeak/mem_pool_base.cpp b/src/QxMemLeak/mem_pool_base.cpp new file mode 100644 index 0000000..1849e21 --- /dev/null +++ b/src/QxMemLeak/mem_pool_base.cpp @@ -0,0 +1,84 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/** + * @file mem_pool_base.cpp + * + * Implementation for the memory pool base. + * + * @version 1.2, 2004/07/26 + * @author Wu Yongwei + * + */ + +#include + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#if defined(_MEM_POOL_USE_MALLOC) +#include +#else +#include +#endif + +#include + +/* Defines macros to abstract system memory routines */ +# ifdef _MEM_POOL_USE_MALLOC +# define _MEM_POOL_ALLOCATE(_Sz) malloc(_Sz) +# define _MEM_POOL_DEALLOCATE(_Ptr) free(_Ptr) +# else +# define _MEM_POOL_ALLOCATE(_Sz) ::operator new((_Sz), std::nothrow) +# define _MEM_POOL_DEALLOCATE(_Ptr) ::operator delete(_Ptr) +# endif + +namespace qx { +namespace memory { + +mem_pool_base::~mem_pool_base() +{ +} + +void* mem_pool_base::alloc_sys(size_t __size) +{ + return _MEM_POOL_ALLOCATE(__size); +} + +void mem_pool_base::dealloc_sys(void* __ptr) +{ + _MEM_POOL_DEALLOCATE(__ptr); +} + +} // namespace memory +} // namespace qx + +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/src/QxMemLeak/static_mem_pool.cpp b/src/QxMemLeak/static_mem_pool.cpp new file mode 100644 index 0000000..ecd8797 --- /dev/null +++ b/src/QxMemLeak/static_mem_pool.cpp @@ -0,0 +1,111 @@ +// -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +// vim:tabstop=4:shiftwidth=4:expandtab: + +/* + * Copyright (C) 2004-2008 Wu Yongwei + * + * 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. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute + * it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must + * not claim that you wrote the original software. If you use this + * software in a product, an acknowledgement in the product + * documentation would be appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must + * not be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source + * distribution. + * + * This file is part of Stones of Nvwa: + * http://sourceforge.net/projects/nvwa + * + */ + +/** + * @file static_mem_pool.cpp + * + * Non-template and non-inline code for the `static' memory pool. + * + * @version 1.7, 2006/08/26 + * @author Wu Yongwei + * + */ + +#include + +#ifndef QT_NO_DEBUG +#ifndef _QX_MODE_RELEASE +#if _QX_USE_MEM_LEAK_DETECTION + +#include + +#include +#include + +namespace qx { +namespace memory { + +static_mem_pool_set::static_mem_pool_set() +{ + _STATIC_MEM_POOL_TRACE(false, "The static_mem_pool_set is created"); +} + +static_mem_pool_set::~static_mem_pool_set() +{ + std::for_each(_M_memory_pool_set.rbegin(), + _M_memory_pool_set.rend(), + delete_object()); + _STATIC_MEM_POOL_TRACE(false, "The static_mem_pool_set is destroyed"); +} + +/** + * Creates the singleton instance of #static_mem_pool_set. + * + * @return reference to the instance of #static_mem_pool_set + */ +static_mem_pool_set& static_mem_pool_set::instance() +{ + lock __guard; + static static_mem_pool_set _S_instance; + return _S_instance; +} + +/** + * Asks all static memory pools to recycle unused memory blocks back to + * the system. The caller should get the lock to prevent other + * operations to #static_mem_pool_set during its execution. + */ +void static_mem_pool_set::recycle() +{ + _STATIC_MEM_POOL_TRACE(false, "Memory pools are being recycled"); + container_type::iterator __end = _M_memory_pool_set.end(); + for (container_type::iterator + __i = _M_memory_pool_set.begin(); + __i != __end; ++__i) + { + (*__i)->recycle(); + } +} + +/** + * Adds a new memory pool to #static_mem_pool_set. + * + * @param __memory_pool_p pointer to the memory pool to add + */ +void static_mem_pool_set::add(mem_pool_base* __memory_pool_p) +{ + lock __guard; + _M_memory_pool_set.push_back(__memory_pool_p); +} + +} // namespace memory +} // namespace qx + +#endif // _QX_USE_MEM_LEAK_DETECTION +#endif // _QX_MODE_RELEASE +#endif // QT_NO_DEBUG diff --git a/src/QxModelView/IxModel.cpp b/src/QxModelView/IxModel.cpp new file mode 100644 index 0000000..ee7af2d --- /dev/null +++ b/src/QxModelView/IxModel.cpp @@ -0,0 +1,840 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#define QX_CONSTRUCT_IX_MODEL() \ + m_pClass(NULL), m_pModelClass(NULL), m_pDataMemberX(NULL), m_pDataMemberId(NULL), m_pCollection(NULL), \ + m_pParent(NULL), m_eAutoUpdateDatabase(IxModel::e_no_auto_update), m_pDataMemberRelationToParent(NULL), m_lManualInsertIndex(0) + +namespace qx +{ + + IxModel::IxModel(QObject *parent /* = 0 */) : QAbstractItemModel(parent), QX_CONSTRUCT_IX_MODEL() { ; } + + IxModel::~IxModel() { ; } + + IxClass *IxModel::getClass() const { return m_pClass; } + + IxClass *IxModel::getModelClass() const { return m_pModelClass; } + + IxCollection *IxModel::getCollection() const { return m_pCollection; } + + QSqlDatabase IxModel::getDatabase() const { return m_database; } + + QSqlError IxModel::getLastError() const { return m_lastError; } + + QString IxModel::getLastErrorAsString() const { return (m_lastError.isValid() ? m_lastError.text() : QString()); } + + QStringList IxModel::getListOfColumns() const { return m_lstColumns; } + + int IxModel::getRowCount() const { return rowCount(); } + + QHash IxModel::getListOfHeaders() const + { + QHash lst; + QHashIterator itr(m_lstHeadersData); + QString sStart = (QString::number(Qt::DisplayRole) + "|"); + while (itr.hasNext()) + { + itr.next(); + if (itr.key().startsWith(sStart)) + { + QString sKey = itr.key(); + sKey.replace(sStart, ""); + lst.insert(sKey, itr.value().toString()); + } + } + return lst; + } + + IxDataMember *IxModel::getDataMember(int column) const { return (((column < 0) || (column >= m_lstDataMember.count())) ? NULL : m_lstDataMember.at(column)); } + + QString IxModel::getDataMemberKey(int column) const + { + IxDataMember *p = getDataMember(column); + return (p ? p->getKey() : QString()); + } + + QVariant IxModel::getModelValue(int row, const QString &column) const + { + if (!m_lstDataMemberByKey.contains(column)) + { + return QVariant(); + } + int iColumnIndex = m_lstDataMemberByKey.value(column); + QModelIndex idx = index(row, iColumnIndex, QModelIndex()); + return data(idx, Qt::DisplayRole); + } + + int IxModel::getColumnIndex(const QString &sColumnName) const + { + if (!m_lstDataMemberByKey.contains(sColumnName)) + { + qAssert(false); + return -1; + } + return m_lstDataMemberByKey.value(sColumnName); + } + + int IxModel::getAutoUpdateDatabase_() const { return static_cast(m_eAutoUpdateDatabase); } + + IxModel::e_auto_update_database IxModel::getAutoUpdateDatabase() const { return m_eAutoUpdateDatabase; } + + QVariant IxModel::getCustomProperty(const QString &key) const { return (m_hCustomProperties.contains(key) ? m_hCustomProperties.value(key) : QVariant()); } + + QObject *IxModel::getParentModel() const { return static_cast(m_pParent); } + + void IxModel::dumpModel(bool bJsonFormat /* = true */) const { dumpModelImpl(bJsonFormat); } + + QObject *IxModel::cloneModel() { return cloneModelImpl(); } + + void IxModel::setDatabase(const QSqlDatabase &db) { m_database = db; } + + void IxModel::setListOfColumns(const QStringList &lst) + { + m_lstColumns = lst; + clear(true); + } + + void IxModel::setListOfHeaders(const QHash &lst) + { + QHashIterator itr(lst); + while (itr.hasNext()) + { + itr.next(); + QString sHeaderDataKey = (QString::number(Qt::DisplayRole) + "|" + itr.key()); + QVariant vHeaderDataValue = QVariant(itr.value()); + m_lstHeadersData.insert(sHeaderDataKey, vHeaderDataValue); + } + Q_EMIT headerDataChanged(Qt::Horizontal, 0, (m_lstDataMember.count() - 1)); + } + + bool IxModel::setModelValue(int row, const QString &column, const QVariant &value) + { + if (!m_lstDataMemberByKey.contains(column)) + { + return false; + } + int iColumnIndex = m_lstDataMemberByKey.value(column); + QModelIndex idx = index(row, iColumnIndex, QModelIndex()); + return setData(idx, value, Qt::EditRole); + } + + void IxModel::setParentModel(IxModel *pParent) + { + m_pParent = pParent; + m_pDataMemberRelationToParent = NULL; + if (!pParent || !m_pDataMemberX) + { + return; + } + long lCount = m_pDataMemberX->count_WithDaoStrategy(); + for (long l = 0; l < lCount; l++) + { + IxDataMember *p = m_pDataMemberX->get_WithDaoStrategy(l); + if (!p) + { + continue; + } + IxSqlRelation *pRelation = p->getSqlRelation(); + if (!pRelation) + { + continue; + } + pRelation->init(); + if (pRelation->getDataId() == pParent->m_pDataMemberId) + { + m_pDataMemberRelationToParent = p; + break; + } + } + } + + void IxModel::setAutoUpdateDatabase_(int i) { m_eAutoUpdateDatabase = static_cast(i); } + + void IxModel::setAutoUpdateDatabase(IxModel::e_auto_update_database e) { m_eAutoUpdateDatabase = e; } + + void IxModel::setCustomProperty(const QString &key, const QVariant &val) { m_hCustomProperties.insert(key, val); } + + int IxModel::qxCount_(const QString &sQuery) + { + qx_query query(sQuery); + return static_cast(qxCount(query, database(NULL))); + } + + bool IxModel::qxFetchById_(const QVariant &id, const QStringList &relation /* = QStringList() */) { return (!qxFetchById(id, relation, database(NULL)).isValid()); } + + bool IxModel::qxFetchAll_(const QStringList &relation /* = QStringList() */) { return (!qxFetchAll(relation, database(NULL)).isValid()); } + + bool IxModel::qxFetchByQuery_(const QString &sQuery, const QStringList &relation /* = QStringList() */) + { + qx_query query(sQuery); + return (!qxFetchByQuery(query, relation, database(NULL)).isValid()); + } + + bool IxModel::qxFetchRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxFetchRow(row, relation, database(NULL)).isValid()); } + + bool IxModel::qxInsert_(const QStringList &relation /* = QStringList() */, bool bUseExecBatch /* = false */) { return (!qxInsert(relation, database(NULL), bUseExecBatch).isValid()); } + + bool IxModel::qxInsertRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxInsertRow(row, relation, database(NULL)).isValid()); } + + bool IxModel::qxUpdate_(const QString &sQuery, const QStringList &relation /* = QStringList() */, bool bUseExecBatch /* = false */) + { + qx_query query(sQuery); + return (!qxUpdate(query, relation, database(NULL), bUseExecBatch).isValid()); + } + + bool IxModel::qxUpdateRow_(int row, const QString &sQuery, const QStringList &relation /* = QStringList() */) + { + qx_query query(sQuery); + return (!qxUpdateRow(row, query, relation, database(NULL)).isValid()); + } + + bool IxModel::qxSave_(const QStringList &relation /* = QStringList() */) { return (!qxSave(relation, database(NULL)).isValid()); } + + bool IxModel::qxSaveRow_(int row, const QStringList &relation /* = QStringList() */) { return (!qxSaveRow(row, relation, database(NULL)).isValid()); } + + bool IxModel::qxDeleteById_(const QVariant &id) { return (!qxDeleteById(id, database(NULL)).isValid()); } + + bool IxModel::qxDeleteAll_() { return (!qxDeleteAll(database(NULL)).isValid()); } + + bool IxModel::qxDeleteByQuery_(const QString &sQuery) + { + qx_query query(sQuery); + return (!qxDeleteByQuery(query, database(NULL)).isValid()); + } + + bool IxModel::qxDeleteRow_(int row) { return (!qxDeleteRow(row, database(NULL)).isValid()); } + + bool IxModel::qxDestroyById_(const QVariant &id) { return (!qxDestroyById(id, database(NULL)).isValid()); } + + bool IxModel::qxDestroyAll_() { return (!qxDestroyAll(database(NULL)).isValid()); } + + bool IxModel::qxDestroyByQuery_(const QString &sQuery) + { + qx_query query(sQuery); + return (!qxDestroyByQuery(query, database(NULL)).isValid()); + } + + bool IxModel::qxDestroyRow_(int row) { return (!qxDestroyRow(row, database(NULL)).isValid()); } + + bool IxModel::qxExecuteQuery_(const QString &sQuery) + { + qx_query query(sQuery); + return (!qxExecuteQuery(query, database(NULL)).isValid()); + } + + bool IxModel::qxExist_(const QVariant &id) { return qxExist(id, database(NULL)).getValue(); } + + QString IxModel::qxValidate_(const QStringList &groups /* = QStringList() */) + { + qx::QxInvalidValueX invalidValueX = qxValidate(groups); + return (invalidValueX ? QString() : invalidValueX.text()); + } + + QString IxModel::qxValidateRow_(int row, const QStringList &groups /* = QStringList() */) + { + qx::QxInvalidValueX invalidValueX = qxValidateRow(row, groups); + return (invalidValueX ? QString() : invalidValueX.text()); + } + + void IxModel::raiseEvent_headerDataChanged(Qt::Orientation orientation, int first, int last) { Q_EMIT headerDataChanged(orientation, first, last); } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + void IxModel::raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles /* = QVector() */) { Q_EMIT dataChanged(topLeft, bottomRight, roles); } + + void IxModel::raiseEvent_layoutAboutToBeChanged(const QList &parents /* = QList() */, QAbstractItemModel::LayoutChangeHint hint /* = QAbstractItemModel::NoLayoutChangeHint */) { Q_EMIT layoutAboutToBeChanged(parents, hint); } + + void IxModel::raiseEvent_layoutChanged(const QList &parents /* = QList() */, QAbstractItemModel::LayoutChangeHint hint /* = QAbstractItemModel::NoLayoutChangeHint */) { Q_EMIT layoutChanged(parents, hint); } + +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + void IxModel::raiseEvent_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { Q_EMIT dataChanged(topLeft, bottomRight); } + + void IxModel::raiseEvent_layoutAboutToBeChanged() { Q_EMIT layoutAboutToBeChanged(); } + + void IxModel::raiseEvent_layoutChanged() { Q_EMIT layoutChanged(); } + +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + void IxModel::clear(bool bUpdateColumns /* = false */) + { + if (!m_pCollection) + { + qAssert(false); + return; + } + if (!bUpdateColumns && (m_pCollection->_count() <= 0)) + { + return; + } + beginResetModel(); + m_pCollection->_clear(); + for (long l = (m_lstChild.count() - 1); l >= 0; l--) + { + removeListOfChild(l); + } + m_lstChild.clear(); + m_hChild.clear(); + if (bUpdateColumns) + { + generateRoleNames(); + } + endResetModel(); + + if (getShowEmptyLine()) + { + setShowEmptyLine(false); + setShowEmptyLine(true); + } + } + + IxModel *IxModel::getChild(long row, const QString &relation) + { + if ((row < 0) || (row >= m_lstChild.count())) + { + return NULL; + } + IxModel::type_relation_by_name child = m_lstChild.at(row); + if (!child.contains(relation)) + { + return NULL; + } + return child.value(relation); + } + + void IxModel::insertChild(long row, const QString &relation, IxModel *pChild) + { + if ((row < 0) || (!pChild)) + { + return; + } + if (relation.isEmpty()) + { + return; + } + while (row > (m_lstChild.count() - 1)) + { + IxModel::type_relation_by_name tmp; + m_lstChild.append(tmp); + } + m_lstChild[row].insert(relation, pChild); + QPair pairRowRelation(static_cast(row), relation); + m_hChild.insert(pChild, pairRowRelation); + } + + void IxModel::removeListOfChild(long row) + { + if ((row < 0) || (row >= m_lstChild.count())) + { + return; + } + IxModel::type_relation_by_name lst = m_lstChild.at(row); + Q_FOREACH (IxModel *p, lst) + { + if (p) + { + m_hChild.remove(p); + delete p; + } + } + m_lstChild.removeAt(row); + } + + QSqlError IxModel::saveChildRelations(IxModel *pChild) + { + if (!m_hChild.contains(pChild)) + { + return QSqlError(); + } + QPair pairRowRelation = m_hChild.value(pChild); + return qxSaveRow(pairRowRelation.first, (QStringList() << pairRowRelation.second)); + } + + QVariant IxModel::getIdFromChild(IxModel *pChild) const + { + if (!m_hChild.contains(pChild)) + { + return QVariant(); + } + if (!m_pCollection || !m_pDataMemberId) + { + qAssert(false); + return QVariant(); + } + int row = m_hChild.value(pChild).first; + if ((row < 0) || (row >= m_pCollection->_count())) + { + return QVariant(); + } + void *pItem = getRowItemAsVoidPtr(row); + return (pItem ? m_pDataMemberId->toVariant(pItem) : QVariant()); + } + + QPair IxModel::getChildPosition(IxModel *pChild) const + { + if (!m_hChild.contains(pChild)) + { + return QPair(-1, ""); + } + return m_hChild.value(pChild); + } + + QVariant IxModel::data(const QModelIndex &index, int role /* = Qt::DisplayRole */) const + { + if (!index.isValid()) + { + return QVariant(); + } + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + { + if ((index.column() < 0) || (index.column() >= m_lstDataMember.count())) + { + return QVariant(); + } + else if ((index.row() < 0) || (index.row() >= rowCount())) + { + return QVariant(); + } + IxDataMember *pDataMember = m_lstDataMember.at(index.column()); + void *pItem = getRowItemAsVoidPtr(index.row()); + if (!pDataMember || !pItem) + { + return QVariant(); + } + return pDataMember->toVariant(pItem); + } + else if (role >= (Qt::UserRole + 1)) + { + QModelIndex idx = this->index(index.row(), (role - Qt::UserRole - 1), QModelIndex()); + return data(idx, Qt::DisplayRole); + } + return QVariant(); + } + + bool IxModel::setData(const QModelIndex &index, const QVariant &value, int role /* = Qt::EditRole */) + { + if (!index.isValid()) + { + return false; + } + if (role == Qt::EditRole) + { + if ((index.column() < 0) || (index.column() >= m_lstDataMember.count())) + { + return false; + } + else if ((index.row() < 0) || (index.row() >= rowCount())) + { + return false; + } + IxDataMember *pDataMember = m_lstDataMember.at(index.column()); + bool bDirtyRow = isDirtyRow(index.row()); + void *pItem = getRowItemAsVoidPtr(index.row()); + if (!pDataMember || !pItem) + { + return false; + } + QVariant vCurrentValue = pDataMember->toVariant(pItem); + if (vCurrentValue == value) + { + return true; + } + qx_bool bSetData = pDataMember->fromVariant(pItem, value); + if (bSetData && (m_eAutoUpdateDatabase == qx::IxModel::e_auto_update_on_field_change)) + { + qxSaveRowData(index.row(), (QStringList() << pDataMember->getKey())); + if (!m_lastError.isValid() && bDirtyRow) + { + insertDirtyRowToModel(); + } + if (m_lastError.isValid()) + { + if (!bDirtyRow) + { + qDebug("[QxOrm] qx::IxModel::setData() : %s", "an error occurred saving value in database (more details with 'getLastError()' method), so previous value has been restored"); + pDataMember->fromVariant(pItem, vCurrentValue); + return false; + } + } + else if (pDataMember->hasSqlRelation()) + { + qxFetchRow(index.row(), (QStringList() << pDataMember->getSqlRelation()->getKey())); + } + } + if (bSetData) + { + raiseEvent_dataChanged(index, index); + } + return bSetData; + } + else if (role >= (Qt::UserRole + 1)) + { + QModelIndex idx = this->index(index.row(), (role - Qt::UserRole - 1), QModelIndex()); + return setData(idx, value, Qt::EditRole); + } + return false; + } + + int IxModel::rowCount(const QModelIndex &parent /* = QModelIndex() */) const + { + if (parent.isValid() || !m_pCollection) + { + return 0; + } + return (static_cast(m_pCollection->_count()) + (getShowEmptyLine() ? 1 : 0)); + } + + int IxModel::columnCount(const QModelIndex &parent /* = QModelIndex() */) const + { + if (parent.isValid()) + { + return 0; + } + qAssert(m_lstRoleNames.count() == m_lstDataMember.count()); + return static_cast(m_lstRoleNames.count()); + } + + QModelIndex IxModel::index(int row, int column, const QModelIndex &parent /* = QModelIndex() */) const + { + if (!hasIndex(row, column, parent)) + { + return QModelIndex(); + } + if ((column < 0) || (column >= m_lstDataMember.count())) + { + return QModelIndex(); + } + IxDataMember *pDataMember = m_lstDataMember.at(column); + if (pDataMember) + { + return createIndex(row, column, static_cast(pDataMember)); + } + else + { + return QModelIndex(); + } + } + + QModelIndex IxModel::parent(const QModelIndex &index) const + { + Q_UNUSED(index); + return QModelIndex(); + } + + bool IxModel::hasChildren(const QModelIndex &parent /* = QModelIndex() */) const + { + Q_UNUSED(parent); + return false; + } + + QVariant IxModel::headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const + { + if (role == Qt::TextAlignmentRole) + { + return Qt::AlignCenter; + } + if ((orientation == Qt::Vertical) && (role == Qt::DisplayRole) && (isDirtyRow(section))) + { + return QVariant(QString("*")); + } + if (orientation != Qt::Horizontal) + { + return QAbstractItemModel::headerData(section, orientation, role); + } + if ((section < 0) || (section >= m_lstDataMember.count())) + { + return QAbstractItemModel::headerData(section, orientation, role); + } + IxDataMember *pDataMember = m_lstDataMember.at(section); + if (!pDataMember) + { + return QAbstractItemModel::headerData(section, orientation, role); + } + QString sHeaderDataKey = (QString::number(role) + "|" + pDataMember->getKey()); + if (m_lstHeadersData.contains(sHeaderDataKey)) + { + return m_lstHeadersData.value(sHeaderDataKey); + } + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) + { + if (!pDataMember->getDescription().isEmpty()) + { + return pDataMember->getDescription(); + } + return pDataMember->getKey(); + } + return QVariant(); + } + + Qt::ItemFlags IxModel::flags(const QModelIndex &index) const + { + if (!index.isValid()) + { + return Qt::ItemIsEnabled; + } + return (Qt::ItemIsEditable | QAbstractItemModel::flags(index)); + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QHash IxModel::roleNames() const + { + return m_lstRoleNames; + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + Qt::DropActions IxModel::supportedDragActions() const + { + return QAbstractItemModel::supportedDragActions(); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + Qt::DropActions IxModel::supportedDropActions() const + { + return QAbstractItemModel::supportedDropActions(); + } + + bool IxModel::removeRows(int row, int count, const QModelIndex &parent /* = QModelIndex() */) + { + if (parent.isValid()) + { + return false; + } + if (m_eAutoUpdateDatabase == IxModel::e_auto_update_on_field_change) + { + return removeRowsAutoUpdateOnFieldChange(row, count); + } + return removeRowsGeneric(row, count); + } + + bool IxModel::removeRowsGeneric(int row, int count) + { + if (!m_pCollection) + { + qAssert(false); + return false; + } + beginRemoveRows(QModelIndex(), row, (row + count - 1)); + for (int i = 0; i < count; ++i) + { + m_pCollection->_remove(row); + removeListOfChild(row); + } + updateShowEmptyLine(); + endRemoveRows(); + return true; + } + + bool IxModel::removeRowsAutoUpdateOnFieldChange(int row, int count) + { + if (!m_pCollection) + { + qAssert(false); + return false; + } + for (int i = 0; i < count; ++i) + { + if ((row >= 0) && (row < m_pCollection->_count())) + { + if (qxDeleteRow_(row)) + { + removeRowsGeneric(row, 1); + } + else + { + qDebug("[QxOrm] qx::IxModel::removeRowsAutoUpdateOnFieldChange() : %s", "an error occurred deleting row from database (more details with 'getLastError()' method), so row is not removed from model"); + return false; + } + } + else if (isDirtyRow(row)) + { + setShowEmptyLine(false); + setShowEmptyLine(true); + } + else + { + return true; + } + } + return true; + } + + bool IxModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role /* = Qt::EditRole */) + { + if (orientation != Qt::Horizontal) + { + return QAbstractItemModel::setHeaderData(section, orientation, value, role); + } + if ((section < 0) || (section >= m_lstDataMember.count())) + { + return false; + } + IxDataMember *pDataMember = m_lstDataMember.at(section); + if (!pDataMember) + { + return false; + } + + if ((role == Qt::EditRole) || (role == Qt::DisplayRole)) + { + QString sHeaderDataKey = (QString::number(Qt::EditRole) + "|" + pDataMember->getKey()); + m_lstHeadersData.insert(sHeaderDataKey, value); + sHeaderDataKey = (QString::number(Qt::DisplayRole) + "|" + pDataMember->getKey()); + m_lstHeadersData.insert(sHeaderDataKey, value); + } + else + { + QString sHeaderDataKey = (QString::number(role) + "|" + pDataMember->getKey()); + m_lstHeadersData.insert(sHeaderDataKey, value); + } + + Q_EMIT headerDataChanged(orientation, section, section); + return true; + } + + bool IxModel::setHeaderData(const QString &sColumnName, const QVariant &value, int role /* = Qt::EditRole */) + { + int section = getColumnIndex(sColumnName); + return ((section == -1) ? false : setHeaderData(section, Qt::Horizontal, value, role)); + } + + void IxModel::syncNestedModel(int row, const QStringList &relation) + { + Q_UNUSED(row); + Q_UNUSED(relation); + } + + void IxModel::syncAllNestedModel(const QStringList &relation) { Q_UNUSED(relation); } + + void IxModel::syncNestedModelRecursive(IxModel *pNestedModel, const QStringList &relation) + { + if (pNestedModel) + { + pNestedModel->syncAllNestedModel(relation); + } + } + + void IxModel::generateRoleNames() + { + int iRoleCount = 0; + m_lstRoleNames.clear(); + m_lstDataMember.clear(); + m_lstDataMemberByKey.clear(); + + for (long l = 0; l < (m_pDataMemberX ? m_pDataMemberX->count_WithDaoStrategy() : 0); ++l) + { + IxDataMember *pDataMember = m_pDataMemberX->get_WithDaoStrategy(l); + if (!pDataMember) + { + continue; + } + IxSqlRelation *pRelation = (pDataMember->hasSqlRelation() ? pDataMember->getSqlRelation() : NULL); + IxSqlRelation::relation_type eRelationType = (pRelation ? pRelation->getRelationType() : IxSqlRelation::no_relation); + if (pRelation && ((eRelationType == IxSqlRelation::one_to_many) || (eRelationType == IxSqlRelation::many_to_many))) + { + continue; + } + if ((m_lstColumns.count() > 0) && (!m_lstColumns.contains(pDataMember->getKey()))) + { + continue; + } + m_lstRoleNames.insert(static_cast(Qt::UserRole + 1 + iRoleCount), pDataMember->getKey().toLatin1()); + m_lstDataMemberByKey.insert(pDataMember->getKey(), static_cast(m_lstDataMember.count())); + m_lstDataMember.append(pDataMember); + iRoleCount++; + } + +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + setRoleNames(m_lstRoleNames); +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) + } + + QSqlDatabase *IxModel::database(QSqlDatabase *other) + { + return (other ? other : (m_database.isValid() ? (&m_database) : NULL)); + } + +#ifndef _QX_NO_JSON + + QString IxModel::toJson(int row /* = -1 */) const { return toJson_Helper(row); } + + bool IxModel::fromJson(const QString &json, int row /* = -1 */) { return fromJson_Helper(json, row); } + + QVariant IxModel::getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase /* = false */, const QString &sAppendRelations /* = QString() */) { return getRelationshipValues_Helper(row, relation, bLoadFromDatabase, sAppendRelations); } + + bool IxModel::setRelationshipValues(int row, const QString &relation, const QVariant &values) { return setRelationshipValues_Helper(row, relation, values); } + +#else // _QX_NO_JSON + + QString IxModel::toJson(int row /* = -1 */) const + { + qDebug("[QxOrm] qx::IxModel::toJson() : %s", "not implemented when _QX_NO_JSON compilation option is defined"); + Q_UNUSED(row); + return QString(); + } + + bool IxModel::fromJson(const QString &json, int row /* = -1 */) + { + qDebug("[QxOrm] qx::IxModel::fromJson() : %s", "not implemented when _QX_NO_JSON compilation option is defined"); + Q_UNUSED(json); + Q_UNUSED(row); + return false; + } + + QVariant IxModel::getRelationshipValues(int row, const QString &relation, bool bLoadFromDatabase /* = false */, const QString &sAppendRelations /* = QString() */) + { + qDebug("[QxOrm] qx::IxModel::getRelationshipValues() : %s", "not implemented when _QX_NO_JSON compilation option is defined"); + Q_UNUSED(row); + Q_UNUSED(relation); + Q_UNUSED(bLoadFromDatabase); + Q_UNUSED(sAppendRelations); + return QVariant(); + } + + bool IxModel::setRelationshipValues(int row, const QString &relation, const QVariant &values) + { + qDebug("[QxOrm] qx::IxModel::setRelationshipValues() : %s", "not implemented when _QX_NO_JSON compilation option is defined"); + Q_UNUSED(row); + Q_UNUSED(relation); + Q_UNUSED(values); + return false; + } + +#endif // _QX_NO_JSON + +} // namespace qx diff --git a/src/QxModelView/QxModelRowCompare.cpp b/src/QxModelView/QxModelRowCompare.cpp new file mode 100644 index 0000000..e2b0cbc --- /dev/null +++ b/src/QxModelView/QxModelRowCompare.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace model_view + { + + bool compareQVariant(const QVariant &v1, const QVariant &v2, bool bAscending) + { + int type1 = static_cast(v1.type()); + int type2 = static_cast(v2.type()); + + if (type1 != type2) + { + if (bAscending) + { + return (v1.toString() < v2.toString()); + } + else + { + return (v1.toString() > v2.toString()); + } + } + + if (type1 == QVariant::Bool) + { + int i1 = (v1.toBool() ? 1 : 0); + int i2 = (v2.toBool() ? 1 : 0); + if (bAscending) + { + return (i1 < i2); + } + else + { + return (i1 > i2); + } + } + else if (type1 == QVariant::Int) + { + if (bAscending) + { + return (v1.toInt() < v2.toInt()); + } + else + { + return (v1.toInt() > v2.toInt()); + } + } + else if (type1 == QVariant::UInt) + { + if (bAscending) + { + return (v1.toUInt() < v2.toUInt()); + } + else + { + return (v1.toUInt() > v2.toUInt()); + } + } + else if (type1 == QVariant::LongLong) + { + if (bAscending) + { + return (v1.toLongLong() < v2.toLongLong()); + } + else + { + return (v1.toLongLong() > v2.toLongLong()); + } + } + else if (type1 == QVariant::ULongLong) + { + if (bAscending) + { + return (v1.toULongLong() < v2.toULongLong()); + } + else + { + return (v1.toULongLong() > v2.toULongLong()); + } + } + else if (type1 == QVariant::Double) + { + if (bAscending) + { + return (v1.toDouble() < v2.toDouble()); + } + else + { + return (v1.toDouble() > v2.toDouble()); + } + } + else if (type1 == QVariant::Date) + { + if (bAscending) + { + return (v1.toDate() < v2.toDate()); + } + else + { + return (v1.toDate() > v2.toDate()); + } + } + else if (type1 == QVariant::DateTime) + { + if (bAscending) + { + return (v1.toDateTime() < v2.toDateTime()); + } + else + { + return (v1.toDateTime() > v2.toDateTime()); + } + } + else if (type1 == QVariant::Time) + { + if (bAscending) + { + return (v1.toTime() < v2.toTime()); + } + else + { + return (v1.toTime() > v2.toTime()); + } + } + else if (type1 == QVariant::ByteArray) + { + if (bAscending) + { + return (v1.toByteArray() < v2.toByteArray()); + } + else + { + return (v1.toByteArray() > v2.toByteArray()); + } + } + + // Default comparaison converting to string + if (bAscending) + { + return (v1.toString() < v2.toString()); + } + return (v1.toString() > v2.toString()); + } + + } // namespace model_view +} // namespace qx diff --git a/src/QxModelView/QxNestedModel.cpp b/src/QxModelView/QxNestedModel.cpp new file mode 100644 index 0000000..440c69a --- /dev/null +++ b/src/QxModelView/QxNestedModel.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + namespace model_view + { + namespace detail + { + + } // namespace detail + } // namespace model_view +} // namespace qx diff --git a/src/QxRegister/IxClass.cpp b/src/QxRegister/IxClass.cpp new file mode 100644 index 0000000..3e40342 --- /dev/null +++ b/src/QxRegister/IxClass.cpp @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN IxClass::IxClassImpl + { + + IxDataMemberX *m_pDataMemberX; //!< List of data member + IxFunctionX_ptr m_pFctMemberX; //!< List of function member + IxFunctionX_ptr m_pFctStaticX; //!< List of function static + + QMutex m_mutex; //!< Mutex => qx::IxClass is thread-safe + QString m_sKey; //!< 'IxClass' key <=> class name + QString m_sName; //!< 'IxClass' name <=> database table name (if empty => class name) + QString m_sDescription; //!< 'IxClass' description + long m_lVersion; //!< 'IxClass' version + bool m_bFinalClass; //!< Class without base class (for example, qx::trait::no_base_class_defined and QObject) + bool m_bDaoReadOnly; //!< If 'true', cannot INSERT, UPDATE OR DELETE an instance of this class using qx::dao namespace + bool m_bRegistered; //!< Class registered into QxOrm context + qx::dao::strategy::inheritance m_eDaoStrategy; //!< Dao class strategy to access data member + qx::QxSoftDelete m_oSoftDelete; //!< Soft delete (or logical delete) behavior + IxValidatorX_ptr m_pAllValidator; //!< List of validator associated to the class + std::shared_ptr m_pSqlRelationX; //!< Collection of SQL relationships + std::shared_ptr> m_pSqlDataMemberX; //!< Collection of SQL columns (data member) + + QByteArray m_byteName; //!< Optimization to retrieve name under "const char *" format + const char *m_pName; //!< Optimization to retrieve name under "const char *" format + + IxClassImpl() : m_pDataMemberX(NULL), m_lVersion(-1), m_bFinalClass(false), m_bDaoReadOnly(false), m_bRegistered(false), m_eDaoStrategy(qx::dao::strategy::concrete_table_inheritance), m_pName(NULL) { ; } + ~IxClassImpl() { ; } + + void updateNamePtr() + { + m_byteName = m_sName.toLatin1(); + m_pName = m_byteName.constData(); + } + + IxDataMember *isValid_SqlRelation(long lIndex) const + { + IxDataMember *p = (m_pDataMemberX ? m_pDataMemberX->get_WithDaoStrategy(lIndex) : NULL); + bool bIsValid = (p && p->getDao() && p->hasSqlRelation()); + if (bIsValid) + { + p->getSqlRelation()->init(); + } + return (bIsValid ? p : NULL); + } + + IxDataMember *isValid_SqlDataMember(long lIndex) const + { + IxDataMember *pId = (m_pDataMemberX ? m_pDataMemberX->getId_WithDaoStrategy() : NULL); + IxDataMember *p = (m_pDataMemberX ? m_pDataMemberX->get_WithDaoStrategy(lIndex) : NULL); + bool bValid = (p && p->getDao() && !p->hasSqlRelation()); + bValid = (bValid && (p != pId)); + return (bValid ? p : NULL); + } + }; + + IxClass::IxClass() : qx::QxPropertyBag(), m_pImpl(new IxClassImpl()) { ; } + + IxClass::~IxClass() + { + if (QxClassX::isSingletonNull() || m_pImpl->m_sKey.isEmpty()) + { + return; + } + if (!QxClassX::getSingleton()->exist(m_pImpl->m_sKey)) + { + return; + } + QxClassX::getSingleton()->remove(m_pImpl->m_sKey); + } + + QString IxClass::getKey() const { return m_pImpl->m_sKey; } + + QString IxClass::getName() const { return m_pImpl->m_sName; } + + const char *IxClass::getNamePtr() const { return m_pImpl->m_pName; } + + QString IxClass::getDescription() const { return m_pImpl->m_sDescription; } + + long IxClass::getVersion() const { return m_pImpl->m_lVersion; } + + qx::dao::strategy::inheritance IxClass::getDaoStrategy() const { return m_pImpl->m_eDaoStrategy; } + + qx::QxSoftDelete IxClass::getSoftDelete() const { return m_pImpl->m_oSoftDelete; } + + bool IxClass::isFinalClass() const { return m_pImpl->m_bFinalClass; } + + bool IxClass::isDaoReadOnly() const { return m_pImpl->m_bDaoReadOnly; } + + bool IxClass::isRegistered() const { return m_pImpl->m_bRegistered; } + + IxDataMemberX *IxClass::getDataMemberX() const { return m_pImpl->m_pDataMemberX; } + + IxFunctionX *IxClass::getFctMemberX() const { return m_pImpl->m_pFctMemberX.get(); } + + IxFunctionX *IxClass::getFctStaticX() const { return m_pImpl->m_pFctStaticX.get(); } + + std::shared_ptr> IxClass::getSqlRelationX() + { + if ((m_pImpl->m_pSqlRelationX) || (!m_pImpl->m_pDataMemberX)) + { + return m_pImpl->m_pSqlRelationX; + } + + QMutexLocker locker(&m_pImpl->m_mutex); + if (m_pImpl->m_pSqlRelationX) + { + return m_pImpl->m_pSqlRelationX; + } + m_pImpl->m_pSqlRelationX = std::make_shared(); + IxDataMember *p = NULL; + long lCount = m_pImpl->m_pDataMemberX->count_WithDaoStrategy(); + for (long l = 0; l < lCount; ++l) + { + if ((p = m_pImpl->isValid_SqlRelation(l))) + { + m_pImpl->m_pSqlRelationX->insert(p->getKey(), p->getSqlRelation()); + } + } + return m_pImpl->m_pSqlRelationX; + } + + std::shared_ptr> IxClass::getSqlDataMemberX() + { + if ((m_pImpl->m_pSqlDataMemberX) || (!m_pImpl->m_pDataMemberX)) + { + return m_pImpl->m_pSqlDataMemberX; + } + + QMutexLocker locker(&m_pImpl->m_mutex); + if (m_pImpl->m_pSqlDataMemberX) + { + return m_pImpl->m_pSqlDataMemberX; + } + m_pImpl->m_pSqlDataMemberX = std::make_shared>(); + IxDataMember *p = NULL; + long lCount = m_pImpl->m_pDataMemberX->count_WithDaoStrategy(); + for (long l = 0; l < lCount; ++l) + { + if ((p = m_pImpl->isValid_SqlDataMember(l))) + { + m_pImpl->m_pSqlDataMemberX->insert(p->getKey(), p); + } + } + return m_pImpl->m_pSqlDataMemberX; + } + + IxValidatorX_ptr &IxClass::getAllValidatorRef() { return m_pImpl->m_pAllValidator; } + + void IxClass::setKey(const QString &sKey) { m_pImpl->m_sKey = sKey; } + + void IxClass::setName(const QString &sName) + { + m_pImpl->m_sName = sName; + m_pImpl->updateNamePtr(); + } + + void IxClass::setDescription(const QString &sDesc) { m_pImpl->m_sDescription = sDesc; } + + void IxClass::setDaoStrategy(qx::dao::strategy::inheritance eDaoStrategy) { m_pImpl->m_eDaoStrategy = eDaoStrategy; } + + void IxClass::setSoftDelete(const qx::QxSoftDelete &oSoftDelete) + { + m_pImpl->m_oSoftDelete = oSoftDelete; + if (m_pImpl->m_oSoftDelete.getTableName().isEmpty()) + { + m_pImpl->m_oSoftDelete.setTableName(m_pImpl->m_sName); + } + } + + void IxClass::setDaoReadOnly(bool bDaoReadOnly) { m_pImpl->m_bDaoReadOnly = bDaoReadOnly; } + + void IxClass::setVersion(long l) { m_pImpl->m_lVersion = l; } + + void IxClass::setRegistered(bool b) { m_pImpl->m_bRegistered = b; } + + void IxClass::setFinalClass(bool b) { m_pImpl->m_bFinalClass = b; } + + void IxClass::setDataMemberX(IxDataMemberX *p) { m_pImpl->m_pDataMemberX = p; } + + void IxClass::setFctMemberX(IxFunctionX *p) { m_pImpl->m_pFctMemberX.reset(p); } + + void IxClass::setFctStaticX(IxFunctionX *p) { m_pImpl->m_pFctStaticX.reset(p); } + + void IxClass::updateClassX() + { + qAssert(!m_pImpl->m_sKey.isEmpty() && !QxClassX::getSingleton()->exist(m_pImpl->m_sKey)); + QxClassX::getSingleton()->insert(m_pImpl->m_sKey, this); + } + + IxValidatorX *IxClass::getAllValidator() + { + if (!m_pImpl->m_pAllValidator) + { + return NULL; + } + m_pImpl->m_pAllValidator->setClass(this); + return m_pImpl->m_pAllValidator.get(); + } + + IxDataMember *IxClass::getId(bool bRecursive /* = false */) const + { + IxDataMember *pId = (m_pImpl->m_pDataMemberX ? m_pImpl->m_pDataMemberX->getId() : NULL); + if (pId || !bRecursive) + { + return pId; + } + IxClass *pBaseClass = getBaseClass(); + return (pBaseClass ? pBaseClass->getId(bRecursive) : NULL); + } + + bool IxClass::isKindOf(const QString &sClassName) const + { + if (sClassName.isEmpty()) + { + qAssert(false); + return false; + } + if (m_pImpl->m_sKey == sClassName) + { + return true; + } + + IxClass *p = getBaseClass(); + while (p != NULL) + { + if (p->getKey() == sClassName) + { + return true; + } + p = p->getBaseClass(); + } + + return false; + } + +#ifndef _QX_NO_RTTI + bool IxClass::isKindOf(const std::type_info &typeInfo) const + { + if (typeInfo == typeid(void)) + { + qAssert(false); + return false; + } + if (typeInfo == this->typeInfo()) + { + return true; + } + + IxClass *p = getBaseClass(); + while (p != NULL) + { + if (typeInfo == p->typeInfo()) + { + return true; + } + p = p->getBaseClass(); + } + + return false; + } +#endif // _QX_NO_RTTI + + QString IxClass::dumpClass() const + { + QString sDump; + sDump += "-- class '" + m_pImpl->m_sKey + "' (name '" + m_pImpl->m_sName + "', "; + sDump += "description '" + m_pImpl->m_sDescription + "', version '" + QString::number(m_pImpl->m_lVersion) + "', "; + sDump += "base class '" + (getBaseClass() ? getBaseClass()->getKey() : "") + "')\n"; + + long lCount = (m_pImpl->m_pDataMemberX ? m_pImpl->m_pDataMemberX->count() : 0); + sDump += "\t* list of registered properties (" + QString::number(lCount) + ")\n"; + if (m_pImpl->m_pDataMemberX) + { + IxDataMember *pId = this->getId(); + for (long l = 0; l < lCount; l++) + { + IxDataMember *p = m_pImpl->m_pDataMemberX->get(l); + if (!p) + { + continue; + } + IxSqlRelation *pRelation = p->getSqlRelation(); + QString sInfos = p->getKey() + ((p == pId) ? QString(" (id)") : QString()) + " - " + p->getType(); + sInfos += (pRelation ? (QString(" (") + pRelation->getDescription() + QString(")")) : QString()); + sDump += "\t\t" + sInfos + "\n"; + } + } + + lCount = (m_pImpl->m_pFctMemberX ? m_pImpl->m_pFctMemberX->count() : 0); + sDump += "\t* list of registered member functions (" + QString::number(lCount) + ")\n"; + if (m_pImpl->m_pFctMemberX) + { + for (auto itr = m_pImpl->m_pFctMemberX->begin(); itr != m_pImpl->m_pFctMemberX->end(); ++itr) + { + IxFunction_ptr p = itr->second; + if (!p) + { + continue; + } + QString sKey = p->getKey(); + sDump += "\t\t" + sKey + "\n"; + } + } + + lCount = (m_pImpl->m_pFctStaticX ? m_pImpl->m_pFctStaticX->count() : 0); + sDump += "\t* list of registered static functions (" + QString::number(lCount) + ")\n"; + if (m_pImpl->m_pFctStaticX) + { + for (auto itr = m_pImpl->m_pFctStaticX->begin(); itr != m_pImpl->m_pFctStaticX->end(); ++itr) + { + IxFunction_ptr p = itr->second; + if (!p) + { + continue; + } + QString sKey = p->getKey(); + sDump += "\t\t" + sKey + "\n"; + } + } + + qDebug("%s", qPrintable(sDump)); + return sDump; + } + +} // namespace qx diff --git a/src/QxRegister/QxClassX.cpp b/src/QxRegister/QxClassX.cpp new file mode 100644 index 0000000..bf309d3 --- /dev/null +++ b/src/QxRegister/QxClassX.cpp @@ -0,0 +1,523 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClassX) + +namespace qx +{ + + QxClassX::QxClassX() : QxSingleton("qx::QxClassX") + { + initSqlTypeByClassName(); + initValidatorMessage(); + } + + QxClassX::~QxClassX() { ; } + + QxCollection *QxClassX::getAll() + { + return (&m_lstClass); + } + + IxClass *QxClassX::get(const QString &sKey) const + { + IxClass *pClass = (m_lstClass.exist(sKey) ? m_lstClass.getByKey(sKey) : NULL); + if (!pClass) + { + qx::create(sKey); + } + if (!pClass) + { + pClass = (m_lstClass.exist(sKey) ? m_lstClass.getByKey(sKey) : NULL); + } + + return pClass; + } + + bool QxClassX::exist(const QString &sKey) const + { + return m_lstClass.exist(sKey); + } + + bool QxClassX::insert(const QString &sKey, IxClass *pClass) + { + return ((!pClass || sKey.isEmpty() || m_lstClass.exist(sKey)) ? false : m_lstClass.insert(sKey, pClass)); + } + + bool QxClassX::remove(const QString &sKey) + { + return m_lstClass.removeByKey(sKey); + } + + void QxClassX::clear() + { + m_lstClass.clear(); + } + + qx::any QxClassX::create(const QString &sKey) + { + return qx::create(sKey); + } + + IxClass *QxClassX::getClass(const QString &sKey) + { + return QxClassX::getSingleton()->get(sKey); + } + + IxDataMemberX *QxClassX::getDataMemberX(const QString &sKey) + { + IxClass *pClass = QxClassX::getClass(sKey); + return (pClass ? pClass->getDataMemberX() : NULL); + } + + IxFunctionX *QxClassX::getFctMemberX(const QString &sKey) + { + IxClass *pClass = QxClassX::getClass(sKey); + return (pClass ? pClass->getFctMemberX() : NULL); + } + + IxFunctionX *QxClassX::getFctStaticX(const QString &sKey) + { + IxClass *pClass = QxClassX::getClass(sKey); + return (pClass ? pClass->getFctStaticX() : NULL); + } + + IxDataMember *QxClassX::getDataMember(const QString &sClassKey, const QString &sDataKey, bool bRecursive /* = true */) + { + QString sBaseClassKey = sClassKey; + IxClass *pClass(NULL); + IxDataMemberX *pDataX(NULL); + IxDataMember *pData(NULL); + + do + { + pClass = QxClassX::getClass(sBaseClassKey); + pDataX = QxClassX::getDataMemberX(sBaseClassKey); + pData = ((pDataX && pDataX->exist(sDataKey)) ? pDataX->get(sDataKey) : NULL); + sBaseClassKey = ((pClass && pClass->getBaseClass()) ? pClass->getBaseClass()->getKey() : QString("")); + } while (bRecursive && !pData && pClass && !sBaseClassKey.isEmpty() && !pClass->isFinalClass()); + + return pData; + } + + IxFunction *QxClassX::getFctMember(const QString &sClassKey, const QString &sFctKey, bool bRecursive /* = true */) + { + QString sBaseClassKey = sClassKey; + IxClass *pClass(NULL); + IxFunctionX *pFctX(NULL); + IxFunction *pFct(NULL); + + do + { + pClass = QxClassX::getClass(sBaseClassKey); + pFctX = QxClassX::getFctMemberX(sBaseClassKey); + pFct = ((pFctX && pFctX->exist(sFctKey)) ? pFctX->getByKey(sFctKey).get() : NULL); + sBaseClassKey = ((pClass && pClass->getBaseClass()) ? pClass->getBaseClass()->getKey() : QString("")); + } while (bRecursive && !pFct && pClass && !sBaseClassKey.isEmpty() && !pClass->isFinalClass()); + + return pFct; + } + + IxFunction *QxClassX::getFctStatic(const QString &sClassKey, const QString &sFctKey, bool bRecursive /* = true */) + { + QString sBaseClassKey = sClassKey; + IxClass *pClass(NULL); + IxFunctionX *pFctX(NULL); + IxFunction *pFct(NULL); + + do + { + pClass = QxClassX::getClass(sBaseClassKey); + pFctX = QxClassX::getFctStaticX(sBaseClassKey); + pFct = ((pFctX && pFctX->exist(sFctKey)) ? pFctX->getByKey(sFctKey).get() : NULL); + sBaseClassKey = ((pClass && pClass->getBaseClass()) ? pClass->getBaseClass()->getKey() : QString("")); + } while (bRecursive && !pFct && pClass && !sBaseClassKey.isEmpty() && !pClass->isFinalClass()); + + return pFct; + } + + bool QxClassX::implementIxPersistable(const QString &sKey, bool bTraceIfFalse /* = true */) + { + IxClass *pClass = QxClassX::getClass(sKey); + bool bImplement = (pClass ? pClass->implementIxPersistable() : false); + if (!bImplement && bTraceIfFalse) + { + qDebug("[QxOrm] class '%s' doesn't implement qx::IxPersistable interface", qPrintable(sKey)); + } + return bImplement; + } + + qx_bool QxClassX::invokeVoidPtr(const QString &sClassKey, const QString &sFctKey, void *pOwner, const QString ¶ms /* = QString() */, qx::any *ret /* = NULL */) + { + IxFunction *pFct = QxClassX::getFctMember(sClassKey, sFctKey, true); + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : qx_bool(false)); + } + + qx_bool QxClassX::invokeVoidPtr(const QString &sClassKey, const QString &sFctKey, void *pOwner, const type_any_params ¶ms, qx::any *ret /* = NULL */) + { + IxFunction *pFct = QxClassX::getFctMember(sClassKey, sFctKey, true); + return ((pOwner && pFct) ? pFct->invoke(pOwner, params, ret) : qx_bool(false)); + } + + qx_bool QxClassX::invokeStatic(const QString &sClassKey, const QString &sFctKey, const QString ¶ms /* = QString() */, qx::any *ret /* = NULL */) + { + IxFunction *pFct = QxClassX::getFctStatic(sClassKey, sFctKey, true); + return (pFct ? pFct->invoke(params, ret) : qx_bool(false)); + } + + qx_bool QxClassX::invokeStatic(const QString &sClassKey, const QString &sFctKey, const type_any_params ¶ms, qx::any *ret /* = NULL */) + { + IxFunction *pFct = QxClassX::getFctStatic(sClassKey, sFctKey, true); + return (pFct ? pFct->invoke(params, ret) : qx_bool(false)); + } + +#ifndef _QX_NO_RTTI + const std::type_info &QxClassX::typeInfo(const QString &sKey) const + { + IxClass *pClass = QxClassX::getClass(sKey); + return (pClass ? pClass->typeInfo() : typeid(void)); + } +#endif // _QX_NO_RTTI + + QxCollection *QxClassX::getAllClasses() + { + QxClassX::registerAllClasses(); + return QxClassX::getSingleton()->getAll(); + } + + void QxClassX::registerAllClasses(bool bInitAllRelations /* = true */, bool bInitValidator /* = true */) + { + QHash *pAllFactory = QxFactoryX::getSingleton()->getAllFactory(); + if (!pAllFactory) + { + qAssert(false); + return; + } + + QHashIterator itr(*pAllFactory); + while (itr.hasNext()) + { + itr.next(); + IxClass *pClass = QxClassX::getClass(itr.key()); + qAssert(pClass != NULL); + if ((pClass) && (bInitValidator)) + { + pClass->getAllValidator(); + } + } + + if (!bInitAllRelations) + { + return; + } + QxCollection *pAllClasses = QxClassX::getSingleton()->getAll(); + if (!pAllClasses) + { + qAssert(false); + return; + } + + for (long k = 0; k < pAllClasses->count(); k++) + { + IxClass *pClass = pAllClasses->getByIndex(k); + if (!pClass) + { + continue; + } + IxDataMemberX *pDataMemberX = pClass->getDataMemberX(); + if (!pDataMemberX) + { + continue; + } + for (long l = 0; l < pDataMemberX->count_WithDaoStrategy(); l++) + { + IxDataMember *pDataMember = pDataMemberX->get_WithDaoStrategy(l); + if (!pDataMember) + { + continue; + } + if (isValid_SqlRelation(pDataMember)) + { + pDataMember->getSqlRelation()->init(); + } + } + pClass->getSqlDataMemberX(); + pClass->getSqlRelationX(); + } + } + + QString QxClassX::dumpAllClasses() + { + QxClassX::registerAllClasses(); + QxCollection *pAllClasses = QxClassX::getAllClasses(); + if (!pAllClasses) + { + qAssert(false); + return ""; + } + + QString sDump; + long lCount = pAllClasses->count(); + qDebug("[QxOrm] start dump all registered classes (%ld)", lCount); + for (auto itr = pAllClasses->begin(); itr != pAllClasses->end(); ++itr) + { + IxClass *pClass = itr->second; + if (pClass) + { + sDump += pClass->dumpClass(); + } + } + qDebug("[QxOrm] %s", "end dump all registered classes"); + + return sDump; + } + + QString QxClassX::dumpSqlSchema() + { + qDebug("[QxOrm] qx::QxClassX::dumpSqlSchema() : %s", "be careful with this function, it's just an example and tested only with SQLite database, so it's strongly recommended to write your own function to create your SQL schema"); + QxCollection *pAllClasses = QxClassX::getAllClasses(); + if (!pAllClasses) + { + qAssert(false); + return ""; + } + QString sql; + long lSqlCount = 0; + + for (long k = 0; k < pAllClasses->count(); k++) + { + IxClass *pClass = pAllClasses->getByIndex(k); + if (!pClass) + { + continue; + } + + // If the class is a parameter or a service from 'QxService' module, it's not a persistent class + if (pClass->isKindOf("qx::service::IxParameter") || pClass->isKindOf("qx::service::IxService")) + { + continue; + } + + // ---- + // Here, you can filter other classes using property bag (meta-data), for example : + // QString sProp = pClass->getPropertyBag("NOT_A_DATABASE_OBJECT").toString(); + // if (sProp == "1") { continue; } + // ---- + + // Get the version of the class : if (version = 0) then 'CREATE TABLE', else if (version > 0) then 'ALTER TABLE' + long lVersion = pClass->getVersion(); + bool bCreateTable = (lVersion <= 0); + sql += (bCreateTable ? "CREATE TABLE " : "ALTER TABLE "); + sql += pClass->getName() + " "; + sql += (bCreateTable ? "(" : "ADD ("); + int iSqlCountRef = sql.length(); + + // Get the primary key (id) of table, all columns into table, and other parameters associated to table + IxDataMember *pId = pClass->getId(); + IxDataMemberX *pDataMemberX = pClass->getDataMemberX(); + QxSoftDelete oSoftDelete = pClass->getSoftDelete(); + + // Insert primary key (id) to SQL schema + if (pId && (bCreateTable || (pId->getVersion() >= lVersion))) + { + sql += pId->getSqlNameAndTypeAndParams(", ") + ", "; + qAssert(!pId->getSqlType().isEmpty()); + } + + // Insert all columns to SQL schema + for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++) + { + IxDataMember *p = pDataMemberX->get_WithDaoStrategy(l); + if (isValid_DataMember(p) && (p != pId) && (bCreateTable || (p->getVersion() >= lVersion))) + { + sql += p->getSqlNameAndTypeAndParams(", ") + ", "; + qAssert(!p->getSqlType().isEmpty()); + } + + // ---- + // Here, you can use property bag (meta-data) to add some SQL features, for example : + // QString sProp = p->getPropertyBag("INDEX").toString(); + // if (sProp == "1") { sql += "CREATE INDEX" + etc...; } + // ---- + } + + // Insert soft delete behaviour to SQL schema + if (bCreateTable && !oSoftDelete.isEmpty()) + { + sql += oSoftDelete.buildSqlQueryToCreateTable() + ", "; + } + + // Insert all relations to SQL schema + for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++) + { + IxDataMember *p = pDataMemberX->get_WithDaoStrategy(l); + QxSqlRelationParams params(0, 0, (&sql), NULL, NULL, NULL); + if (isValid_SqlRelation(p) && (p != pId) && (bCreateTable || (p->getVersion() >= lVersion))) + { + p->getSqlRelation()->createTable(params); + } + } + + // Terminate SQL schema for current class + bool bAddBracket = (sql.length() != iSqlCountRef); + sql = sql.left(sql.length() - 2); // Remove last ", " + if (bAddBracket) + { + sql += ")\n"; + } + else + { + sql += "\n"; + } + lSqlCount++; + + // Create extra-table from relations (for example, many-to-many relation needs an extra-table) + for (long l = 0; (pDataMemberX && (l < pDataMemberX->count_WithDaoStrategy())); l++) + { + IxDataMember *p = pDataMemberX->get_WithDaoStrategy(l); + if (isValid_SqlRelation(p) && (p != pId) && (bCreateTable || (p->getVersion() >= lVersion))) + { + QString sqlExtraTable = p->getSqlRelation()->createExtraTable(); + if (sqlExtraTable.isEmpty()) + { + continue; + } + sql += sqlExtraTable + "\n"; + } + } + } + + qDebug("[QxOrm] start dump SQL schema (%ld)", lSqlCount); + qDebug("%s", qPrintable(sql)); + qDebug("[QxOrm] %s", "end dump SQL schema"); + + return sql; + } + + bool QxClassX::isValid_DataMember(IxDataMember *p) + { + return (p && p->getDao() && !p->hasSqlRelation()); + } + + bool QxClassX::isValid_SqlRelation(IxDataMember *p) + { + bool bIsValid = (p && p->getDao() && p->hasSqlRelation()); + if (bIsValid) + { + p->getSqlRelation()->init(); + } + return bIsValid; + } + + void QxClassX::initSqlTypeByClassName() + { + m_lstSqlTypeByClassName.clear(); + + m_lstSqlTypeByClassName.insert("bool", "SMALLINT"); + m_lstSqlTypeByClassName.insert("qx_bool", "SMALLINT"); + m_lstSqlTypeByClassName.insert("char", "SMALLINT"); + m_lstSqlTypeByClassName.insert("short", "SMALLINT"); + m_lstSqlTypeByClassName.insert("int", "INTEGER"); + m_lstSqlTypeByClassName.insert("long", "INTEGER"); + m_lstSqlTypeByClassName.insert("long long", "INTEGER"); + m_lstSqlTypeByClassName.insert("float", "FLOAT"); + m_lstSqlTypeByClassName.insert("double", "FLOAT"); + m_lstSqlTypeByClassName.insert("long double", "FLOAT"); + m_lstSqlTypeByClassName.insert("unsigned short", "SMALLINT"); + m_lstSqlTypeByClassName.insert("unsigned int", "INTEGER"); + m_lstSqlTypeByClassName.insert("unsigned long", "INTEGER"); + m_lstSqlTypeByClassName.insert("unsigned long long", "INTEGER"); + m_lstSqlTypeByClassName.insert("std::string", "TEXT"); + m_lstSqlTypeByClassName.insert("std::wstring", "TEXT"); + m_lstSqlTypeByClassName.insert("QString", "TEXT"); + m_lstSqlTypeByClassName.insert("QVariant", "TEXT"); + m_lstSqlTypeByClassName.insert("QUuid", "TEXT"); + m_lstSqlTypeByClassName.insert("QDate", "DATE"); + m_lstSqlTypeByClassName.insert("QTime", "TIME"); + m_lstSqlTypeByClassName.insert("QDateTime", "TIMESTAMP"); + m_lstSqlTypeByClassName.insert("QByteArray", "BLOB"); + m_lstSqlTypeByClassName.insert("qx::QxDateNeutral", "TEXT"); + m_lstSqlTypeByClassName.insert("qx::QxTimeNeutral", "TEXT"); + m_lstSqlTypeByClassName.insert("qx::QxDateTimeNeutral", "TEXT"); + } + + void QxClassX::initValidatorMessage() + { + m_lstValidatorMessage.clear(); + + m_lstValidatorMessage.insert("not_null", "value '%NAME%' cannot be null"); + m_lstValidatorMessage.insert("not_empty", "value '%NAME%' cannot be empty"); + m_lstValidatorMessage.insert("min_value", "value '%NAME%' must be greater than or equal to '%CONSTRAINT%'"); + m_lstValidatorMessage.insert("max_value", "value '%NAME%' must be lesser than or equal to '%CONSTRAINT%'"); + m_lstValidatorMessage.insert("min_length", "size of '%NAME%' must be greater than or equal to '%CONSTRAINT%' characters"); + m_lstValidatorMessage.insert("max_length", "size of '%NAME%' must be lesser than or equal to '%CONSTRAINT%' characters"); + m_lstValidatorMessage.insert("date_past", "date '%NAME%' must be in the past"); + m_lstValidatorMessage.insert("date_future", "date '%NAME%' must be in the future"); + m_lstValidatorMessage.insert("min_decimal", "value '%NAME%' must be greater than or equal to '%CONSTRAINT%'"); + m_lstValidatorMessage.insert("max_decimal", "value '%NAME%' must be lesser than or equal to '%CONSTRAINT%'"); + m_lstValidatorMessage.insert("regular_expression", "value '%NAME%' doesn't match the regular expression '%CONSTRAINT%'"); + m_lstValidatorMessage.insert("e_mail", "value '%NAME%' is not a valid e-mail"); + } + + namespace trait + { + namespace detail + { + + /* Defined into './include/QxTraits/get_sql_type.h' file */ + const char *get_sql_type_by_class_name(const char *sClassName, const char *sDefaultValue) + { + static std::string s; +#ifndef QT_NO_STL + s = qx::QxClassX::getSqlTypeByClassName(sClassName).toStdString(); +#else // QT_NO_STL + s = qx::QxClassX::getSqlTypeByClassName(sClassName).toLatin1().constData(); +#endif // QT_NO_STL + return (s.empty() ? sDefaultValue : s.c_str()); + } + + } // namespace detail + } // namespace trait +} // namespace qx diff --git a/src/QxRestApi/QxRestApi.cpp b/src/QxRestApi/QxRestApi.cpp new file mode 100644 index 0000000..a6e35d9 --- /dev/null +++ b/src/QxRestApi/QxRestApi.cpp @@ -0,0 +1,1045 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#ifndef _QX_NO_JSON +#include +#include +#include +#include +#include +#include +#endif // _QX_NO_JSON + +#include +#include + +#include + +namespace qx +{ + + struct Q_DECL_HIDDEN QxRestApi::QxRestApiImpl + { + + QString m_requestId; //!< Request identifier (GUID for example) + QString m_entity; //!< Entity where to process request + QString m_action; //!< Action to execute (count, fetch_by_id, fetch_all, fetch_by_query, insert, update, etc...) + QString m_function; //!< Entity static function to call with action 'call_entity_function' and signature : static QJsonValue myEntity::myFct(const QJsonValue & request) + QStringList m_columns; //!< Columns to fetch + QStringList m_relations; //!< Relations to fetch + QStringList m_outputFormat; //!< JSON output format (same syntax as relations) + QString m_database; //!< Database to use to process request + QString m_query; //!< SQL query to execute + QString m_data; //!< Data used to process request + QSqlError m_error; //!< Error after executing the request + qx::IxPersistable_ptr m_instance; //!< Current instance to execute request + QSqlDatabase m_db; //!< Current database to execute request + qx_query m_qxQuery; //!< Query used by some actions + long m_countResult; //!< Result after a count query + qx_bool m_existResult; //!< Result after a exist query + QxInvalidValueX m_validateResult; //!< Result after a validate query + qx::dao::save_mode::e_save_mode m_eSaveMode; //!< Save mode for 'save' action + bool m_bUseExecBatch; //!< If true then use the QSqlQuery::execBatch() method to improve performance inserting/updating/deleting a list of instances to database (but doesn't fill the last inserted identifier in the C++ instances) + +#ifndef _QX_NO_JSON + + QJsonValue m_requestJson; //!< Request which contains all parameters (as JSON format) + QJsonValue m_responseJson; //!< Response after executing the request (as JSON format) + QJsonValue m_dataJson; //!< Data used to process request (as JSON format) + QJsonValue m_errorJson; //!< Error after executing the request (as JSON format) + +#endif // _QX_NO_JSON + + QxRestApiImpl() : m_countResult(0), m_eSaveMode(qx::dao::save_mode::e_none), m_bUseExecBatch(false) + { + ; + } + ~QxRestApiImpl() { ; } + +#ifndef _QX_NO_JSON + + void clear(); + void resetRequest(); + QJsonValue processRequestAsArray(const QJsonValue &request); + void buildError(int errCode, const QString &errDesc); + void buildError(const QSqlError &error); + bool parseRequest(const QString &request); + bool createInstance(); + bool decodeRequest(); + bool checkRequest(); + bool executeAction(); + bool buildResponse(); + bool formatResponse(); + bool doRequest(); + void getMetaData(); + QJsonValue getMetaData(IxClass *pClass); + qx_bool callEntityFunction(); + void getDatabases(); + +#endif // _QX_NO_JSON + }; + + QxRestApi::QxRestApi(QObject *parent /* = NULL */) : QObject(parent), m_pImpl(new QxRestApiImpl()) { ; } + + QxRestApi::~QxRestApi() { ; } + + void QxRestApi::clearAll() { (*m_pImpl) = QxRestApiImpl(); } + + QString QxRestApi::getErrorDesc() const { return (m_pImpl->m_error.isValid() ? (m_pImpl->m_error.driverText() + "\n" + m_pImpl->m_error.databaseText()) : QString()); } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int QxRestApi::getErrorCode() const + { + return (m_pImpl->m_error.isValid() ? m_pImpl->m_error.nativeErrorCode().toInt() : 0); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int QxRestApi::getErrorCode() const + { + return (m_pImpl->m_error.isValid() ? m_pImpl->m_error.number() : 0); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + + QSqlError QxRestApi::getError() const + { + return m_pImpl->m_error; + } + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString QxRestApi::getNativeErrorCode() const + { + return m_pImpl->m_error.nativeErrorCode(); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + + void QxRestApi::setEntity(const QString &entity) + { + m_pImpl->m_entity = entity; + } + + void QxRestApi::setAction(const QString &action) { m_pImpl->m_action = action; } + + void QxRestApi::setFunction(const QString &fct) { m_pImpl->m_function = fct; } + + void QxRestApi::setColumns(const QStringList &columns) { m_pImpl->m_columns = columns; } + + void QxRestApi::setRelations(const QStringList &relations) { m_pImpl->m_relations = relations; } + + void QxRestApi::setOutputFormat(const QStringList &outputFormat) { m_pImpl->m_outputFormat = outputFormat; } + + void QxRestApi::setDatabase(const QString &database) { m_pImpl->m_database = database; } + + void QxRestApi::setQuery(const QString &query) { m_pImpl->m_query = query; } + + void QxRestApi::setData(const QString &data) { m_pImpl->m_data = data; } + + void QxRestApi::setUseExecBatch(bool useExecBatch) { m_pImpl->m_bUseExecBatch = useExecBatch; } + + QString QxRestApi::processRequest(const QString &request) + { +#ifdef _QX_NO_JSON + QString msg = "QxOrm library must be built without _QX_NO_JSON compilation option to be able to call REST API module"; + m_pImpl->m_error = QSqlError(msg, "Cannot process request with _QX_NO_JSON compilation option", QSqlError::UnknownError); + return "{ \"error\": \"" + msg + "\" }"; +#else // _QX_NO_JSON + m_pImpl->clear(); + if (m_pImpl->parseRequest(request)) + { + processRequest(m_pImpl->m_requestJson); + } + QJsonValue result = (m_pImpl->m_errorJson.isNull() ? m_pImpl->m_responseJson : m_pImpl->m_errorJson); + return qx::cvt::to_string(result); +#endif // _QX_NO_JSON + } + +#ifndef _QX_NO_JSON + + void QxRestApi::setData(const QJsonValue &data) + { + m_pImpl->m_dataJson = data; + } + + QJsonValue QxRestApi::processRequest(const QJsonValue &request) + { + m_pImpl->clear(); + +#ifdef _QX_ENABLE_MONGODB + if (qx::QxSqlDatabase::getSingleton()->getDriverName() == "QXMONGODB") + { + m_pImpl->m_db = QSqlDatabase(); + } + else +#endif // _QX_ENABLE_MONGODB + { + m_pImpl->m_db = qx::QxSqlDatabase::getDatabase(m_pImpl->m_error); + } + + if (m_pImpl->m_error.isValid()) + { + m_pImpl->buildError(m_pImpl->m_error); + return m_pImpl->m_errorJson; + } + if (request.isArray()) + { + return m_pImpl->processRequestAsArray(request); + } + m_pImpl->m_requestJson = request; + if (!m_pImpl->doRequest()) + { + return m_pImpl->m_errorJson; + } + return m_pImpl->m_responseJson; + } + + QJsonValue QxRestApi::QxRestApiImpl::processRequestAsArray(const QJsonValue &request) + { + QJsonArray responseArray; + QJsonArray requestArray = request.toArray(); + if (requestArray.count() <= 0) + { + buildError(9999, "Request array is empty"); + return m_errorJson; + } + + bool bTransaction = false; + if (m_db.driver() && m_db.driver()->hasFeature(QSqlDriver::Transactions)) + { + bTransaction = m_db.transaction(); + } + + for (int i = 0; i < requestArray.count(); i++) + { + resetRequest(); + m_requestJson = requestArray.at(i); + if (!doRequest()) + { + break; + } + responseArray.append(m_responseJson); + } + + bool bTransactionOk = true; + if (!m_errorJson.isNull() && bTransaction) + { + bTransactionOk = m_db.rollback(); + } + else if (bTransaction) + { + bTransactionOk = m_db.commit(); + } + if (m_errorJson.isNull() && !bTransactionOk) + { + buildError(m_db.lastError()); + } + + if (!m_errorJson.isNull()) + { + return m_errorJson; + } + m_responseJson = responseArray; + return m_responseJson; + } + + bool QxRestApi::QxRestApiImpl::doRequest() + { + if (!decodeRequest()) + { + return false; + } + if (!checkRequest()) + { + return false; + } + if (!createInstance()) + { + return false; + } + if (!executeAction()) + { + return false; + } + if (!buildResponse()) + { + return false; + } + if (!formatResponse()) + { + return false; + } + return true; + } + + void QxRestApi::QxRestApiImpl::clear() + { + // Reset error and instance + m_responseJson = QJsonValue(); + m_errorJson = QJsonValue(); + m_error = QSqlError(); + m_instance.reset(); + m_db = QSqlDatabase(); + } + + void QxRestApi::QxRestApiImpl::resetRequest() + { + m_requestId = ""; + m_action = ""; + m_entity = ""; + m_data = ""; + m_query = ""; + m_function = ""; + m_database = ""; + m_qxQuery = qx_query(); + m_dataJson = QJsonValue(); + m_requestJson = QJsonValue(); + m_responseJson = QJsonValue(); + m_eSaveMode = qx::dao::save_mode::e_none; + m_bUseExecBatch = false; + m_columns.clear(); + m_relations.clear(); + m_outputFormat.clear(); + m_instance.reset(); + } + + void QxRestApi::QxRestApiImpl::buildError(int errCode, const QString &errDesc) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + m_error = QSqlError(errDesc, "", QSqlError::UnknownError, QString::number(errCode)); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + m_error = QSqlError(errDesc, "", QSqlError::UnknownError, errCode); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QJsonObject errJson; + QJsonObject errDetail; + errDetail.insert("code", errCode); + errDetail.insert("desc", errDesc); + errJson.insert("error", errDetail); + if (!m_requestId.isEmpty()) + { + errJson.insert("request_id", m_requestId); + } + m_errorJson = errJson; + } + + void QxRestApi::QxRestApiImpl::buildError(const QSqlError &error) + { + if (!error.isValid()) + { + return; + } + m_error = error; + QJsonObject errJson; + QJsonObject errDetail; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + errDetail.insert("code", error.nativeErrorCode()); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + errDetail.insert("code", error.number()); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + QString errMsg = (error.driverText() + "\n" + error.databaseText()); + errDetail.insert("desc", errMsg); + errJson.insert("error", errDetail); + if (!m_requestId.isEmpty()) + { + errJson.insert("request_id", m_requestId); + } + m_errorJson = errJson; + } + + bool QxRestApi::QxRestApiImpl::createInstance() + { + // Some actions doesn't require any instance + if (m_action == "get_meta_data") + { + return true; + } + if (m_action == "get_databases") + { + return true; + } + if (m_action == "call_custom_query") + { + return true; + } + if (m_action == "call_entity_function") + { + return true; + } + + // Check if entity implements qx::IxPersistable interface + m_instance.reset(); + if (m_entity.isEmpty()) + { + buildError(9999, "JSON request is invalid : 'entity' field is empty"); + return false; + } + if (!qx::QxClassX::implementIxPersistable(m_entity)) + { + buildError(9999, "Entity '" + m_entity + "' must implement qx::IxPersistable interface"); + return false; + } + m_instance = qx::IxPersistable_ptr(static_cast(qx::create_void_ptr(m_entity))); + if (!m_instance) + { + buildError(9999, "Entity '" + m_entity + "' is not valid : unable to create a new qx::IxPersistable instance"); + return false; + } + + // Check if action requires some input data + if (m_action == "count") + { + return true; + } + if (m_action == "delete_all") + { + return true; + } + if (m_action == "destroy_all") + { + return true; + } + if (m_action == "delete_by_query") + { + return true; + } + if (m_action == "destroy_by_query") + { + return true; + } + + // Check if some input data has been provided by caller + if (m_dataJson.isNull() && (m_action != "fetch_all") && (m_action != "fetch_by_query")) + { + buildError(9999, "No data provided for entity '" + m_entity + "'"); + return false; + } + + // Check data format : single instance, or array of instances, or collection of instances (hash-map key/value) + if (m_dataJson.isArray()) + { + std::shared_ptr lst; + QJsonArray dataArray = m_dataJson.toArray(); + if (dataArray.count() <= 0) + { + buildError(9999, "Data array is empty for entity '" + m_entity + "'"); + return false; + } + QJsonValue dataFirst = dataArray.first(); + if (dataFirst.isNull()) + { + buildError(9999, "First item in data array is null for entity '" + m_entity + "'"); + return false; + } + if (!dataFirst.isObject()) + { + buildError(9999, "First item in data array is not an object for entity '" + m_entity + "'"); + return false; + } + QJsonObject dataFirstObject = dataFirst.toObject(); + if (dataFirstObject.isEmpty()) + { + buildError(9999, "First object in data array is empty for entity '" + m_entity + "'"); + return false; + } + if ((dataFirstObject.count() == 2) && dataFirstObject.contains("key") && dataFirstObject.contains("value")) + { + lst = m_instance->qxNewPersistableCollection(false); + } + else + { + lst = m_instance->qxNewPersistableCollection(true); + } + m_instance = std::static_pointer_cast(lst); + } + else if ((m_action == "fetch_all") || (m_action == "fetch_by_query")) + { + std::shared_ptr lst; + lst = m_instance->qxNewPersistableCollection(true); + m_instance = std::static_pointer_cast(lst); + } + + // Fill data in qx::IxPersistable instance + qx_bool bFromJson = (m_dataJson.isNull() ? qx_bool(true) : m_instance->fromJson_(m_dataJson)); + if (!bFromJson) + { + buildError(static_cast(bFromJson.getCode()), bFromJson.getDesc()); + return false; + } + return true; + } + + bool QxRestApi::QxRestApiImpl::parseRequest(const QString &request) + { + // Parse request as JSON format + QJsonParseError jsonError; + QByteArray requestAsByteArray = request.toUtf8(); + QJsonDocument doc = QJsonDocument::fromJson(requestAsByteArray, (&jsonError)); + if (jsonError.error != QJsonParseError::NoError) + { + buildError(static_cast(jsonError.error), "Error parsing JSON request : " + jsonError.errorString()); + return false; + } + + // Request can be an array or a single object + m_requestJson = (doc.isArray() ? QJsonValue(doc.array()) : QJsonValue(doc.object())); + return true; + } + + bool QxRestApi::QxRestApiImpl::decodeRequest() + { + // Check if request is a valid JSON object + if (m_requestJson.isNull()) + { + buildError(9999, "Request is NULL"); + return false; + } + if (!m_requestJson.isObject()) + { + buildError(9999, "Request is not a JSON object"); + return false; + } + QJsonObject request = m_requestJson.toObject(); + + // Extract request identifier + if (request.contains("request_id")) + { + m_requestId = request.value("request_id").toString(); + } + + // Extract action + if (request.contains("action")) + { + m_action = request.value("action").toString(); + } + else + { + buildError(9999, "Parameter 'action' is required and cannot be empty"); + return false; + } + if (m_action.isEmpty()) + { + buildError(9999, "Parameter 'action' cannot be empty"); + return false; + } + + // Extract entity + if (request.contains("entity")) + { + m_entity = request.value("entity").toString(); + } + + // Extract data + if (request.contains("data")) + { + m_dataJson = request.value("data"); + } + else if (!m_data.isEmpty()) + { + qx_bool bParseOk = qx::cvt::from_string(m_data, m_dataJson); + if (!bParseOk) + { + buildError(static_cast(bParseOk.getCode()), bParseOk.getDesc()); + return false; + } + } + + // Extract function + if (request.contains("fct")) + { + qx::cvt::from_json(request.value("fct"), m_function); + } + + // Extract columns + if (request.contains("columns")) + { + qx::cvt::from_json(request.value("columns"), m_columns); + } + + // Extract relations + if (request.contains("relations")) + { + qx::cvt::from_json(request.value("relations"), m_relations); + } + + // Extract output format + if (request.contains("output_format")) + { + qx::cvt::from_json(request.value("output_format"), m_outputFormat); + } + + // Extract database key + if (request.contains("database")) + { + m_database = request.value("database").toString(); + } + + // Extract use exec batch setting + if (request.contains("use_exec_batch")) + { + m_bUseExecBatch = (request.value("use_exec_batch").toBool() || (request.value("use_exec_batch").toString() == "1")); + } + + // Extract save mode for 'save' action + if (request.contains("save_mode")) + { + QString sSaveMode = request.value("save_mode").toString(); + bool bSaveModeAsInt = false; + int iSaveMode = sSaveMode.toInt(&bSaveModeAsInt); + if (bSaveModeAsInt) + { + m_eSaveMode = static_cast(iSaveMode); + } + else + { + m_eSaveMode = ((sSaveMode == "check_insert_or_update") ? qx::dao::save_mode::e_check_insert_or_update : ((sSaveMode == "insert_only") ? qx::dao::save_mode::e_insert_only : ((sSaveMode == "update_only") ? qx::dao::save_mode::e_update_only : qx::dao::save_mode::e_none))); + } + } + + // Extract query + if (request.contains("query")) + { + qx::cvt::from_json(request.value("query"), m_qxQuery); + } + else if (!m_query.isEmpty()) + { + m_qxQuery = qx_query(m_query); + } + + return true; + } + + bool QxRestApi::QxRestApiImpl::checkRequest() + { + bool isEntityRequired = ((m_action == "get_meta_data") || (m_action == "call_entity_function")); + isEntityRequired = (isEntityRequired || (m_action == "fetch_by_id") || (m_action == "fetch_all") || (m_action == "fetch_by_query")); + isEntityRequired = (isEntityRequired || (m_action == "insert") || (m_action == "update") || (m_action == "save")); + isEntityRequired = (isEntityRequired || (m_action == "delete_by_id") || (m_action == "delete_all") || (m_action == "delete_by_query")); + isEntityRequired = (isEntityRequired || (m_action == "destroy_by_id") || (m_action == "destroy_all") || (m_action == "destroy_by_query")); + isEntityRequired = (isEntityRequired || (m_action == "exec_custom_query") || (m_action == "exist") || (m_action == "validate") || (m_action == "count")); + if (isEntityRequired && (m_entity.isEmpty())) + { + buildError(9999, "Parameter 'entity' is required and cannot be empty for action '" + m_action + "'"); + return false; + } + + bool isDataRequired = ((m_action == "fetch_by_id") || (m_action == "delete_by_id") || (m_action == "destroy_by_id")); + isDataRequired = (isDataRequired || (m_action == "insert") || (m_action == "update") || (m_action == "save")); + isDataRequired = (isDataRequired || (m_action == "exist") || (m_action == "validate")); + if (isDataRequired && (m_dataJson.isNull())) + { + buildError(9999, "Parameter 'data' is required and cannot be empty for action '" + m_action + "'"); + return false; + } + + bool isQueryRequired = ((m_action == "fetch_by_query") || (m_action == "delete_by_query") || (m_action == "destroy_by_query")); + isQueryRequired = (isQueryRequired || (m_action == "exec_custom_query") || (m_action == "call_custom_query")); + if (isQueryRequired && (m_qxQuery.query().isEmpty())) + { + buildError(9999, "Parameter 'query' is required and cannot be empty for action '" + m_action + "'"); + return false; + } + + bool isFunctionRequired = (m_action == "call_entity_function"); + if (isFunctionRequired && (m_function.isEmpty())) + { + buildError(9999, "Parameter 'fct' is required and cannot be empty for action '" + m_action + "'"); + return false; + } + + return true; + } + + bool QxRestApi::QxRestApiImpl::executeAction() + { + m_error = QSqlError(); + m_errorJson = QJsonValue(); + + try + { + if (m_action == "count") + { + m_countResult = 0; + m_error = m_instance->qxCount(m_countResult, m_qxQuery, (&m_db), m_relations); + } + else if (m_action == "fetch_by_id") + { + QVariant id; + m_error = m_instance->qxFetchById(id, m_columns, m_relations, (&m_db)); + } + else if (m_action == "fetch_all") + { + m_error = m_instance->qxFetchAll(NULL, m_columns, m_relations, (&m_db)); + } + else if (m_action == "fetch_by_query") + { + m_error = m_instance->qxFetchByQuery(m_qxQuery, NULL, m_columns, m_relations, (&m_db)); + } + else if (m_action == "insert") + { + m_error = m_instance->qxInsert(m_relations, (&m_db), m_bUseExecBatch); + } + else if (m_action == "update") + { + m_error = m_instance->qxUpdate(m_qxQuery, m_columns, m_relations, (&m_db), m_bUseExecBatch); + } + else if (m_action == "save") + { + m_error = m_instance->qxSave(m_relations, (&m_db), m_eSaveMode); + } + else if (m_action == "delete_by_id") + { + QVariant id; + m_error = m_instance->qxDeleteById(id, (&m_db), m_bUseExecBatch); + } + else if (m_action == "delete_all") + { + m_error = m_instance->qxDeleteAll(&m_db); + } + else if (m_action == "delete_by_query") + { + m_error = m_instance->qxDeleteByQuery(m_qxQuery, (&m_db)); + } + else if (m_action == "destroy_by_id") + { + QVariant id; + m_error = m_instance->qxDestroyById(id, (&m_db), m_bUseExecBatch); + } + else if (m_action == "destroy_all") + { + m_error = m_instance->qxDestroyAll(&m_db); + } + else if (m_action == "destroy_by_query") + { + m_error = m_instance->qxDestroyByQuery(m_qxQuery, (&m_db)); + } + else if (m_action == "exec_custom_query") + { + m_error = m_instance->qxExecuteQuery(m_qxQuery, NULL, (&m_db)); + } + else if (m_action == "exist") + { + QVariant id; + m_existResult = m_instance->qxExist(id, (&m_db)); + } + else if (m_action == "validate") + { + m_validateResult = m_instance->qxValidate(); + } + else if (m_action == "call_custom_query") + { + m_error = qx::dao::call_query(m_qxQuery, (&m_db)); + } + else if (m_action == "call_entity_function") + { + if (!callEntityFunction()) + { + return false; + } + } + else if (m_action == "get_meta_data") + { + getMetaData(); + } + else if (m_action == "get_databases") + { + getDatabases(); + } + else + { + buildError(9999, "Unknown action '" + m_action + "'"); + return false; + } + } + catch (const qx::exception &x) + { + buildError(9999, "An exception occurred executing action '" + m_action + "' : " + QString::number(x.getCode()) + " - " + x.getDescription()); + return false; + } + catch (const std::exception &e) + { + buildError(9999, "An exception occurred executing action '" + m_action + "' : " + QString(e.what())); + return false; + } + catch (...) + { + buildError(9999, "Unknown exception occurred executing action '" + m_action + "'"); + return false; + } + + if (m_error.isValid()) + { + buildError(m_error); + } + return (!m_error.isValid()); + } + + bool QxRestApi::QxRestApiImpl::buildResponse() + { + if (m_action == "get_meta_data") + { + return m_errorJson.isNull(); + } + if (m_action == "get_databases") + { + return m_errorJson.isNull(); + } + + QJsonObject response; + if (m_action == "count") + { + response.insert("count", static_cast(m_countResult)); + m_responseJson = response; + return true; + } + else if (m_action == "exist") + { + response.insert("exist", (m_existResult ? true : false)); + m_responseJson = response; + return true; + } + else if (m_action == "validate") + { + response.insert("invalid_values", qx::cvt::to_json(m_validateResult)); + m_responseJson = response; + return true; + } + else if (m_action == "call_custom_query") + { + response.insert("query_output", qx::cvt::to_json(m_qxQuery)); + m_responseJson = response; + return true; + } + else if ((m_action == "delete_all") || (m_action == "delete_by_query")) + { + response.insert("deleted", true); + m_responseJson = response; + return true; + } + else if ((m_action == "destroy_all") || (m_action == "destroy_by_query")) + { + response.insert("destroyed", true); + m_responseJson = response; + return true; + } + else if (m_action == "call_entity_function") + { + return true; + } + + QString outputFormat = (m_outputFormat.isEmpty() ? QString() : QString("filter: " + m_outputFormat.join(" | "))); + if (outputFormat.isEmpty() && ((m_action == "insert") || (m_action == "update") || (m_action == "save"))) + { + outputFormat = QX_JSON_SERIALIZE_ONLY_ID; + } + else if (outputFormat.isEmpty() && ((m_action == "delete_by_id") || (m_action == "destroy_by_id"))) + { + outputFormat = QX_JSON_SERIALIZE_ONLY_ID; + } + m_responseJson = m_instance->toJson_(outputFormat); + return true; + } + + bool QxRestApi::QxRestApiImpl::formatResponse() + { + QJsonObject response; + if (!m_requestId.isEmpty()) + { + response.insert("request_id", m_requestId); + } + response.insert("data", m_responseJson); + m_responseJson = response; + return true; + } + + qx_bool QxRestApi::QxRestApiImpl::callEntityFunction() + { + qx::any anyResponse; + std::vector anyRequest; + anyRequest.push_back(m_dataJson); + if (m_entity.isEmpty()) + { + buildError(9999, "Unable to call entity function : 'entity' field is empty"); + return qx_bool(false); + } + if (m_function.isEmpty()) + { + buildError(9999, "Unable to call entity function : 'fct' field is empty"); + return qx_bool(false); + } + if (!qx::QxClassX::getFctStatic(m_entity, m_function, true)) + { + buildError(9999, "Unable to call entity function : '" + m_entity + "::" + m_function + "' function not found (or not registered in QxOrm context)"); + return qx_bool(false); + } + qx_bool bInvokeFct = qx::QxClassX::invokeStatic(m_entity, m_function, anyRequest, (&anyResponse)); + if (bInvokeFct) + { + m_responseJson = qx::any_cast(anyResponse); + } + else + { + buildError(static_cast(bInvokeFct.getCode()), bInvokeFct.getDesc()); + } + return bInvokeFct; + } + + void QxRestApi::QxRestApiImpl::getMetaData() + { + QJsonObject response; + QxClassX::registerAllClasses(); + if (m_entity == "*") + { + QJsonArray entities; + QxCollection *pAllClasses = QxClassX::getAllClasses(); + if (!pAllClasses) + { + buildError(9999, "Unable to access to registered classes"); + return; + } + for (auto itr = pAllClasses->begin(); itr != pAllClasses->end(); ++itr) + { + IxClass *pClass = itr->second; + if (!pClass || !pClass->implementIxPersistable()) + { + continue; + } + entities.append(getMetaData(pClass)); + } + response.insert("entities", entities); + } + else + { + IxClass *pClass = QxClassX::getClass(m_entity); + if (!pClass) + { + buildError(9999, "Entity not found : " + m_entity); + return; + } + if (!pClass->implementIxPersistable()) + { + buildError(9999, "Entity doesn't implement qx::IxPersistable interface : " + m_entity); + return; + } + response.insert("entity", getMetaData(pClass)); + } + m_responseJson = response; + } + + QJsonValue QxRestApi::QxRestApiImpl::getMetaData(IxClass *pClass) + { + // Fill data about entity + QJsonObject entity; + entity.insert("key", pClass->getKey()); + entity.insert("name", pClass->getName()); + entity.insert("description", pClass->getDescription()); + entity.insert("version", static_cast(pClass->getVersion())); + entity.insert("base_entity", (pClass->getBaseClass() ? pClass->getBaseClass()->getKey() : QString())); + + // Fill primary key information + IxDataMember *pDataMemberId = pClass->getId(); + QJsonObject primaryKey; + if (pDataMemberId) + { + primaryKey.insert("key", pDataMemberId->getKey()); + primaryKey.insert("description", pDataMemberId->getDescription()); + primaryKey.insert("type", pDataMemberId->getType()); + } + entity.insert("entity_id", primaryKey); + + // Prepare arrays for properties and relations + QJsonArray properties; + QJsonArray relations; + + // Process all data members in a single loop + IxDataMemberX *pDataMemberX = pClass->getDataMemberX(); + if (pDataMemberX) + { + const long memberCount = pDataMemberX->count(); + for (long i = 0; i < memberCount; ++i) + { + IxDataMember *pDataMember = pDataMemberX->get(i); + if (!pDataMember || (pDataMember == pDataMemberId)) + { + continue; + } + + IxSqlRelation *pRelation = pDataMember->getSqlRelation(); + if (pRelation) + { + // This is a relation + QJsonObject relation; + relation.insert("key", pDataMember->getKey()); + relation.insert("description", pDataMember->getDescription()); + relation.insert("type", pDataMember->getType()); + relation.insert("type_relation", pRelation->getDescription()); + relation.insert("target", (pRelation->getClass() ? pRelation->getClass()->getKey() : QString())); + relations.append(relation); + } + else + { + // This is a regular property + QJsonObject property; + property.insert("key", pDataMember->getKey()); + property.insert("description", pDataMember->getDescription()); + property.insert("type", pDataMember->getType()); + properties.append(property); + } + } + } + + entity.insert("properties", properties); + entity.insert("relations", relations); + + return entity; + } + + void QxRestApi::QxRestApiImpl::getDatabases() + { + } + +#endif // _QX_NO_JSON + +} // namespace qx diff --git a/src/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.cpp b/src/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.cpp new file mode 100644 index 0000000..6063806 --- /dev/null +++ b/src/QxSerialize/QDataStream/QxSerializeQDataStream_QObject.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const QObject &t) +{ + QList propertyKeyList = t.dynamicPropertyNames(); + qint16 iPropertyCount = static_cast(propertyKeyList.count()); + QPair pair_string_variant; + stream << iPropertyCount; + + for (qint16 i = 0; i < iPropertyCount; i++) + { + pair_string_variant.first = propertyKeyList.at(i); + pair_string_variant.second = t.property(propertyKeyList.at(i).constData()); + stream << pair_string_variant; + } + + return stream; +} + +QDataStream &operator>>(QDataStream &stream, QObject &t) +{ + qint16 iPropertyCount = 0; + stream >> iPropertyCount; + + for (qint16 i = 0; i < iPropertyCount; i++) + { + QPair pair_string_variant; + stream >> pair_string_variant; + t.setProperty(pair_string_variant.first.constData(), pair_string_variant.second); + } + + return stream; +} diff --git a/src/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.cpp b/src/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.cpp new file mode 100644 index 0000000..1b3f61e --- /dev/null +++ b/src/QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const QSqlError &t) +{ + QString sDatabaseText = t.databaseText(); + QString sDriverText = t.driverText(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + qint32 iNumber = static_cast(t.nativeErrorCode().toInt()); + QString sNativeErrorCode = t.nativeErrorCode(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + qint32 iNumber = static_cast(t.number()); + QString sNativeErrorCode = ""; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + qint32 iType = static_cast(t.type()); + + stream << sDatabaseText; + stream << sDriverText; + stream << iNumber; + stream << iType; + stream << sNativeErrorCode; + + return stream; +} + +QDataStream &operator>>(QDataStream &stream, QSqlError &t) +{ + QString sDatabaseText; + QString sDriverText; + qint32 iNumber(0); + qint32 iType(0); + QString sNativeErrorCode; + + stream >> sDatabaseText; + stream >> sDriverText; + stream >> iNumber; + stream >> iType; + stream >> sNativeErrorCode; + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t = QSqlError(sDriverText, sDatabaseText, static_cast(iType), sNativeErrorCode); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t.setDatabaseText(sDatabaseText); + t.setDriverText(sDriverText); + t.setNumber(static_cast(iNumber)); + t.setType(static_cast(iType)); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + + return stream; +} diff --git a/src/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.cpp b/src/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.cpp new file mode 100644 index 0000000..0fa706a --- /dev/null +++ b/src/QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const long &t) +{ + qint64 tmp = static_cast(t); + stream << tmp; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, long &t) +{ + qint64 tmp = 0; + stream >> tmp; + t = static_cast(tmp); + return stream; +} diff --git a/src/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.cpp b/src/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.cpp new file mode 100644 index 0000000..17c513e --- /dev/null +++ b/src/QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +namespace qx +{ + + QDataStream &QxSerializeRegistered_Helper::save(QDataStream &stream, IxClass *pClass, const void *pOwner) + { + if (!pClass || !pOwner) + { + qAssert(false); + return stream; + } + stream << (quint32)(13939); + bool bJustId = false; + + if (qx::serialization::helper::QxSerializeCheckInstance::contains(pOwner, pClass)) + { + bJustId = true; + stream << bJustId; + qx::IxDataMember *pId = pClass->getId(true); + if (!pId) + { + return stream; + } + QVariant val = pId->toVariant(pOwner); + stream << val; + return stream; + } + qx::serialization::helper::QxSerializeCheckInstance checker(pOwner, pClass); + stream << bJustId; + Q_UNUSED(checker); + + do + { + qx::QxSerializeRegistered_Helper::saveHelper(stream, pClass, pOwner); + pClass = pClass->getBaseClass(); + } while (pClass != NULL); + + return stream; + } + + QDataStream &QxSerializeRegistered_Helper::load(QDataStream &stream, IxClass *pClass, void *pOwner) + { + if (!pClass || !pOwner) + { + qAssert(false); + return stream; + } + + bool bJustId = false; + quint32 magic = 0; + stream >> magic; + if ((magic != 13937) && (magic != 13939)) + { + qDebug("[QxOrm] qx::QxSerializeRegistered_Helper::load() : %s", "input binary data is not valid"); + return stream; + } + if (magic > 13937) + { + stream >> bJustId; + } + + if (bJustId) + { + qx::IxDataMember *pId = pClass->getId(true); + if (!pId) + { + return stream; + } + QVariant val; + stream >> val; + pId->fromVariant(pOwner, val); + return stream; + } + + do + { + qx::QxSerializeRegistered_Helper::loadHelper(stream, pClass, pOwner); + pClass = pClass->getBaseClass(); + } while (pClass != NULL); + + return stream; + } + + void QxSerializeRegistered_Helper::saveHelper(QDataStream &stream, IxClass *pClass, const void *pOwner) + { + IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + qint16 iVersion = static_cast(pClass->getVersion()); + stream << iVersion; + + for (long l = 0; l < pDataMemberX->count(); l++) + { + IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if (pDataMember->getVersion() > static_cast(iVersion)) + { + qAssert(false); + continue; + } + QVariant vValue = pDataMember->toVariant(pOwner, -1, qx::cvt::context::e_serialize_registered); + stream << vValue; + } + } + + void QxSerializeRegistered_Helper::loadHelper(QDataStream &stream, IxClass *pClass, void *pOwner) + { + IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + qint16 iVersion = 0; + stream >> iVersion; + + for (long l = 0; l < pDataMemberX->count(); l++) + { + IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if (pDataMember->getVersion() > static_cast(iVersion)) + { + continue; + } + QVariant vValue; + stream >> vValue; + pDataMember->fromVariant(pOwner, vValue, -1, qx::cvt::context::e_serialize_registered); + } + } + +} // namespace qx diff --git a/src/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.cpp b/src/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.cpp new file mode 100644 index 0000000..38daff3 --- /dev/null +++ b/src/QxSerialize/QDataStream/QxSerializeQDataStream_std_string.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +QDataStream &operator<<(QDataStream &stream, const std::string &t) +{ + QString tmp = qx::cvt::detail::QxConvert_ToString::toString(t, "", 0, qx::cvt::context::e_no_context); + stream << tmp; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, std::string &t) +{ + QString tmp; + stream >> tmp; + qx::cvt::detail::QxConvert_FromString::fromString(tmp, t, "", 0, qx::cvt::context::e_no_context); + return stream; +} + +QDataStream &operator<<(QDataStream &stream, const std::wstring &t) +{ + QString tmp = qx::cvt::detail::QxConvert_ToString::toString(t, "", 0, qx::cvt::context::e_no_context); + stream << tmp; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, std::wstring &t) +{ + QString tmp; + stream >> tmp; + qx::cvt::detail::QxConvert_FromString::fromString(tmp, t, "", 0, qx::cvt::context::e_no_context); + return stream; +} diff --git a/src/QxSerialize/QJson/QxSerializeQJson_IxService.cpp b/src/QxSerialize/QJson/QxSerializeQJson_IxService.cpp new file mode 100644 index 0000000..84c74b9 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_IxService.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::service::IxService &t, const QString &format) + { + QJsonObject obj; + obj.insert("service_name", QJsonValue(t.m_sServiceName)); + obj.insert("service_method", QJsonValue(t.m_sServiceMethodName)); + obj.insert("message_return", qx::cvt::to_json(t.m_bMessageReturn, format)); + + QJsonValue input; + if (t.m_pInputParameter) + { + t.m_pInputParameter->registerClass(); + QString sClassName = t.m_pInputParameter->getClassName(); + obj.insert("input_parameter_class_name", sClassName); + input = t.m_pInputParameter->saveToJson(); + } + obj.insert("input_parameter", input); + + QJsonValue output; + if (t.m_pOutputParameter) + { + t.m_pOutputParameter->registerClass(); + QString sClassName = t.m_pOutputParameter->getClassName(); + obj.insert("output_parameter_class_name", sClassName); + output = t.m_pOutputParameter->saveToJson(); + } + obj.insert("output_parameter", output); + + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::IxService &t, const QString &format) + { + t = qx::service::IxService(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + t.m_sServiceName = obj.value("service_name").toString(); + t.m_sServiceMethodName = obj.value("service_method").toString(); + qx::cvt::from_json(obj.value("message_return"), t.m_bMessageReturn, format); + + t.m_pInputParameter.reset(); + if (obj.contains("input_parameter_class_name")) + { + QString sClassName = obj.value("input_parameter_class_name").toString(); + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::cvt::detail::QxConvert_FromJson< qx::service::IxService >, loading QJson", "unable to create nude pointer for input parameter"); + } + else + { + ptr->registerClass(); + ptr->loadFromJson(obj.value("input_parameter")); + } + t.m_pInputParameter.reset(ptr); + } + + t.m_pOutputParameter.reset(); + if (obj.contains("output_parameter_class_name")) + { + QString sClassName = obj.value("output_parameter_class_name").toString(); + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::cvt::detail::QxConvert_FromJson< qx::service::IxService >, loading QJson", "unable to create nude pointer for output parameter"); + } + else + { + ptr->registerClass(); + ptr->loadFromJson(obj.value("output_parameter")); + } + t.m_pOutputParameter.reset(ptr); + } + + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.cpp b/src/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.cpp new file mode 100644 index 0000000..b6d3ede --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_IxSqlElement.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::dao::detail::IxSqlElement &t, const QString &format) + { + QJsonObject obj; + obj.insert("index", QJsonValue(t.m_iIndex)); + obj.insert("list_columns", qx::cvt::to_json(t.m_lstColumns, format)); + obj.insert("list_keys", qx::cvt::to_json(t.m_lstKeys, format)); + obj.insert("list_values", qx::cvt::to_json(t.m_lstValues, format)); + obj.insert("extra_settings", QJsonValue(t.getExtraSettings())); + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::dao::detail::IxSqlElement &t, const QString &format) + { + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + t.m_iIndex = qRound(obj.value("index").toDouble()); + qx::cvt::from_json(obj.value("list_columns"), t.m_lstColumns, format); + qx::cvt::from_json(obj.value("list_keys"), t.m_lstKeys, format); + qx::cvt::from_json(obj.value("list_values"), t.m_lstValues, format); + t.setExtraSettings(obj.value("extra_settings").toString()); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QBrush.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QBrush.cpp new file mode 100644 index 0000000..3060e16 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QBrush.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QBrush &t, const QString &format) + { + QJsonObject obj; + int iStyle = static_cast(t.style()); + obj.insert("style", qx::cvt::to_json(iStyle, format)); + QColor color(t.color()); + obj.insert("color", qx::cvt::to_json(color, format)); + QPixmap texture(t.texture()); + obj.insert("texture", qx::cvt::to_json(texture, format)); + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QBrush &t, const QString &format) + { + t = QBrush(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + int iStyle = 0; + QColor color; + QPixmap texture; + qx::cvt::from_json(obj.value("style"), iStyle, format); + qx::cvt::from_json(obj.value("color"), color, format); + qx::cvt::from_json(obj.value("texture"), texture, format); + t.setStyle(static_cast(iStyle)); + ((iStyle == Qt::TexturePattern) ? t.setTexture(texture) : t.setColor(color)); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QColor.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QColor.cpp new file mode 100644 index 0000000..be54104 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QColor.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QColor &t, const QString &format) + { + QJsonObject obj; + QColor clr = t.toRgb(); + int iR(clr.red()), iG(clr.green()), iB(clr.blue()), iA(t.alpha()); + obj.insert("red", qx::cvt::to_json(iR, format)); + obj.insert("green", qx::cvt::to_json(iG, format)); + obj.insert("blue", qx::cvt::to_json(iB, format)); + obj.insert("alpha", qx::cvt::to_json(iA, format)); + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QColor &t, const QString &format) + { + t = QColor(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + int iR(0), iG(0), iB(0), iA(0); + qx::cvt::from_json(obj.value("red"), iR, format); + qx::cvt::from_json(obj.value("green"), iG, format); + qx::cvt::from_json(obj.value("blue"), iB, format); + qx::cvt::from_json(obj.value("alpha"), iA, format); + t.setRed(iR); + t.setGreen(iG); + t.setBlue(iB); + t.setAlpha(iA); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QFont.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QFont.cpp new file mode 100644 index 0000000..ae79f1c --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QFont.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QFont &t, const QString &format) + { + Q_UNUSED(format); + return QJsonValue(t.toString()); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QFont &t, const QString &format) + { + Q_UNUSED(format); + t.fromString(j.toString()); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QImage.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QImage.cpp new file mode 100644 index 0000000..57c9a13 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QImage.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QImage &t, const QString &format) + { + if (t.isNull()) + { + return QJsonValue(); + } + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + t.save(&buffer, "PNG"); + return qx::cvt::to_json(bytes, format); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QImage &t, const QString &format) + { + t = QImage(); + if (j.isNull()) + { + return qx_bool(true); + } + QByteArray bytes; + qx::cvt::from_json(j, bytes, format); + t.loadFromData(bytes); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QMatrix.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QMatrix.cpp new file mode 100644 index 0000000..e0bf0ef --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QMatrix.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QMatrix &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + double m11(t.m11()), m12(t.m12()), m21(t.m21()), m22(t.m22()), dx(t.dx()), dy(t.dy()); + arr.append(QJsonValue(m11)); + arr.append(QJsonValue(m12)); + arr.append(QJsonValue(m21)); + arr.append(QJsonValue(m22)); + arr.append(QJsonValue(dx)); + arr.append(QJsonValue(dy)); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QMatrix &t, const QString &format) + { + Q_UNUSED(format); + t = QMatrix(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + double m11(arr.at(0).toDouble()); + double m12(arr.at(1).toDouble()); + double m21(arr.at(2).toDouble()); + double m22(arr.at(3).toDouble()); + double dx(arr.at(4).toDouble()); + double dy(arr.at(5).toDouble()); + t.setMatrix(m11, m12, m21, m22, dx, dy); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QObject.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QObject.cpp new file mode 100644 index 0000000..0bf407c --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QObject.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QObject &t, const QString &format) + { + Q_UNUSED(format); + QJsonObject obj; + QList propertyKeyList = t.dynamicPropertyNames(); + + for (long l = 0; l < propertyKeyList.count(); l++) + { + QString key = propertyKeyList.at(l); + QVariant val = t.property(propertyKeyList.at(l).constData()); + obj.insert(key, QJsonValue::fromVariant(val)); + } + + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QObject &t, const QString &format) + { + Q_UNUSED(format); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + + for (QJsonObject::const_iterator itr = obj.constBegin(); itr != obj.constEnd(); ++itr) + { + QString key = itr.key(); + t.setProperty(qPrintable(key), itr.value().toVariant()); + } + + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QPicture.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QPicture.cpp new file mode 100644 index 0000000..277b9b2 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QPicture.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QPicture &t, const QString &format) + { + if (t.isNull()) + { + return QJsonValue(); + } + QByteArray bytes; + QBuffer buffer(&bytes); + QPicture *pTmp = const_cast(&t); + buffer.open(QIODevice::ReadWrite); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + pTmp->save(&buffer); +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + pTmp->save(&buffer, "PNG"); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + return qx::cvt::to_json(bytes, format); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPicture &t, const QString &format) + { + t = QPicture(); + if (j.isNull()) + { + return qx_bool(true); + } + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + qx::cvt::from_json(j, bytes, format); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + t.load(&buffer); +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + t.load(&buffer, "PNG"); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QPixmap.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QPixmap.cpp new file mode 100644 index 0000000..437d28e --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QPixmap.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QPixmap &t, const QString &format) + { + if (t.isNull()) + { + return QJsonValue(); + } + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + t.save(&buffer, "PNG"); + return qx::cvt::to_json(bytes, format); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPixmap &t, const QString &format) + { + t = QPixmap(); + if (j.isNull()) + { + return qx_bool(true); + } + QByteArray bytes; + qx::cvt::from_json(j, bytes, format); + t.loadFromData(bytes); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QPoint.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QPoint.cpp new file mode 100644 index 0000000..47d9d18 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QPoint.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QPoint &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + arr.append(QJsonValue(t.x())); + arr.append(QJsonValue(t.y())); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QPoint &t, const QString &format) + { + Q_UNUSED(format); + t = QPoint(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.setX(qRound(arr.at(0).toDouble())); + t.setY(qRound(arr.at(1).toDouble())); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QRect.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QRect.cpp new file mode 100644 index 0000000..08333e0 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QRect.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QRect &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + arr.append(QJsonValue(t.left())); + arr.append(QJsonValue(t.right())); + arr.append(QJsonValue(t.top())); + arr.append(QJsonValue(t.bottom())); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRect &t, const QString &format) + { + Q_UNUSED(format); + t = QRect(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.setLeft(qRound(arr.at(0).toDouble())); + t.setRight(qRound(arr.at(1).toDouble())); + t.setTop(qRound(arr.at(2).toDouble())); + t.setBottom(qRound(arr.at(3).toDouble())); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QRegExp.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QRegExp.cpp new file mode 100644 index 0000000..e109364 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QRegExp.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QRegExp &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + arr.append(QJsonValue(t.pattern())); + arr.append(QJsonValue(static_cast(t.caseSensitivity()))); + arr.append(QJsonValue(static_cast(t.patternSyntax()))); + arr.append(QJsonValue(t.isMinimal())); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRegExp &t, const QString &format) + { + Q_UNUSED(format); + t = QRegExp(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.setPattern(arr.at(0).toString()); + t.setCaseSensitivity(static_cast(qRound(arr.at(1).toDouble()))); + t.setPatternSyntax(static_cast(qRound(arr.at(2).toDouble()))); + t.setMinimal(arr.at(3).toBool()); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QRegion.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QRegion.cpp new file mode 100644 index 0000000..ef73142 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QRegion.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_GUI + +#include +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QRegion &t, const QString &format) + { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + QVector rectList(t.begin(), t.end()); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + QVector rectList = t.rects(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + return qx::cvt::to_json(rectList, format); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QRegion &t, const QString &format) + { + QVector rectList; + qx::cvt::from_json(j, rectList, format); + t.setRects(rectList.data(), rectList.count()); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QSize.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QSize.cpp new file mode 100644 index 0000000..86c709c --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QSize.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QSize &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + arr.append(QJsonValue(t.width())); + arr.append(QJsonValue(t.height())); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QSize &t, const QString &format) + { + Q_UNUSED(format); + t = QSize(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.setWidth(qRound(arr.at(0).toDouble())); + t.setHeight(qRound(arr.at(1).toDouble())); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QSqlError.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QSqlError.cpp new file mode 100644 index 0000000..d4172df --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QSqlError.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QSqlError &t, const QString &format) + { + Q_UNUSED(format); + QJsonArray arr; + arr.append(QJsonValue(t.databaseText())); + arr.append(QJsonValue(t.driverText())); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + arr.append(QJsonValue(t.nativeErrorCode())); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + arr.append(QJsonValue(t.number())); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + arr.append(QJsonValue(static_cast(t.type()))); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QSqlError &t, const QString &format) + { + Q_UNUSED(format); + t = QSqlError(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t = QSqlError(arr.at(1).toString(), arr.at(0).toString(), static_cast(qRound(arr.at(3).toDouble())), arr.at(2).toString()); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t.setDatabaseText(arr.at(0).toString()); + t.setDriverText(arr.at(1).toString()); + t.setNumber(qRound(arr.at(2).toDouble())); + t.setType(static_cast(qRound(arr.at(3).toDouble()))); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QStringList.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QStringList.cpp new file mode 100644 index 0000000..fb7e798 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QStringList.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const QStringList &t, const QString &format) + { + QJsonArray arr; + for (int i = 0; i < t.count(); i++) + { + arr.append(qx::cvt::to_json(t.at(i), format)); + } + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, QStringList &t, const QString &format) + { + t.clear(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + t.reserve(arr.count()); +#endif // (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) + + for (int i = 0; i < arr.count(); i++) + { + QString tmp; + qx::cvt::from_json(arr.at(i), tmp, format); + t.append(tmp); + } + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.cpp new file mode 100644 index 0000000..7c11243 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::QxInvalidValue &t, const QString &format) + { + QJsonObject obj; + obj.insert("message", t.m_sMessage); + if (!t.m_sPropertyName.isEmpty()) + { + obj.insert("property_name", t.m_sPropertyName); + } + if (!t.m_sPath.isEmpty()) + { + obj.insert("path", t.m_sPath); + } + if ((t.m_lstPropertyBag) && (t.m_lstPropertyBag->count() > 0)) + { + obj.insert("property_bag", qx::cvt::to_json(t.m_lstPropertyBag, format)); + } + return obj; + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValue &t, const QString &format) + { + t = qx::QxInvalidValue(); + + if (j.isArray()) + { + QJsonArray arr = j.toArray(); + t.m_sMessage = arr.at(0).toString(); + t.m_sPropertyName = arr.at(1).toString(); + t.m_sPath = arr.at(2).toString(); + qx::cvt::from_json(arr.at(3), t.m_lstPropertyBag, format); + } + else if (j.isObject()) + { + QJsonObject obj = j.toObject(); + t.m_sMessage = obj.value("message").toString(); + t.m_sPropertyName = obj.value("property_name").toString(); + t.m_sPath = obj.value("path").toString(); + qx::cvt::from_json(obj.value("property_bag"), t.m_lstPropertyBag, format); + } + + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.cpp new file mode 100644 index 0000000..4577c5b --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::QxInvalidValueX &t, const QString &format) + { + if (t.m_lstInvalidValues.count() <= 0) + { + return QJsonValue(); + } + + QJsonArray arr; + arr.append(QJsonValue(t.m_sCurrentPath)); + arr.append(qx::cvt::to_json(t.m_lstInvalidValues, format)); + return QJsonValue(arr); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxInvalidValueX &t, const QString &format) + { + t = qx::QxInvalidValueX(); + if (!j.isArray()) + { + return qx_bool(true); + } + QJsonArray arr = j.toArray(); + t.m_sCurrentPath = arr.at(0).toString(); + qx::cvt::from_json(arr.at(1), t.m_lstInvalidValues, format); + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.cpp new file mode 100644 index 0000000..45767c6 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::QxSqlQuery &t, const QString &format) + { + QJsonObject obj; + QJsonArray arr; + QHash lstResultPosByKey; + QVector> lstResultValues; + qx::dao::detail::IxSqlElement::type_class eNoSqlType = qx::dao::detail::IxSqlElement::_no_type; + + if (t.m_pSqlResult) + { + lstResultPosByKey = t.m_pSqlResult->positionByKey; + lstResultValues = t.m_pSqlResult->values; + } + + obj.insert("query", qx::cvt::to_json(t.m_sQuery)); + obj.insert("list_values", qx::cvt::to_json(t.m_lstValue, format)); + obj.insert("sql_element_index", QJsonValue(t.m_iSqlElementIndex)); + obj.insert("parenthesis_count", QJsonValue(t.m_iParenthesisCount)); + obj.insert("distinct", QJsonValue(t.m_bDistinct)); + obj.insert("result_position_by_key", qx::cvt::to_json(lstResultPosByKey, format)); + obj.insert("result_values", qx::cvt::to_json(lstResultValues, format)); + obj.insert("response", QJsonValue(t.m_vResponse.toString())); + obj.insert("type", QJsonValue(t.m_sType)); + obj.insert("list_join_query_user", qx::cvt::to_json(t.m_lstJoinQueryUser, format)); + obj.insert("list_join_query_resolve", qx::cvt::to_json(t.m_lstJoinQueryToResolve, format)); + + if (!t.m_pSqlElementTemp) + { + obj.insert("sql_element_temp_type", QJsonValue(static_cast(eNoSqlType))); + } + else + { + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = t.m_pSqlElementTemp->getTypeClass(); + obj.insert("sql_element_temp_type", QJsonValue(static_cast(eTypeSqlElement))); + obj.insert("sql_element_temp", qx::cvt::to_json((*t.m_pSqlElementTemp), format)); + } + + Q_FOREACH (qx::dao::detail::IxSqlElement_ptr pSqlElement, t.m_lstSqlElement) + { + QJsonObject item; + if (!pSqlElement) + { + item.insert("sql_element_type", QJsonValue(static_cast(eNoSqlType))); + arr.append(QJsonValue(item)); + continue; + } + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = pSqlElement->getTypeClass(); + item.insert("sql_element_type", QJsonValue(static_cast(eTypeSqlElement))); + item.insert("sql_element", qx::cvt::to_json((*pSqlElement), format)); + arr.append(QJsonValue(item)); + } + obj.insert("sql_element_list", QJsonValue(arr)); + + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::QxSqlQuery &t, const QString &format) + { + t = qx::QxSqlQuery(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + QHash lstResultPosByKey; + QVector> lstResultValues; + + if (obj.contains("sql")) + { + QJsonValue jsonSql = obj.value("sql"); + if (jsonSql.isString()) + { + t.m_sQuery.clear(); + t.m_sQuery << jsonSql.toString(); + } + } + else + { + qx::cvt::from_json(obj.value("query"), t.m_sQuery); + } + + if (obj.contains("params")) + { + QJsonArray arrParams = obj.value("params").toArray(); + for (int i = 0; i < arrParams.count(); i++) + { + QJsonValue objParam = arrParams.at(i); + if (!objParam.isObject()) + { + continue; + } + QJsonObject jsonParam = objParam.toObject(); + QSql::ParamType jsonParamType = QSql::In; + if (jsonParam.contains("type")) + { + QString paramType = jsonParam.value("type").toString(); + if (paramType == "in") + { + jsonParamType = QSql::In; + } + else if (paramType == "out") + { + jsonParamType = QSql::Out; + } + else if (paramType == "in_out") + { + jsonParamType = QSql::InOut; + } + else if (paramType == "binary") + { + jsonParamType = QSql::Binary; + } + } + QString jsonParamKey; + QVariant jsonParamValue; + qx::cvt::from_json(jsonParam.value("key"), jsonParamKey); + qx::cvt::from_json(jsonParam.value("value"), jsonParamValue); + if (jsonParamKey.isEmpty()) + { + t.bind(jsonParamValue, jsonParamType); + } + else + { + t.bind(jsonParamKey, jsonParamValue, jsonParamType); + } + } + } + else + { + qx::cvt::from_json(obj.value("list_values"), t.m_lstValue, format); + } + + t.m_iSqlElementIndex = qRound(obj.value("sql_element_index").toDouble()); + t.m_iParenthesisCount = qRound(obj.value("parenthesis_count").toDouble()); + t.m_bDistinct = obj.value("distinct").toBool(); + qx::cvt::from_json(obj.value("result_position_by_key"), lstResultPosByKey, format); + qx::cvt::from_json(obj.value("result_values"), lstResultValues, format); + t.m_vResponse = obj.value("response").toVariant(); + t.m_sType = obj.value("type").toString(); + qx::cvt::from_json(obj.value("list_join_query_user"), t.m_lstJoinQueryUser, format); + qx::cvt::from_json(obj.value("list_join_query_resolve"), t.m_lstJoinQueryToResolve, format); + + t.m_pSqlResult.reset(); + if ((lstResultPosByKey.count() > 0) || (lstResultValues.count() > 0)) + { + t.m_pSqlResult = std::shared_ptr(new qx::QxSqlQuery::QxSqlResult()); + t.m_pSqlResult->positionByKey = lstResultPosByKey; + t.m_pSqlResult->values = lstResultValues; + } + + t.m_pSqlElementTemp.reset(); + qx::dao::detail::IxSqlElement::type_class eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + eTypeSqlElement = static_cast(qRound(obj.value("sql_element_temp_type").toDouble())); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + t.m_pSqlElementTemp = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(t.m_pSqlElementTemp); + if (t.m_pSqlElementTemp) + { + qx::cvt::from_json(obj.value("sql_element_temp"), (*t.m_pSqlElementTemp), format); + } + } + + t.m_lstSqlElement.clear(); + QJsonArray arr = obj.value("sql_element_list").toArray(); + for (int i = 0; i < arr.count(); i++) + { + QJsonValue val = arr.at(i); + if (!val.isObject()) + { + continue; + } + QJsonObject item = val.toObject(); + qx::dao::detail::IxSqlElement_ptr pSqlElement; + eTypeSqlElement = qx::dao::detail::IxSqlElement::_no_type; + eTypeSqlElement = static_cast(qRound(item.value("sql_element_type").toDouble())); + if (eTypeSqlElement != qx::dao::detail::IxSqlElement::_no_type) + { + pSqlElement = qx::dao::detail::create_sql_element(eTypeSqlElement); + qAssert(pSqlElement); + if (pSqlElement) + { + qx::cvt::from_json(item.value("sql_element"), (*pSqlElement), format); + } + } + t.m_lstSqlElement.append(pSqlElement); + } + + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_QxTransaction.cpp b/src/QxSerialize/QJson/QxSerializeQJson_QxTransaction.cpp new file mode 100644 index 0000000..f8a3793 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_QxTransaction.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + QJsonValue QxConvert_ToJson_Helper(const qx::service::QxTransaction &t, const QString &format) + { + QJsonObject obj; + obj.insert("transaction_id", QJsonValue(t.m_sTransactionId)); + obj.insert("input_transaction_size", QJsonValue(static_cast(t.m_uiInputTransactionSize))); + obj.insert("output_transaction_size", QJsonValue(static_cast(t.m_uiOutputTransactionSize))); + obj.insert("dt_transaction_begin", qx::cvt::to_json(t.m_dtTransactionBegin, format)); + obj.insert("dt_transaction_request_sent", qx::cvt::to_json(t.m_dtTransactionRequestSent, format)); + obj.insert("dt_transaction_request_received", qx::cvt::to_json(t.m_dtTransactionRequestReceived, format)); + obj.insert("dt_transaction_reply_sent", qx::cvt::to_json(t.m_dtTransactionReplySent, format)); + obj.insert("dt_transaction_reply_received", qx::cvt::to_json(t.m_dtTransactionReplyReceived, format)); + obj.insert("dt_transaction_end", qx::cvt::to_json(t.m_dtTransactionEnd, format)); + obj.insert("ip_source", QJsonValue(t.m_sIpSource)); + obj.insert("ip_target", QJsonValue(t.m_sIpTarget)); + obj.insert("port_source", QJsonValue(static_cast(t.m_lPortSource))); + obj.insert("port_target", QJsonValue(static_cast(t.m_lPortTarget))); + obj.insert("service_name", QJsonValue(t.m_sServiceName)); + obj.insert("service_method", QJsonValue(t.m_sServiceMethod)); + obj.insert("message_return", qx::cvt::to_json(t.m_bMessageReturn, format)); + + QJsonValue input; + if (t.m_pInputParameter) + { + t.m_pInputParameter->registerClass(); + QString sClassName = t.m_pInputParameter->getClassName(); + obj.insert("input_parameter_class_name", sClassName); + input = t.m_pInputParameter->saveToJson(); + } + obj.insert("input_parameter", input); + + QJsonValue output; + if (t.m_pOutputParameter) + { + t.m_pOutputParameter->registerClass(); + QString sClassName = t.m_pOutputParameter->getClassName(); + obj.insert("output_parameter_class_name", sClassName); + output = t.m_pOutputParameter->saveToJson(); + } + obj.insert("output_parameter", output); + + return QJsonValue(obj); + } + + qx_bool QxConvert_FromJson_Helper(const QJsonValue &j, qx::service::QxTransaction &t, const QString &format) + { + t.clear(); + if (!j.isObject()) + { + return qx_bool(true); + } + QJsonObject obj = j.toObject(); + t.m_sTransactionId = obj.value("transaction_id").toString(); + t.m_uiInputTransactionSize = static_cast(qRound64(obj.value("input_transaction_size").toDouble())); + t.m_uiOutputTransactionSize = static_cast(qRound64(obj.value("output_transaction_size").toDouble())); + qx::cvt::from_json(obj.value("dt_transaction_begin"), t.m_dtTransactionBegin, format); + qx::cvt::from_json(obj.value("dt_transaction_request_sent"), t.m_dtTransactionRequestSent, format); + qx::cvt::from_json(obj.value("dt_transaction_request_received"), t.m_dtTransactionRequestReceived, format); + qx::cvt::from_json(obj.value("dt_transaction_reply_sent"), t.m_dtTransactionReplySent, format); + qx::cvt::from_json(obj.value("dt_transaction_reply_received"), t.m_dtTransactionReplyReceived, format); + qx::cvt::from_json(obj.value("dt_transaction_end"), t.m_dtTransactionEnd, format); + t.m_sIpSource = obj.value("ip_source").toString(); + t.m_sIpTarget = obj.value("ip_target").toString(); + t.m_lPortSource = static_cast(qRound64(obj.value("port_source").toDouble())); + t.m_lPortTarget = static_cast(qRound64(obj.value("port_target").toDouble())); + t.m_sServiceName = obj.value("service_name").toString(); + t.m_sServiceMethod = obj.value("service_method").toString(); + qx::cvt::from_json(obj.value("message_return"), t.m_bMessageReturn, format); + + t.m_pInputParameter.reset(); + if (obj.contains("input_parameter_class_name")) + { + QString sClassName = obj.value("input_parameter_class_name").toString(); + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::cvt::detail::QxConvert_FromJson< qx::service::QxTransaction >, loading QJson", "unable to create nude pointer for input parameter"); + } + else + { + ptr->registerClass(); + ptr->loadFromJson(obj.value("input_parameter")); + } + t.m_pInputParameter.reset(ptr); + } + + t.m_pOutputParameter.reset(); + if (obj.contains("output_parameter_class_name")) + { + QString sClassName = obj.value("output_parameter_class_name").toString(); + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::cvt::detail::QxConvert_FromJson< qx::service::QxTransaction >, loading QJson", "unable to create nude pointer for output parameter"); + } + else + { + ptr->registerClass(); + ptr->loadFromJson(obj.value("output_parameter")); + } + t.m_pOutputParameter.reset(ptr); + } + + return qx_bool(true); + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.cpp b/src/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.cpp new file mode 100644 index 0000000..c6c3ea2 --- /dev/null +++ b/src/QxSerialize/QJson/QxSerializeQJson_qx_registered_class.cpp @@ -0,0 +1,570 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifndef _QX_NO_JSON + +#include +#include + +#include + +#include + +#include + +namespace qx +{ + namespace cvt + { + namespace detail + { + + void QxSerializeJsonRegistered_saveHelper(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format); + void QxSerializeJsonRegistered_saveHelper_MongoDB(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format); + void QxSerializeJsonRegistered_saveHelper_WithFilter(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format); + + void QxSerializeJsonRegistered_loadHelper(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format); + void QxSerializeJsonRegistered_loadHelper_MongoDB(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format); + void QxSerializeJsonRegistered_loadHelper_WithFilter(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format); + + qx_bool QxSerializeJsonRegistered_initHierarchy_WithFilter(IxClass *pClass, const void *pOwner, const QString &format); + + QJsonValue QxSerializeJsonRegistered_Helper::save(IxClass *pClass, const void *pOwner, const QString &format) + { + if (!pClass || !pOwner) + { + qAssert(false); + return QJsonValue(); + } + bool bOnlyId = ((!format.isEmpty()) && ((format == QX_JSON_SERIALIZE_ONLY_ID) || (format == "mongodb:only_id") || (format == "mongodb:relation_id"))); + bool bCheckInstance = qx::serialization::helper::QxSerializeCheckInstance::contains(pOwner, pClass); + QJsonObject obj; + + if (bCheckInstance || bOnlyId) + { + qx::IxDataMember *pId = pClass->getId(true); + if (!pId) + { + return QJsonValue(); + } + QString key = ((format == "mongodb:only_id") ? QString("_id") : pId->getKey()); + QJsonValue val = pId->toJson(pOwner, format); + if (format == "mongodb:relation_id") + { + return val; + } + obj.insert(key, val); + return QJsonValue(obj); + } + + bool bMongoDB = format.startsWith("mongodb"); + bool bWithFilter = format.startsWith("filter:"); + qx_bool bHierarchyOk = (bWithFilter ? QxSerializeJsonRegistered_initHierarchy_WithFilter(pClass, pOwner, format) : qx_bool(true)); + if (!bHierarchyOk) + { + obj.insert("error", bHierarchyOk.getDesc()); + return QJsonValue(obj); + } + qx::serialization::helper::QxSerializeCheckInstance checker(pOwner, pClass); + Q_UNUSED(checker); + + do + { + if (bMongoDB) + { + qx::cvt::detail::QxSerializeJsonRegistered_saveHelper_MongoDB(obj, pClass, pOwner, format); + } + else if (bWithFilter) + { + qx::cvt::detail::QxSerializeJsonRegistered_saveHelper_WithFilter(obj, pClass, pOwner, format); + break; + } + else + { + qx::cvt::detail::QxSerializeJsonRegistered_saveHelper(obj, pClass, pOwner, format); + } + pClass = pClass->getBaseClass(); + } while (pClass != NULL); + + return QJsonValue(obj); + } + + qx_bool QxSerializeJsonRegistered_Helper::load(const QJsonValue &j, IxClass *pClass, void *pOwner, const QString &format) + { + if (!pClass || !pOwner) + { + qAssert(false); + return qx_bool(true); + } + if (!j.isObject()) + { + qx::IxDataMember *pId = pClass->getId(true); + if (!pId) + { + return qx_bool(true); + } + return pId->fromJson(pOwner, j, format); + } + + bool bMongoDB = format.startsWith("mongodb"); + bool bWithFilter = format.startsWith("filter:"); + QJsonObject obj = j.toObject(); + + do + { + if (bMongoDB) + { + qx::cvt::detail::QxSerializeJsonRegistered_loadHelper_MongoDB(obj, pClass, pOwner, format); + } + else if (bWithFilter) + { + qx::cvt::detail::QxSerializeJsonRegistered_loadHelper_WithFilter(obj, pClass, pOwner, format); + break; + } + else + { + qx::cvt::detail::QxSerializeJsonRegistered_loadHelper(obj, pClass, pOwner, format); + } + pClass = pClass->getBaseClass(); + } while (pClass != NULL); + + return qx_bool(true); + } + + qx_bool QxSerializeJsonRegistered_initHierarchy_WithFilter(IxClass *pClass, const void *pOwner, const QString &format) + { + qx_bool bHierarchyOk(true); + Q_UNUSED(pOwner); + if (!qx::serialization::helper::QxSerializeCheckInstance::isRoot()) + { + return bHierarchyOk; + } + std::shared_ptr pRelationLinked = qx::QxSqlRelationLinked::getHierarchy(pClass, format.right(format.size() - 7).split("|"), bHierarchyOk); + if (!bHierarchyOk || !pRelationLinked) + { + return qx_bool(false, bHierarchyOk.getDesc()); + } + + QString empty; + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy hierarchy = qMakePair(pRelationLinked, empty); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(hierarchy); + return bHierarchyOk; + } + + void QxSerializeJsonRegistered_saveHelper(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format) + { + qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + QJsonValue val = pDataMember->toJson(pOwner, format); + obj.insert(pDataMember->getKey(), val); + } + } + + void QxSerializeJsonRegistered_saveHelper_MongoDB(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format) + { + qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + bool bMongoDBColumns = (format.contains(":columns{") && format.contains("}")); + bool bMongoDBChild = format.startsWith("mongodb:child"); + + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize() || !pDataMember->getDao()) + { + continue; + } + if (bMongoDBColumns && !pDataMember->getIsPrimaryKey() && !format.contains("," + pDataMember->getKey() + ",")) + { + continue; + } + qx::IxSqlRelation *pRelation = pDataMember->getSqlRelation(); + qx::IxSqlRelation::relation_type eRelationType = (pRelation ? pRelation->getRelationType() : qx::IxSqlRelation::no_relation); + if ((eRelationType == qx::IxSqlRelation::one_to_many) || (eRelationType == qx::IxSqlRelation::many_to_many)) + { + continue; + } + QString key = ((!bMongoDBChild && pDataMember->getIsPrimaryKey()) ? QString("_id") : pDataMember->getKey()); + QString formatTmp = (pRelation ? QString("mongodb:relation_id") : (QString("mongodb:child:") + format)); + if (pDataMember->getIsPrimaryKey()) + { + QVariant id = pDataMember->toVariant(pOwner); + if (!qx::trait::is_valid_primary_key(id)) + { + continue; + } + } + QJsonValue val = pDataMember->toJson(pOwner, formatTmp); + obj.insert(key, val); + } + } + + void QxSerializeJsonRegistered_saveHelper_WithFilter(QJsonObject &obj, IxClass *pClass, const void *pOwner, const QString &format) + { + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy currHierarchy = qx::serialization::helper::QxSerializeCheckInstance::getHierarchy(); + std::shared_ptr pRelationLinked = currHierarchy.first; + QString sRelation = currHierarchy.second; + + if (!pRelationLinked || !pClass) + { + QString msg = ("hierarchy (relations linked) not found : " + sRelation); + qAssertMsg(false, "QxSerializeJsonRegistered_saveHelper_WithFilter", qPrintable(msg)); + return; + } + qx::QxSqlRelationLinked::type_lst_relation pRelations = pRelationLinked->getRelationX(); + + qx::IxDataMember *pDataMemberId = pClass->getId(true); + if (pDataMemberId) + { + QJsonValue val = pDataMemberId->toJson(pOwner, format); + obj.insert(pDataMemberId->getKey(), val); + } + + if (pRelationLinked->isRoot() && sRelation.isEmpty()) + { + std::shared_ptr> pDataMemberX = pClass->getSqlDataMemberX(); + if (!pDataMemberX) + { + return; + } + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->getByIndex(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if (!pRelationLinked->checkRootColumns(pDataMember->getKey())) + { + continue; + } + QJsonValue val = pDataMember->toJson(pOwner, format); + obj.insert(pDataMember->getKey(), val); + } + + for (auto itr = pRelations.begin(); itr != pRelations.end(); ++itr) + { + const qx::QxSqlRelationLinked::type_relation &item = itr->second; + qx::IxSqlRelation *pRelation = std::get<1>(item); + if (!pRelation) + { + continue; + } + qx::IxDataMember *pDataMember = pRelation->getDataMember(); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nextHierarchy = qMakePair(pRelationLinked, itr->first); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nextHierarchy); + QJsonValue val = pDataMember->toJson(pOwner, format); + obj.insert(pDataMember->getKey(), val); + } + + std::shared_ptr pNullRelationLinked; + QString empty; + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nullHierarchy = qMakePair(pNullRelationLinked, empty); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nullHierarchy); + } + else if (pRelations.exist(sRelation)) + { + const qx::QxSqlRelationLinked::type_relation &currRelation = pRelations.getByKey(sRelation); + qx::IxSqlRelation *pRelation = std::get<1>(currRelation); + if (!pRelation) + { + return; + } + QSet columns = std::get<2>(currRelation).first; + long l = 0; + qx::IxDataMember *pDataMember = NULL; + while ((pDataMember = pRelation->nextData(l))) + { + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if ((columns.count() > 0) && (!columns.contains(pDataMember->getKey()))) + { + continue; + } + QJsonValue val = pDataMember->toJson(pOwner, format); + obj.insert(pDataMember->getKey(), val); + } + + qx::QxSqlRelationLinked::type_lst_relation_linked allSubRelationsLinked = pRelationLinked->getRelationLinkedX(); + qx::QxSqlRelationLinked::type_ptr pSubRelationLinked = allSubRelationsLinked.value(pRelation->getKey()); + if (!pSubRelationLinked) + { + return; + } + qx::QxSqlRelationLinked::type_lst_relation pSubRelations = pSubRelationLinked->getRelationX(); + for (auto itr = pSubRelations.begin(); itr != pSubRelations.end(); ++itr) + { + const qx::QxSqlRelationLinked::type_relation &item = itr->second; + qx::IxSqlRelation *pSubRelation = std::get<1>(item); + if (!pSubRelation) + { + continue; + } + pDataMember = pSubRelation->getDataMember(); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nextHierarchy = qMakePair(pSubRelationLinked, itr->first); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nextHierarchy); + QJsonValue val = pDataMember->toJson(pOwner, format); + obj.insert(pDataMember->getKey(), val); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(currHierarchy); + } + } + else + { + qAssertMsg(false, "QxSerializeJsonRegistered_saveHelper_WithFilter", "unknown error"); + } + } + + void QxSerializeJsonRegistered_loadHelper(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format) + { + qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + QString key = pDataMember->getKey(); + if (obj.contains(key)) + { + pDataMember->fromJson(pOwner, obj.value(key), format); + } + } + } + + void QxSerializeJsonRegistered_loadHelper_MongoDB(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format) + { + qx::IxDataMemberX *pDataMemberX = (pClass ? pClass->getDataMemberX() : NULL); + if (!pDataMemberX) + { + return; + } + bool bMongoDBColumns = (format.contains(":columns{") && format.contains("}")); + bool bMongoDBChild = format.startsWith("mongodb:child"); + + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->get(l); + if (!pDataMember || !pDataMember->getSerialize() || !pDataMember->getDao()) + { + continue; + } + if (bMongoDBColumns && !pDataMember->getIsPrimaryKey() && !format.contains("," + pDataMember->getKey() + ",")) + { + continue; + } + QString key = ((!bMongoDBChild && pDataMember->getIsPrimaryKey()) ? QString("_id") : pDataMember->getKey()); + key = ((bMongoDBChild && pDataMember->getIsPrimaryKey() && (!obj.contains(key))) ? QString("_id") : key); + if (obj.contains(key)) + { + pDataMember->fromJson(pOwner, obj.value(key), (QString("mongodb:child:") + format)); + } + } + } + + void QxSerializeJsonRegistered_loadHelper_WithFilter(const QJsonObject &obj, IxClass *pClass, void *pOwner, const QString &format) + { + qx_bool bHierarchyOk = QxSerializeJsonRegistered_initHierarchy_WithFilter(pClass, pOwner, format); + if (!bHierarchyOk) + { + QString msg = bHierarchyOk.getDesc(); + qDebug("[QxOrm] !!! Error in QxSerializeJsonRegistered_loadHelper_WithFilter !!! : '%s'", qPrintable(msg)); + return; + } + qx::serialization::helper::QxSerializeCheckInstance checker(pOwner, pClass); + Q_UNUSED(checker); + + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy currHierarchy = qx::serialization::helper::QxSerializeCheckInstance::getHierarchy(); + std::shared_ptr pRelationLinked = currHierarchy.first; + QString sRelation = currHierarchy.second; + + if (!pRelationLinked || !pClass) + { + QString msg = ("hierarchy (relations linked) not found : " + sRelation); + qAssertMsg(false, "QxSerializeJsonRegistered_loadHelper_WithFilter", qPrintable(msg)); + return; + } + qx::QxSqlRelationLinked::type_lst_relation pRelations = pRelationLinked->getRelationX(); + + qx::IxDataMember *pDataMemberId = pClass->getId(true); + if (pDataMemberId && obj.contains(pDataMemberId->getKey())) + { + pDataMemberId->fromJson(pOwner, obj.value(pDataMemberId->getKey()), format); + } + + if (pRelationLinked->isRoot() && sRelation.isEmpty()) + { + std::shared_ptr> pDataMemberX = pClass->getSqlDataMemberX(); + if (!pDataMemberX) + { + return; + } + for (long l = 0; l < pDataMemberX->count(); l++) + { + qx::IxDataMember *pDataMember = pDataMemberX->getByIndex(l); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if (!pRelationLinked->checkRootColumns(pDataMember->getKey())) + { + continue; + } + if (obj.contains(pDataMember->getKey())) + { + pDataMember->fromJson(pOwner, obj.value(pDataMember->getKey()), format); + } + } + + for (auto itr = pRelations.begin(); itr != pRelations.end(); ++itr) + { + const qx::QxSqlRelationLinked::type_relation &item = itr->second; + qx::IxSqlRelation *pRelation = std::get<1>(item); + if (!pRelation) + { + continue; + } + qx::IxDataMember *pDataMember = pRelation->getDataMember(); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nextHierarchy = qMakePair(pRelationLinked, itr->first); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nextHierarchy); + if (obj.contains(pDataMember->getKey())) + { + pDataMember->fromJson(pOwner, obj.value(pDataMember->getKey()), format); + } + } + + std::shared_ptr pNullRelationLinked; + QString empty; + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nullHierarchy = qMakePair(pNullRelationLinked, empty); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nullHierarchy); + } + else if (pRelations.exist(sRelation)) + { + const qx::QxSqlRelationLinked::type_relation &currRelation = pRelations.getByKey(sRelation); + qx::IxSqlRelation *pRelation = std::get<1>(currRelation); + if (!pRelation) + { + return; + } + QSet columns = std::get<2>(currRelation).first; + long l = 0; + qx::IxDataMember *pDataMember = NULL; + while ((pDataMember = pRelation->nextData(l))) + { + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + if ((columns.count() > 0) && (!columns.contains(pDataMember->getKey()))) + { + continue; + } + if (obj.contains(pDataMember->getKey())) + { + pDataMember->fromJson(pOwner, obj.value(pDataMember->getKey()), format); + } + } + + qx::QxSqlRelationLinked::type_lst_relation_linked allSubRelationsLinked = pRelationLinked->getRelationLinkedX(); + qx::QxSqlRelationLinked::type_ptr pSubRelationLinked = allSubRelationsLinked.value(pRelation->getKey()); + if (!pSubRelationLinked) + { + return; + } + qx::QxSqlRelationLinked::type_lst_relation pSubRelations = pSubRelationLinked->getRelationX(); + for (auto itr = pSubRelations.begin(); itr != pSubRelations.end(); ++itr) + { + const qx::QxSqlRelationLinked::type_relation &item = itr->second; + qx::IxSqlRelation *pSubRelation = std::get<1>(item); + if (!pSubRelation) + { + continue; + } + pDataMember = pSubRelation->getDataMember(); + if (!pDataMember || !pDataMember->getSerialize()) + { + continue; + } + qx::serialization::helper::QxSerializeCheckInstance::type_hierarchy nextHierarchy = qMakePair(pSubRelationLinked, itr->first); + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(nextHierarchy); + if (obj.contains(pDataMember->getKey())) + { + pDataMember->fromJson(pOwner, obj.value(pDataMember->getKey()), format); + } + qx::serialization::helper::QxSerializeCheckInstance::setHierarchy(currHierarchy); + } + } + else + { + qAssertMsg(false, "QxSerializeJsonRegistered_loadHelper_WithFilter", "unknown error"); + } + } + + } // namespace detail + } // namespace cvt +} // namespace qx + +#endif // _QX_NO_JSON diff --git a/src/QxSerialize/Qt/QxSerialize_QBrush.cpp b/src/QxSerialize/Qt/QxSerialize_QBrush.cpp new file mode 100644 index 0000000..5c24381 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QBrush.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QBrush &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iStyle = static_cast(t.style()); + QColor color(t.color()); + QPixmap texture(t.texture()); + + ar << boost::serialization::make_nvp("style", iStyle); + ar << boost::serialization::make_nvp("color", color); + ar << boost::serialization::make_nvp("texture", texture); + } + + template + inline void qx_load(Archive &ar, QBrush &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iStyle = 0; + QColor color; + QPixmap texture; + + ar >> boost::serialization::make_nvp("style", iStyle); + ar >> boost::serialization::make_nvp("color", color); + ar >> boost::serialization::make_nvp("texture", texture); + + t.setStyle(static_cast(iStyle)); + ((iStyle == Qt::TexturePattern) ? t.setTexture(texture) : t.setColor(color)); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QBrush) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QByteArray.cpp b/src/QxSerialize/Qt/QxSerialize_QByteArray.cpp new file mode 100644 index 0000000..cd6d27f --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QByteArray.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QByteArray &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + std::string data(t.constData(), lCount); + ar << boost::serialization::make_nvp("size", lCount); + ar << boost::serialization::make_nvp("data", data); + } + + template + inline void qx_load(Archive &ar, QByteArray &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + std::string data; + t.clear(); + ar >> boost::serialization::make_nvp("size", lCount); + ar >> boost::serialization::make_nvp("data", data); + if (lCount > 0) + { + t = QByteArray(data.c_str(), lCount); + } + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QByteArray) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QColor.cpp b/src/QxSerialize/Qt/QxSerialize_QColor.cpp new file mode 100644 index 0000000..f8ecb6c --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QColor.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QColor &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QColor clr = t.toRgb(); + int iR(clr.red()), iG(clr.green()), iB(clr.blue()), iA(t.alpha()); + + ar << boost::serialization::make_nvp("R", iR); + ar << boost::serialization::make_nvp("G", iG); + ar << boost::serialization::make_nvp("B", iB); + ar << boost::serialization::make_nvp("A", iA); + } + + template + inline void qx_load(Archive &ar, QColor &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iR(0), iG(0), iB(0), iA(0); + + ar >> boost::serialization::make_nvp("R", iR); + ar >> boost::serialization::make_nvp("G", iG); + ar >> boost::serialization::make_nvp("B", iB); + ar >> boost::serialization::make_nvp("A", iA); + + t.setRed(iR); + t.setGreen(iG); + t.setBlue(iB); + t.setAlpha(iA); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QColor) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QDate.cpp b/src/QxSerialize/Qt/QxSerialize_QDate.cpp new file mode 100644 index 0000000..ceddf63 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QDate.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QDate &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDate = t.toString(QX_SERIALIZE_QDATE_FORMAT); + ar << boost::serialization::make_nvp(NULL, sDate); + } + + template + inline void qx_load(Archive &ar, QDate &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDate; + ar >> boost::serialization::make_nvp(NULL, sDate); + t = QDate::fromString(sDate, QX_SERIALIZE_QDATE_FORMAT); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QDate) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QDateTime.cpp b/src/QxSerialize/Qt/QxSerialize_QDateTime.cpp new file mode 100644 index 0000000..dc79a80 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QDateTime.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QDateTime &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDateTime = t.toString(QX_SERIALIZE_QDATETIME_FORMAT); + ar << boost::serialization::make_nvp(NULL, sDateTime); + } + + template + inline void qx_load(Archive &ar, QDateTime &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDateTime; + ar >> boost::serialization::make_nvp(NULL, sDateTime); + t = QDateTime::fromString(sDateTime, QX_SERIALIZE_QDATETIME_FORMAT); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QDateTime) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QFont.cpp b/src/QxSerialize/Qt/QxSerialize_QFont.cpp new file mode 100644 index 0000000..9949b89 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QFont.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QFont &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sFontAttr = t.toString(); + ar << boost::serialization::make_nvp(NULL, sFontAttr); + } + + template + inline void qx_load(Archive &ar, QFont &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sFontAttr; + ar >> boost::serialization::make_nvp(NULL, sFontAttr); + t.fromString(sFontAttr); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QFont) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QImage.cpp b/src/QxSerialize/Qt/QxSerialize_QImage.cpp new file mode 100644 index 0000000..bd4faff --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QImage.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(QImage) + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QImage &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + bool bIsNull = t.isNull(); + ar << boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + t.save(&buffer, "PNG"); + ar << boost::serialization::make_nvp("bytes", bytes); + } + + template + inline void qx_load(Archive &ar, QImage &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + t = QImage(); + bool bIsNull(false); + ar >> boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + ar >> boost::serialization::make_nvp("bytes", bytes); + t.loadFromData(bytes); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QImage) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QMatrix.cpp b/src/QxSerialize/Qt/QxSerialize_QMatrix.cpp new file mode 100644 index 0000000..b5d8017 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QMatrix.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QMatrix &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + double m11(t.m11()), m12(t.m12()), m21(t.m21()), m22(t.m22()), dx(t.dx()), dy(t.dy()); + + ar << boost::serialization::make_nvp("m11", m11); + ar << boost::serialization::make_nvp("m12", m12); + ar << boost::serialization::make_nvp("m21", m21); + ar << boost::serialization::make_nvp("m22", m22); + ar << boost::serialization::make_nvp("dx", dx); + ar << boost::serialization::make_nvp("dy", dy); + } + + template + inline void qx_load(Archive &ar, QMatrix &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + double m11(0.0), m12(0.0), m21(0.0), m22(0.0), dx(0.0), dy(0.0); + + ar >> boost::serialization::make_nvp("m11", m11); + ar >> boost::serialization::make_nvp("m12", m12); + ar >> boost::serialization::make_nvp("m21", m21); + ar >> boost::serialization::make_nvp("m22", m22); + ar >> boost::serialization::make_nvp("dx", dx); + ar >> boost::serialization::make_nvp("dy", dy); + + t.setMatrix(m11, m12, m21, m22, dx, dy); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QMatrix) + +#endif // _QX_ENABLE_QT_GUI +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QObject.cpp b/src/QxSerialize/Qt/QxSerialize_QObject.cpp new file mode 100644 index 0000000..fb2ea0b --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QObject.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(QObject) + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QObject &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QList propertyKeyList = t.dynamicPropertyNames(); + int iPropertyCount = propertyKeyList.count(); + std::pair pair_string_variant; + ar << boost::serialization::make_nvp("propertyCount", iPropertyCount); + + for (long l = 0; l < iPropertyCount; l++) + { + pair_string_variant.first = propertyKeyList.at(l).constData(); + pair_string_variant.second = t.property(pair_string_variant.first.c_str()); + ar << boost::serialization::make_nvp("property", pair_string_variant); + } + } + + template + inline void qx_load(Archive &ar, QObject &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iPropertyCount = 0; + std::pair pair_string_variant; + ar >> boost::serialization::make_nvp("propertyCount", iPropertyCount); + + for (long l = 0; l < iPropertyCount; l++) + { + ar >> boost::serialization::make_nvp("property", pair_string_variant); + t.setProperty(pair_string_variant.first.c_str(), pair_string_variant.second); + } + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QObject) +QX_REGISTER_BOOST_SERIALIZE_HELPER_CPP(QObject) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QPicture.cpp b/src/QxSerialize/Qt/QxSerialize_QPicture.cpp new file mode 100644 index 0000000..ed14fd2 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QPicture.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(QPicture) + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QPicture &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + bool bIsNull = t.isNull(); + ar << boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + QBuffer buffer(&bytes); + QPicture *pTmp = const_cast(&t); + buffer.open(QIODevice::ReadWrite); + pTmp->save(&buffer, "PNG"); + ar << boost::serialization::make_nvp("bytes", bytes); + } + + template + inline void qx_load(Archive &ar, QPicture &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + t = QPicture(); + bool bIsNull(false); + ar >> boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + ar >> boost::serialization::make_nvp("bytes", bytes); + t.load(&buffer, "PNG"); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QPicture) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QPixmap.cpp b/src/QxSerialize/Qt/QxSerialize_QPixmap.cpp new file mode 100644 index 0000000..cc5e1ec --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QPixmap.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +QX_BOOST_EXPORT_SERIALIZATION_FAST_COMPIL_CPP(QPixmap) + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QPixmap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + bool bIsNull = t.isNull(); + ar << boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadWrite); + t.save(&buffer, "PNG"); + ar << boost::serialization::make_nvp("bytes", bytes); + } + + template + inline void qx_load(Archive &ar, QPixmap &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + t = QPixmap(); + bool bIsNull(false); + ar >> boost::serialization::make_nvp("null", bIsNull); + if (bIsNull) + { + return; + } + + QByteArray bytes; + ar >> boost::serialization::make_nvp("bytes", bytes); + t.loadFromData(bytes); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QPixmap) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QPoint.cpp b/src/QxSerialize/Qt/QxSerialize_QPoint.cpp new file mode 100644 index 0000000..e6d1de4 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QPoint.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_serialize(Archive &ar, QPoint &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("x", t.rx()); + ar &boost::serialization::make_nvp("y", t.ry()); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SERIALIZE_CPP(QPoint) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QRect.cpp b/src/QxSerialize/Qt/QxSerialize_QRect.cpp new file mode 100644 index 0000000..f84a554 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QRect.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QRect &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iLeft(t.left()), iRight(t.right()), iTop(t.top()), iBottom(t.bottom()); + + ar << boost::serialization::make_nvp("left", iLeft); + ar << boost::serialization::make_nvp("right", iRight); + ar << boost::serialization::make_nvp("top", iTop); + ar << boost::serialization::make_nvp("bottom", iBottom); + } + + template + inline void qx_load(Archive &ar, QRect &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iLeft(0), iRight(0), iTop(0), iBottom(0); + + ar >> boost::serialization::make_nvp("left", iLeft); + ar >> boost::serialization::make_nvp("right", iRight); + ar >> boost::serialization::make_nvp("top", iTop); + ar >> boost::serialization::make_nvp("bottom", iBottom); + + t.setTop(iTop); + t.setBottom(iBottom); + t.setLeft(iLeft); + t.setRight(iRight); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QRect) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QRegExp.cpp b/src/QxSerialize/Qt/QxSerialize_QRegExp.cpp new file mode 100644 index 0000000..4d6b2b9 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QRegExp.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QRegExp &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sPattern = t.pattern(); + int iCaseSensitivity = static_cast(t.caseSensitivity()); + int iPatternSyntax = static_cast(t.patternSyntax()); + bool bMinimal = t.isMinimal(); + + ar << boost::serialization::make_nvp("pattern", sPattern); + ar << boost::serialization::make_nvp("caseSensitivity", iCaseSensitivity); + ar << boost::serialization::make_nvp("patternSyntax", iPatternSyntax); + ar << boost::serialization::make_nvp("minimal", bMinimal); + } + + template + inline void qx_load(Archive &ar, QRegExp &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sPattern; + bool bMinimal(false); + int iCaseSensitivity(0), iPatternSyntax(0); + + ar >> boost::serialization::make_nvp("pattern", sPattern); + ar >> boost::serialization::make_nvp("caseSensitivity", iCaseSensitivity); + ar >> boost::serialization::make_nvp("patternSyntax", iPatternSyntax); + ar >> boost::serialization::make_nvp("minimal", bMinimal); + + t.setPattern(sPattern); + t.setCaseSensitivity(static_cast(iCaseSensitivity)); + t.setPatternSyntax(static_cast(iPatternSyntax)); + t.setMinimal(bMinimal); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QRegExp) + +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QRegion.cpp b/src/QxSerialize/Qt/QxSerialize_QRegion.cpp new file mode 100644 index 0000000..b9a09d3 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QRegion.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#ifdef _QX_ENABLE_QT_GUI + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QRegion &t, const unsigned int file_version) + { + Q_UNUSED(file_version); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + QVector rectList(t.begin(), t.end()); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + QVector rectList = t.rects(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + ar << boost::serialization::make_nvp("rectList", rectList); + } + + template + inline void qx_load(Archive &ar, QRegion &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QVector rectList; + ar >> boost::serialization::make_nvp("rectList", rectList); + t.setRects(rectList.data(), rectList.count()); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QRegion) + +#endif // _QX_ENABLE_QT_GUI +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QSize.cpp b/src/QxSerialize/Qt/QxSerialize_QSize.cpp new file mode 100644 index 0000000..d6c89b8 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QSize.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_serialize(Archive &ar, QSize &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + ar &boost::serialization::make_nvp("width", t.rwidth()); + ar &boost::serialization::make_nvp("height", t.rheight()); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SERIALIZE_CPP(QSize) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QSqlError.cpp b/src/QxSerialize/Qt/QxSerialize_QSqlError.cpp new file mode 100644 index 0000000..ae7c62b --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QSqlError.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QSqlError &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDatabaseText = t.databaseText(); + QString sDriverText = t.driverText(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int iNumber = t.nativeErrorCode().toInt(); + QString sNativeErrorCode = t.nativeErrorCode(); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int iNumber = t.number(); + QString sNativeErrorCode = ""; +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + int iType = static_cast(t.type()); + + ar << boost::serialization::make_nvp("database_text", sDatabaseText); + ar << boost::serialization::make_nvp("driver_text", sDriverText); + ar << boost::serialization::make_nvp("number", iNumber); + ar << boost::serialization::make_nvp("type", iType); + ar << boost::serialization::make_nvp("native_error_code", sNativeErrorCode); + } + + template + inline void qx_load(Archive &ar, QSqlError &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sDatabaseText; + QString sDriverText; + int iNumber(0); + int iType(0); + QString sNativeErrorCode; + + ar >> boost::serialization::make_nvp("database_text", sDatabaseText); + ar >> boost::serialization::make_nvp("driver_text", sDriverText); + ar >> boost::serialization::make_nvp("number", iNumber); + ar >> boost::serialization::make_nvp("type", iType); + ar >> boost::serialization::make_nvp("native_error_code", sNativeErrorCode); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t = QSqlError(sDriverText, sDatabaseText, static_cast(iType), sNativeErrorCode); +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + t.setDatabaseText(sDatabaseText); + t.setDriverText(sDriverText); + t.setNumber(iNumber); + t.setType(static_cast(iType)); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0)) + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QSqlError) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QString.cpp b/src/QxSerialize/Qt/QxSerialize_QString.cpp new file mode 100644 index 0000000..d55d2df --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QString.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + struct qx_serialize_qstring + { + + template + static inline void save(Archive &ar, const QString &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + char cell, row; + long lSize = t.size(); + ar << boost::serialization::make_nvp("size", lSize); + const QChar *qcharPtr = t.constData(); + for (long l = 0; l < lSize; ++l) + { + cell = static_cast(qcharPtr[l].cell()); + row = static_cast(qcharPtr[l].row()); + ar << boost::serialization::make_nvp(NULL, cell); + ar << boost::serialization::make_nvp(NULL, row); + } + } + + template + static inline void load(Archive &ar, QString &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + char cell, row; + long lSize = 0; + ar >> boost::serialization::make_nvp("size", lSize); + t.clear(); + t.reserve(lSize); + for (long l = 0; l < lSize; ++l) + { + ar >> boost::serialization::make_nvp(NULL, cell); + ar >> boost::serialization::make_nvp(NULL, row); + t.append(QChar(cell, row)); + } + } + }; + + template <> + struct qx_serialize_qstring + { + + template + static inline void save(Archive &ar, const QString &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + typedef typename qx::trait::archive_wide_traits::type_string qx_type_string_tmp; + qx_type_string_tmp str; + qx::trait::archive_wide_traits::fromQString(t, str); + ar << boost::serialization::make_nvp(NULL, str); + } + + template + static inline void load(Archive &ar, QString &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + typedef typename qx::trait::archive_wide_traits::type_string qx_type_string_tmp; + qx_type_string_tmp str; + ar >> boost::serialization::make_nvp(NULL, str); + t = qx::trait::archive_wide_traits::toQString(str); + } + }; + + template + inline void qx_save(Archive &ar, const QString &t, const unsigned int file_version) + { + qx_serialize_qstring::value>::save(ar, t, file_version); + } + + template + inline void qx_load(Archive &ar, QString &t, const unsigned int file_version) + { + qx_serialize_qstring::value>::load(ar, t, file_version); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QString) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QStringList.cpp b/src/QxSerialize/Qt/QxSerialize_QStringList.cpp new file mode 100644 index 0000000..1471a98 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QStringList.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QStringList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = t.count(); + ar << boost::serialization::make_nvp("count", lCount); + + for (long l = 0; l < lCount; l++) + ar << boost::serialization::make_nvp("item", t.at(l)); + } + + template + inline void qx_load(Archive &ar, QStringList &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + long lCount = 0; + ar >> boost::serialization::make_nvp("count", lCount); + + t.clear(); + QString item; + + for (long l = 0; l < lCount; l++) + { + ar >> boost::serialization::make_nvp("item", item); + t.append(item); + } + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QStringList) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QTime.cpp b/src/QxSerialize/Qt/QxSerialize_QTime.cpp new file mode 100644 index 0000000..d69047f --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QTime.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QTime &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sTime = t.toString(QX_SERIALIZE_QTIME_FORMAT); + ar << boost::serialization::make_nvp(NULL, sTime); + } + + template + inline void qx_load(Archive &ar, QTime &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sTime; + ar >> boost::serialization::make_nvp(NULL, sTime); + t = QTime::fromString(sTime, QX_SERIALIZE_QTIME_FORMAT); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QTime) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QUrl.cpp b/src/QxSerialize/Qt/QxSerialize_QUrl.cpp new file mode 100644 index 0000000..c4c0e11 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QUrl.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QUrl &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sUrl = t.toString(); + ar << boost::serialization::make_nvp(NULL, sUrl); + } + + template + inline void qx_load(Archive &ar, QUrl &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sUrl; + ar >> boost::serialization::make_nvp(NULL, sUrl); + t = QUrl(sUrl); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QUrl) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QUuid.cpp b/src/QxSerialize/Qt/QxSerialize_QUuid.cpp new file mode 100644 index 0000000..13a8633 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QUuid.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QUuid &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sUuid = t.toString(); + ar << boost::serialization::make_nvp("uuid", sUuid); + } + + template + inline void qx_load(Archive &ar, QUuid &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sUuid; + ar >> boost::serialization::make_nvp("uuid", sUuid); + t = QUuid(sUuid); + } + + } // namespace boost +} // namespace serialization + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QUuid) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/Qt/QxSerialize_QVariant.cpp b/src/QxSerialize/Qt/QxSerialize_QVariant.cpp new file mode 100644 index 0000000..15f4585 --- /dev/null +++ b/src/QxSerialize/Qt/QxSerialize_QVariant.cpp @@ -0,0 +1,463 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +#include + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const QVariant &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iType = static_cast(t.type()); + ar << boost::serialization::make_nvp("type", iType); + const char *sTag = "value"; + + if (iType == QVariant::Bool) + { + bool b(false); + b = t.toBool(); + ar << boost::serialization::make_nvp(sTag, b); + } + else if (iType == QVariant::Int) + { + int i(0); + i = t.toInt(); + ar << boost::serialization::make_nvp(sTag, i); + } + else if (iType == QVariant::UInt) + { + uint ui(0); + ui = t.toUInt(); + ar << boost::serialization::make_nvp(sTag, ui); + } + else if (iType == QVariant::LongLong) + { + long l(0); + l = static_cast(t.toLongLong()); + ar << boost::serialization::make_nvp(sTag, l); + } + else if (iType == QVariant::ULongLong) + { + unsigned long ul(0); + ul = static_cast(t.toULongLong()); + ar << boost::serialization::make_nvp(sTag, ul); + } + else if (iType == QVariant::Double) + { + double d(0.0); + d = t.toDouble(); + ar << boost::serialization::make_nvp(sTag, d); + } + else if (iType == QVariant::String) + { + QString s; + s = t.toString(); + ar << boost::serialization::make_nvp(sTag, s); + } + else if (iType == QVariant::Date) + { + QDate qdate; + qdate = t.toDate(); + ar << boost::serialization::make_nvp(sTag, qdate); + } + else if (iType == QVariant::DateTime) + { + QDateTime qdatetime; + qdatetime = t.toDateTime(); + ar << boost::serialization::make_nvp(sTag, qdatetime); + } + else if (iType == QVariant::Time) + { + QTime qtime; + qtime = t.toTime(); + ar << boost::serialization::make_nvp(sTag, qtime); + } + else if (iType == QVariant::ByteArray) + { + QByteArray qbytearray; + qbytearray = t.toByteArray(); + ar << boost::serialization::make_nvp(sTag, qbytearray); + } + else if (iType == QVariant::Point) + { + QPoint qpoint; + qpoint = t.toPoint(); + ar << boost::serialization::make_nvp(sTag, qpoint); + } + else if (iType == QVariant::Rect) + { + QRect qrect; + qrect = t.toRect(); + ar << boost::serialization::make_nvp(sTag, qrect); + } + else if (iType == QVariant::Size) + { + QSize qsize; + qsize = t.toSize(); + ar << boost::serialization::make_nvp(sTag, qsize); + } +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + else if (iType == QVariant::RegExp) + { + QRegExp qregexp; + qregexp = t.toRegExp(); + ar << boost::serialization::make_nvp(sTag, qregexp); + } +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + else if (iType == QVariant::Url) + { + QUrl qurl; + qurl = t.toUrl(); + ar << boost::serialization::make_nvp(sTag, qurl); + } +#ifdef _QX_ENABLE_QT_GUI + else if (iType == QVariant::Brush) + { + QBrush qbrush; + qbrush = t.value(); + ar << boost::serialization::make_nvp(sTag, qbrush); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Color) + { + QColor qcolor; + qcolor = t.value(); + ar << boost::serialization::make_nvp(sTag, qcolor); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Font) + { + QFont qfont; + qfont = t.value(); + ar << boost::serialization::make_nvp(sTag, qfont); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Image) + { + QImage qimage; + qimage = t.value(); + ar << boost::serialization::make_nvp(sTag, qimage); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Pixmap) + { + QPixmap qpixmap; + qpixmap = t.value(); + ar << boost::serialization::make_nvp(sTag, qpixmap); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Region) + { + QRegion qregion; + qregion = t.value(); + ar << boost::serialization::make_nvp(sTag, qregion); + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ +#endif // _QX_ENABLE_QT_GUI + else if (iType == QVariant::Invalid) + { + QString sInvalid; + ar << boost::serialization::make_nvp(sTag, sInvalid); + } + else if (iType == QMetaType::Long) + { + long l(0); + l = static_cast(t.toLongLong()); + ar << boost::serialization::make_nvp(sTag, l); + } + else if (iType == QMetaType::Short) + { + int i(0); + i = t.toInt(); + ar << boost::serialization::make_nvp(sTag, i); + } + else if (iType == QMetaType::Char) + { + int i(0); + i = t.toInt(); + ar << boost::serialization::make_nvp(sTag, i); + } + else if (iType == QMetaType::ULong) + { + unsigned long ul(0); + ul = static_cast(t.toULongLong()); + ar << boost::serialization::make_nvp(sTag, ul); + } + else if (iType == QMetaType::UShort) + { + uint ui(0); + ui = t.toUInt(); + ar << boost::serialization::make_nvp(sTag, ui); + } + else if (iType == QMetaType::UChar) + { + uint ui(0); + ui = t.toUInt(); + ar << boost::serialization::make_nvp(sTag, ui); + } + else if (iType == QMetaType::Float) + { + double d(0.0); + d = t.toDouble(); + ar << boost::serialization::make_nvp(sTag, d); + } + else + { + QString sUserType("unknown variant serialize type"); + qx::QxClassX::type_fct_save_qvariant_usertype fct; + fct = qx::QxClassX::getFctSaveQVariantUserType(); + if (fct) + { + sUserType = fct(t, iType, file_version); + } + ar << boost::serialization::make_nvp(sTag, sUserType); + } + } + + template + inline void qx_load(Archive &ar, QVariant &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + int iType = 0; + ar >> boost::serialization::make_nvp("type", iType); + const char *sTag = "value"; + + if (iType == QVariant::Bool) + { + bool b(false); + ar >> boost::serialization::make_nvp(sTag, b); + t = QVariant(b); + } + else if (iType == QVariant::Int) + { + int i(0); + ar >> boost::serialization::make_nvp(sTag, i); + t = QVariant(i); + } + else if (iType == QVariant::UInt) + { + uint ui(0); + ar >> boost::serialization::make_nvp(sTag, ui); + t = QVariant(ui); + } + else if (iType == QVariant::LongLong) + { + long l(0); + ar >> boost::serialization::make_nvp(sTag, l); + t = QVariant(static_cast(l)); + } + else if (iType == QVariant::ULongLong) + { + unsigned long ul(0); + ar >> boost::serialization::make_nvp(sTag, ul); + t = QVariant(static_cast(ul)); + } + else if (iType == QVariant::Double) + { + double d(0.0); + ar >> boost::serialization::make_nvp(sTag, d); + t = QVariant(d); + } + else if (iType == QVariant::String) + { + QString s; + ar >> boost::serialization::make_nvp(sTag, s); + t = QVariant(s); + } + else if (iType == QVariant::Date) + { + QDate qdate; + ar >> boost::serialization::make_nvp(sTag, qdate); + t = QVariant(qdate); + } + else if (iType == QVariant::DateTime) + { + QDateTime qdatetime; + ar >> boost::serialization::make_nvp(sTag, qdatetime); + t = QVariant(qdatetime); + } + else if (iType == QVariant::Time) + { + QTime qtime; + ar >> boost::serialization::make_nvp(sTag, qtime); + t = QVariant(qtime); + } + else if (iType == QVariant::ByteArray) + { + QByteArray qbytearray; + ar >> boost::serialization::make_nvp(sTag, qbytearray); + t = QVariant(qbytearray); + } + else if (iType == QVariant::Point) + { + QPoint qpoint; + ar >> boost::serialization::make_nvp(sTag, qpoint); + t = QVariant(qpoint); + } + else if (iType == QVariant::Rect) + { + QRect qrect; + ar >> boost::serialization::make_nvp(sTag, qrect); + t = QVariant(qrect); + } + else if (iType == QVariant::Size) + { + QSize qsize; + ar >> boost::serialization::make_nvp(sTag, qsize); + t = QVariant(qsize); + } + else if (iType == QVariant::RegExp) + { + QRegExp qregexp; + ar >> boost::serialization::make_nvp(sTag, qregexp); + t = QVariant(qregexp); + } + else if (iType == QVariant::Url) + { + QUrl qurl; + ar >> boost::serialization::make_nvp(sTag, qurl); + t = QVariant(qurl); + } +#ifdef _QX_ENABLE_QT_GUI + else if (iType == QVariant::Brush) + { + QBrush qbrush; + ar >> boost::serialization::make_nvp(sTag, qbrush); + t = qbrush; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Color) + { + QColor qcolor; + ar >> boost::serialization::make_nvp(sTag, qcolor); + t = qcolor; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Font) + { + QFont qfont; + ar >> boost::serialization::make_nvp(sTag, qfont); + t = qfont; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Image) + { + QImage qimage; + ar >> boost::serialization::make_nvp(sTag, qimage); + t = qimage; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Pixmap) + { + QPixmap qpixmap; + ar >> boost::serialization::make_nvp(sTag, qpixmap); + t = qpixmap; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ + else if (iType == QVariant::Region) + { + QRegion qregion; + ar >> boost::serialization::make_nvp(sTag, qregion); + t = qregion; + } /* if you crash on this line, please check in your main() function if you have created a QApplication and not a QCoreApplication ! */ +#endif // _QX_ENABLE_QT_GUI + else if (iType == QVariant::Invalid) + { + QString sInvalid; + ar >> boost::serialization::make_nvp(sTag, sInvalid); + t = QVariant(); + } + else if (iType == QMetaType::Long) + { + long l(0); + ar >> boost::serialization::make_nvp(sTag, l); + t = QVariant(static_cast(l)); + } + else if (iType == QMetaType::Short) + { + int i(0); + ar >> boost::serialization::make_nvp(sTag, i); + t = QVariant(i); + } + else if (iType == QMetaType::Char) + { + int i(0); + ar >> boost::serialization::make_nvp(sTag, i); + t = QVariant(i); + } + else if (iType == QMetaType::ULong) + { + unsigned long ul(0); + ar >> boost::serialization::make_nvp(sTag, ul); + t = QVariant(static_cast(ul)); + } + else if (iType == QMetaType::UShort) + { + uint ui(0); + ar >> boost::serialization::make_nvp(sTag, ui); + t = QVariant(ui); + } + else if (iType == QMetaType::UChar) + { + uint ui(0); + ar >> boost::serialization::make_nvp(sTag, ui); + t = QVariant(ui); + } + else if (iType == QMetaType::Float) + { + double d(0.0); + ar >> boost::serialization::make_nvp(sTag, d); + t = QVariant(d); + } + else + { + QString sUserType; + qx::QxClassX::type_fct_load_qvariant_usertype fct; + ar >> boost::serialization::make_nvp(sTag, sUserType); + fct = qx::QxClassX::getFctLoadQVariantUserType(); + if (fct) + { + t = fct(sUserType, iType, file_version); + } + else + { + t = QVariant(); + } + } + } + + } // namespace serialization +} // namespace boost + +QX_SERIALIZE_FAST_COMPIL_SAVE_LOAD_CPP(QVariant) + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.cpp b/src/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.cpp new file mode 100644 index 0000000..fcae11a --- /dev/null +++ b/src/QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include +#include + +#include + +namespace qx +{ + + IxBoostSerializeRegisterHelper::IxBoostSerializeRegisterHelper(const QString &sKey) : m_sKey(sKey) + { + QxBoostSerializeRegisterHelperX::getSingleton()->add(m_sKey, this); + } + + IxBoostSerializeRegisterHelper::~IxBoostSerializeRegisterHelper() + { + if (!QxBoostSerializeRegisterHelperX::isSingletonNull()) + QxBoostSerializeRegisterHelperX::getSingleton()->remove(m_sKey); + } + +} // namespace qx + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.cpp b/src/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.cpp new file mode 100644 index 0000000..ad77971 --- /dev/null +++ b/src/QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxBoostSerializeRegisterHelperX) + +namespace qx +{ + + void QxBoostSerializeRegisterHelperX::add(const QString &sKey, IxBoostSerializeRegisterHelper *p) + { + QMutexLocker locker(&m_oMutexHelperX); + qAssert(!sKey.isEmpty() && !m_colHelperX.exist(sKey)); + + if (!p || sKey.isEmpty() || m_colHelperX.exist(sKey)) + return; + + m_colHelperX.insert(sKey, p); + } + + void QxBoostSerializeRegisterHelperX::remove(const QString &sKey) + { + QMutexLocker locker(&m_oMutexHelperX); + m_colHelperX.removeByKey(sKey); + } + +} // namespace qx + +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxSerialize/QxSerializeCheckInstance.cpp b/src/QxSerialize/QxSerializeCheckInstance.cpp new file mode 100644 index 0000000..97c57ff --- /dev/null +++ b/src/QxSerialize/QxSerializeCheckInstance.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +#include + +namespace qx +{ + namespace serialization + { + namespace helper + { + + QSet>> QxSerializeCheckInstance::m_lstInstanceByThread; + QHash QxSerializeCheckInstance::m_hashLevelByThread; + QHash QxSerializeCheckInstance::m_hashHierarchyByThread; + QMutex QxSerializeCheckInstance::m_mutex; + + QxSerializeCheckInstance::QxSerializeCheckInstance(const void *pInstance, qx::IxClass *pClass) : m_pInstance(0), m_lThreadId(0), m_pClass(pClass) + { + QMutexLocker locker(&m_mutex); + m_pInstance = reinterpret_cast(const_cast(pInstance)); + m_lThreadId = QThread::currentThreadId(); + qAssert(m_pInstance != 0); + m_lstInstanceByThread.insert(qMakePair(m_lThreadId, qMakePair(m_pInstance, m_pClass))); + int iLevel = (m_hashLevelByThread.value(m_lThreadId, 0) + 1); + m_hashLevelByThread.insert(m_lThreadId, iLevel); + } + + QxSerializeCheckInstance::~QxSerializeCheckInstance() + { + QMutexLocker locker(&m_mutex); + m_lstInstanceByThread.remove(qMakePair(m_lThreadId, qMakePair(m_pInstance, m_pClass))); + int iLevel = (m_hashLevelByThread.value(m_lThreadId, 0) - 1); + m_hashLevelByThread.insert(m_lThreadId, iLevel); + if (iLevel <= 0) + { + m_hashHierarchyByThread.remove(m_lThreadId); + } + } + + bool QxSerializeCheckInstance::contains(const void *pInstance, qx::IxClass *pClass) + { + QMutexLocker locker(&m_mutex); + Qt::HANDLE lCurrThreadId = QThread::currentThreadId(); + qptrdiff iInstance = reinterpret_cast(const_cast(pInstance)); + return m_lstInstanceByThread.contains(qMakePair(lCurrThreadId, qMakePair(iInstance, pClass))); + } + + bool QxSerializeCheckInstance::isRoot() + { + QMutexLocker locker(&m_mutex); + Qt::HANDLE lThreadId = QThread::currentThreadId(); + int iLevel = m_hashLevelByThread.value(lThreadId, 0); + qAssert(iLevel >= 0); + return (iLevel == 0); + } + + QxSerializeCheckInstance::type_hierarchy QxSerializeCheckInstance::getHierarchy() + { + QMutexLocker locker(&m_mutex); + Qt::HANDLE lThreadId = QThread::currentThreadId(); + return m_hashHierarchyByThread.value(lThreadId); + } + + void QxSerializeCheckInstance::setHierarchy(const QxSerializeCheckInstance::type_hierarchy &hierarchy) + { + QMutexLocker locker(&m_mutex); + Qt::HANDLE lThreadId = QThread::currentThreadId(); + m_hashHierarchyByThread.insert(lThreadId, hierarchy); + } + + } // namespace helper + } // namespace serialization +} // namespace qx diff --git a/src/QxSerialize/boost/QxExportDllBoostArchive.cpp b/src/QxSerialize/boost/QxExportDllBoostArchive.cpp new file mode 100644 index 0000000..43aab8d --- /dev/null +++ b/src/QxSerialize/boost/QxExportDllBoostArchive.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +#include + +#if _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON + +#include + +#include + +#include + +#if (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::archive_serializer_map, Archive) +#else // (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION > 103800) + +#if (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_CPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::archive_serializer_map, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::archive_serializer_map, ArchiveOut) +#else // (BOOST_VERSION > 103800) +#define QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_CPP(ArchiveIn, ArchiveOut) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::archive_pointer_iserializer, ArchiveIn) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::archive_pointer_oserializer, ArchiveOut) +#endif // (BOOST_VERSION > 103800) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::save_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::save_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::save_non_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::save_non_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::save_enum_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::save_enum_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::save_array_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::save_array_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::load_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::load_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::load_non_pointer_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::load_non_pointer_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::load_enum_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::load_enum_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#if (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(struct, boost::archive::detail::load_array_type, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::load_array_type, Archive) +#else // (BOOST_VERSION >= 104100) +#define QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_CPP(Archive) /* Nothing */ +#endif // (BOOST_VERSION >= 104100) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_IARCHIVE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::interface_iarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::interface_iarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_OARCHIVE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::interface_oarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::interface_oarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_IARCHIVE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::common_iarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::common_iarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_OARCHIVE_CPP(Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_P1_CPP(class, boost::archive::detail::common_oarchive, Archive) \ + QX_DLL_EXPORT_TEMPLATE_T_U_P1_CPP(class, boost::serialization::singleton, boost::archive::detail::common_oarchive, Archive) + +#define QX_BOOST_EXPORT_ARCHIVE_INTERFACE_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_IARCHIVE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_OARCHIVE_CPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_COMMON_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_IARCHIVE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_OARCHIVE_CPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_SINGLETON_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_NON_POINTER_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_POINTER_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ENUM_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_SAVE_ARRAY_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_NON_POINTER_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_POINTER_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ENUM_TYPE_CPP(ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_CPP(ArchiveIn) \ + QX_BOOST_EXPORT_ARCHIVE_LOAD_ARRAY_TYPE_CPP(ArchiveOut) + +#define QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_INTERFACE_CPP(ArchiveIn, ArchiveOut) \ + QX_BOOST_EXPORT_ARCHIVE_COMMON_CPP(ArchiveIn, ArchiveOut) + +#if _QX_SERIALIZE_POLYMORPHIC +QX_BOOST_EXPORT_ARCHIVE_CPP(boost::archive::polymorphic_iarchive, boost::archive::polymorphic_oarchive) +QX_BOOST_EXPORT_ARCHIVE_CPP(boost::archive::polymorphic_binary_iarchive, boost::archive::polymorphic_binary_oarchive) +QX_BOOST_EXPORT_ARCHIVE_CPP(boost::archive::polymorphic_text_iarchive, boost::archive::polymorphic_text_oarchive) +QX_BOOST_EXPORT_ARCHIVE_CPP(boost::archive::polymorphic_xml_iarchive, boost::archive::polymorphic_xml_oarchive) +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::binary_iarchive, boost::archive::binary_oarchive) +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::text_iarchive, boost::archive::text_oarchive) +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::xml_iarchive, boost::archive::xml_oarchive) +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY +QX_BOOST_EXPORT_ARCHIVE_SERIALIZER_MAP_CPP(eos::portable_iarchive, eos::portable_oarchive) +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(eos::portable_iarchive, eos::portable_oarchive) +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#if _QX_SERIALIZE_WIDE_BINARY +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::binary_wiarchive, boost::archive::binary_woarchive) +#endif // _QX_SERIALIZE_WIDE_BINARY + +#if _QX_SERIALIZE_WIDE_TEXT +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::text_wiarchive, boost::archive::text_woarchive) +#endif // _QX_SERIALIZE_WIDE_TEXT + +#if _QX_SERIALIZE_WIDE_XML +QX_BOOST_EXPORT_ARCHIVE_ALL_CPP(boost::archive::xml_wiarchive, boost::archive::xml_woarchive) +#endif // _QX_SERIALIZE_WIDE_XML + +#endif // _QX_USE_EXPORT_DLL_BOOST_SERIALIZATION_SINGLETON +#endif // _QX_ENABLE_BOOST_SERIALIZATION diff --git a/src/QxService/IxParameter.cpp b/src/QxService/IxParameter.cpp new file mode 100644 index 0000000..f66d0de --- /dev/null +++ b/src/QxService/IxParameter.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +QX_REGISTER_INTERNAL_HELPER_START_FILE_CPP(qx::service::IxParameter) + +namespace qx +{ + namespace service + { + + IxParameter::IxParameter() { ; } + + IxParameter::~IxParameter() { ; } + + void IxParameter::registerClass() const { qAssertMsg(false, "[QxOrm] qx::service::IxParameter::registerClass()", "need to override this method with 'qx::service::QxConnect::serialization_qt' or 'qx::service::QxConnect::serialization_json' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); } + + QString IxParameter::getClassName() const + { + qAssertMsg(false, "[QxOrm] qx::service::IxParameter::getClassName()", "need to override this method with 'qx::service::QxConnect::serialization_qt' or 'qx::service::QxConnect::serialization_json' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); + return ""; + } + + void IxParameter::save(QDataStream &stream) const + { + qAssertMsg(false, "[QxOrm] qx::service::IxParameter::save()", "need to override this method with 'qx::service::QxConnect::serialization_qt' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); + Q_UNUSED(stream); + } + + void IxParameter::load(QDataStream &stream) + { + qAssertMsg(false, "[QxOrm] qx::service::IxParameter::load()", "need to override this method with 'qx::service::QxConnect::serialization_qt' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); + Q_UNUSED(stream); + } + +#ifndef _QX_NO_JSON + + QJsonValue IxParameter::saveToJson() const + { + qAssertMsg(false, "[QxOrm] qx::service::IxParameter::saveToJson()", "need to override this method with 'qx::service::QxConnect::serialization_json' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); + return QJsonValue(); + } + + qx_bool IxParameter::loadFromJson(const QJsonValue &val) + { + qAssertMsg(false, "[QxOrm] qx::service::IxParameter::loadFromJson()", "need to override this method with 'qx::service::QxConnect::serialization_json' (use QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP and QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP macro to override)"); + Q_UNUSED(val); + return qx_bool(); + } + +#endif // _QX_NO_JSON + + } // namespace service +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const qx::service::IxParameter &t, const unsigned int file_version) + { + Q_UNUSED(ar); + Q_UNUSED(t); + Q_UNUSED(file_version); + } + + template + inline void qx_load(Archive &ar, qx::service::IxParameter &t, const unsigned int file_version) + { + Q_UNUSED(ar); + Q_UNUSED(t); + Q_UNUSED(file_version); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +QX_REGISTER_INTERNAL_HELPER_END_FILE_CPP(qx::service::IxParameter) + +QDataStream &operator<<(QDataStream &stream, const qx::service::IxParameter &t) +{ + Q_UNUSED(t); + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::service::IxParameter &t) +{ + Q_UNUSED(t); + return stream; +} + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/IxService.cpp b/src/QxService/IxService.cpp new file mode 100644 index 0000000..fd82b5b --- /dev/null +++ b/src/QxService/IxService.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include + +#include + +#include + +QX_REGISTER_INTERNAL_HELPER_START_FILE_CPP(qx::service::IxService) + +namespace qx +{ + namespace service + { + + IxService::IxService() { ; } + IxService::IxService(const QString &sServiceName) : m_sServiceName(sServiceName) { qAssert(!m_sServiceName.isEmpty()); } + IxService::~IxService() { ; } + + std::shared_ptr IxService::getTransaction() const { return m_pTransaction; } + void IxService::setTransaction(const std::shared_ptr &p) { m_pTransaction = p; } + + } // namespace service +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const qx::service::IxService &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + + QString sServiceName = t.getServiceName(); + qx::service::IxParameter_ptr pInputParam = t.getInputParameter_BaseClass(); + qx::service::IxParameter_ptr pOutputParam = t.getOutputParameter_BaseClass(); + qx_bool bMsgReturn = t.getMessageReturn(); + + ar << boost::serialization::make_nvp("service_name", sServiceName); + ar << boost::serialization::make_nvp("input_param", pInputParam); + ar << boost::serialization::make_nvp("output_param", pOutputParam); + ar << boost::serialization::make_nvp("msg_return", bMsgReturn); + } + + template + inline void qx_load(Archive &ar, qx::service::IxService &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sServiceName; + qx::service::IxParameter_ptr pInputParam; + qx::service::IxParameter_ptr pOutputParam; + qx_bool bMsgReturn; + + ar >> boost::serialization::make_nvp("service_name", sServiceName); + ar >> boost::serialization::make_nvp("input_param", pInputParam); + ar >> boost::serialization::make_nvp("output_param", pOutputParam); + ar >> boost::serialization::make_nvp("msg_return", bMsgReturn); + + t.setServiceName(sServiceName); + t.setInputParameter(pInputParam); + t.setOutputParameter(pOutputParam); + t.setMessageReturn(bMsgReturn); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +QX_REGISTER_INTERNAL_HELPER_END_FILE_CPP(qx::service::IxService) + +QDataStream &operator<<(QDataStream &stream, const qx::service::IxService &t) +{ + stream << t.m_sServiceName; + stream << t.m_sServiceMethodName; + stream << t.m_bMessageReturn; + + qint16 iIsNull = (t.m_pInputParameter ? 0 : 1); + stream << iIsNull; + if (t.m_pInputParameter) + { + t.m_pInputParameter->registerClass(); + QString sClassName = t.m_pInputParameter->getClassName(); + stream << sClassName; + t.m_pInputParameter->save(stream); + } + + iIsNull = (t.m_pOutputParameter ? 0 : 1); + stream << iIsNull; + if (t.m_pOutputParameter) + { + t.m_pOutputParameter->registerClass(); + QString sClassName = t.m_pOutputParameter->getClassName(); + stream << sClassName; + t.m_pOutputParameter->save(stream); + } + + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::service::IxService &t) +{ + stream >> t.m_sServiceName; + stream >> t.m_sServiceMethodName; + stream >> t.m_bMessageReturn; + + qint16 iIsNull = 0; + stream >> iIsNull; + if (iIsNull) + { + t.m_pInputParameter.reset(); + } + else + { + QString sClassName; + stream >> sClassName; + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::service::IxService, loading QDataStream", "unable to create nude pointer for input parameter"); + } + else + { + ptr->registerClass(); + ptr->load(stream); + } + t.m_pInputParameter.reset(ptr); + } + + iIsNull = 0; + stream >> iIsNull; + if (iIsNull) + { + t.m_pOutputParameter.reset(); + } + else + { + QString sClassName; + stream >> sClassName; + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::service::IxService, loading QDataStream", "unable to create nude pointer for output parameter"); + } + else + { + ptr->registerClass(); + ptr->load(stream); + } + t.m_pOutputParameter.reset(ptr); + } + + return stream; +} + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxConnect.cpp b/src/QxService/QxConnect.cpp new file mode 100644 index 0000000..34daa20 --- /dev/null +++ b/src/QxService/QxConnect.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +#if _QX_SERIALIZE_BINARY +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_binary +#elif _QX_SERIALIZE_WIDE_BINARY +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_wide_binary +#elif _QX_SERIALIZE_PORTABLE_BINARY +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_portable_binary +#elif _QX_SERIALIZE_POLYMORPHIC +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_polymorphic_binary +#elif _QX_SERIALIZE_TEXT +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_text +#elif _QX_SERIALIZE_XML +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_xml +#elif _QX_SERIALIZE_WIDE_TEXT +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_wide_text +#elif _QX_SERIALIZE_WIDE_XML +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_wide_xml +#endif // _QX_SERIALIZE_BINARY + +#ifndef QX_SERVICE_DEFAULT_SERIALIZATION_TYPE +#define QX_SERVICE_DEFAULT_SERIALIZATION_TYPE QxConnect::serialization_qt +#endif // QX_SERVICE_DEFAULT_SERIALIZATION_TYPE + +#define QX_SERVICE_DEFAULT_ENCRYPT_KEY Q_UINT64_C(0x0f2aac3b24358a1a) + +#ifndef QT_NO_SSL +#define QX_CONSTRUCT_QX_SERVICE_CONNECT_SSL() \ + , m_sslEnabled(false), m_sslProtocol(QSsl::SecureProtocols), m_sslPeerVerifyMode(QSslSocket::VerifyNone), m_sslPeerVerifyDepth(0) +#else // QT_NO_SSL +#define QX_CONSTRUCT_QX_SERVICE_CONNECT_SSL() /* Nothing */ +#endif // QT_NO_SSL + +#define QX_CONSTRUCT_QX_SERVICE_CONNECT() \ + m_lPort(7832), m_eSerializationType(QX_SERVICE_DEFAULT_SERIALIZATION_TYPE), m_lThreadCount(30), \ + m_iMaxWait(30000), m_bCompressData(false), m_bEncryptData(false), m_lKeepAlive(0), m_bModeHTTP(false), m_lSessionTimeOut(86400000) QX_CONSTRUCT_QX_SERVICE_CONNECT_SSL() + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::service::QxConnect) + +namespace qx +{ + namespace service + { + + struct Q_DECL_HIDDEN QxConnect::QxConnectImpl + { + + QMutex m_mutex; //!< Mutex => 'QxConnect' is thread-safe + QString m_sIp; //!< Ip address + long m_lPort; //!< Port number + QxConnect::serialization_type m_eSerializationType; //!< Serialization type to send data over network + long m_lThreadCount; //!< Thread count to execute all transactions (cf. 'QxThreadPool') + int m_iMaxWait; //!< Max wait in milliseconds for network processes + bool m_bCompressData; //!< Compress data over network + bool m_bEncryptData; //!< Encrypt data before transfering it over network + quint64 m_uiEncryptKey; //!< 64 bit key to encrypt/decrypt data + long m_lKeepAlive; //!< Keep socket opened during X milliseconds (-1 means never disconnect) + bool m_bModeHTTP; //!< Put QxService module in mode HTTP (see QxHttpServer module) + qlonglong m_lSessionTimeOut; //!< HTTP session time-out (expiration) in milliseconds + +#ifndef QT_NO_SSL + bool m_sslEnabled; //!< Is secure connection enabled + QSslConfiguration m_sslConfig; //!< Global SSL configuration + QList m_sslCACertificates; //!< CA certificates + QSslCertificate m_sslLocalCertificate; //!< Server certificate (public part) + QSslKey m_sslPrivateKey; //!< Server certificate private key + QList m_sslIgnoreErrors; //!< List of SSL errors to ignore + QSsl::SslProtocol m_sslProtocol; //!< List of supported protocols (SSL, TLS) + QString m_sslPeerVerifyName; //!< Peer name for certificate validation + QSslSocket::PeerVerifyMode m_sslPeerVerifyMode; //!< Peer mode for certificate validation + int m_sslPeerVerifyDepth; //!< Peer depth level for certificate validation +#endif // QT_NO_SSL + + QxConnectImpl() : QX_CONSTRUCT_QX_SERVICE_CONNECT() + { + m_uiEncryptKey = QX_SERVICE_DEFAULT_ENCRYPT_KEY; + ignoreAllSSLErrors(); + } + ~QxConnectImpl() { ; } + + void ignoreAllSSLErrors() + { +#ifndef QT_NO_SSL + QSslError err = QSslError(QSslError::UnableToGetIssuerCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::UnableToDecryptCertificateSignature); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::UnableToDecodeIssuerPublicKey); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateSignatureFailed); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateNotYetValid); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateExpired); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::InvalidNotBeforeField); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::InvalidNotAfterField); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::SelfSignedCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::SelfSignedCertificateInChain); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::UnableToGetLocalIssuerCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::UnableToVerifyFirstCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateRevoked); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::InvalidCaCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::PathLengthExceeded); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::InvalidPurpose); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateUntrusted); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateRejected); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::SubjectIssuerMismatch); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::AuthorityIssuerSerialNumberMismatch); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::NoPeerCertificate); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::HostNameMismatch); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::UnspecifiedError); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::NoSslSupport); + m_sslIgnoreErrors.append(err); + err = QSslError(QSslError::CertificateBlacklisted); + m_sslIgnoreErrors.append(err); +#endif // QT_NO_SSL + } + }; + + QxConnect::QxConnect() : qx::QxSingleton("qx::service::QxConnect"), m_pImpl(new QxConnectImpl()) { ; } + + QxConnect::~QxConnect() { ; } + + QString QxConnect::getIp() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sIp; + } + + long QxConnect::getPort() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_lPort; + } + + QxConnect::serialization_type QxConnect::getSerializationType() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_eSerializationType; + } + + long QxConnect::getThreadCount() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_lThreadCount; + } + + int QxConnect::getMaxWait() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_iMaxWait; + } + + bool QxConnect::getCompressData() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_bCompressData; + } + + bool QxConnect::getEncryptData() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_bEncryptData; + } + + quint64 QxConnect::getEncryptKey() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_uiEncryptKey; + } + + long QxConnect::getKeepAlive() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_lKeepAlive; + } + + bool QxConnect::getModeHTTP() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_bModeHTTP; + } + + qlonglong QxConnect::getSessionTimeOut() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_lSessionTimeOut; + } + +#ifndef QT_NO_SSL + + bool QxConnect::getSSLEnabled() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslEnabled; + } + + QSslConfiguration QxConnect::getSSLConfiguration() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslConfig; + } + + QList QxConnect::getSSLCACertificates() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslCACertificates; + } + + QSslCertificate QxConnect::getSSLLocalCertificate() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslLocalCertificate; + } + + QSslKey QxConnect::getSSLPrivateKey() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslPrivateKey; + } + + QList QxConnect::getSSLIgnoreErrors() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslIgnoreErrors; + } + + QSsl::SslProtocol QxConnect::getSSLProtocol() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslProtocol; + } + + QString QxConnect::getSSLPeerVerifyName() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslPeerVerifyName; + } + + QSslSocket::PeerVerifyMode QxConnect::getSSLPeerVerifyMode() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslPeerVerifyMode; + } + + int QxConnect::getSSLPeerVerifyDepth() + { + QMutexLocker locker(&m_pImpl->m_mutex); + return m_pImpl->m_sslPeerVerifyDepth; + } + +#endif // QT_NO_SSL + + void QxConnect::setIp(const QString &s) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sIp = s; + } + + void QxConnect::setPort(long l) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_lPort = l; + } + + void QxConnect::setSerializationType(QxConnect::serialization_type e) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_eSerializationType = e; + } + + void QxConnect::setThreadCount(long l) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_lThreadCount = l; + qAssert(l > 0); + } + + void QxConnect::setMaxWait(int i) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_iMaxWait = i; + qAssert(i > 0); + } + + void QxConnect::setCompressData(bool b) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_bCompressData = b; + } + + void QxConnect::setEncryptData(bool b, quint64 key /* = 0 */) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_bEncryptData = b; + if (key != 0) + { + m_pImpl->m_uiEncryptKey = key; + } + } + + void QxConnect::setKeepAlive(long l) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_lKeepAlive = l; + } + + void QxConnect::setModeHTTP(bool b) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_bModeHTTP = b; + } + + void QxConnect::setSessionTimeOut(qlonglong l) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_lSessionTimeOut = l; + } + +#ifndef QT_NO_SSL + + void QxConnect::setSSLEnabled(bool b) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslEnabled = b; + } + + void QxConnect::setSSLConfiguration(QSslConfiguration cfg) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslConfig = cfg; + } + + void QxConnect::setSSLCACertificates(QList lst) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslCACertificates = lst; + } + + void QxConnect::setSSLLocalCertificate(QSslCertificate cert) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslLocalCertificate = cert; + } + + void QxConnect::setSSLPrivateKey(QSslKey key) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslPrivateKey = key; + } + + void QxConnect::setSSLIgnoreErrors(QList lst) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslIgnoreErrors = lst; + } + + void QxConnect::setSSLProtocol(QSsl::SslProtocol e) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslProtocol = e; + } + + void QxConnect::setSSLPeerVerifyName(const QString &s) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslPeerVerifyName = s; + } + + void QxConnect::setSSLPeerVerifyMode(QSslSocket::PeerVerifyMode e) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslPeerVerifyMode = e; + } + + void QxConnect::setSSLPeerVerifyDepth(int i) + { + QMutexLocker locker(&m_pImpl->m_mutex); + m_pImpl->m_sslPeerVerifyDepth = i; + } + +#endif // QT_NO_SSL + + } // namespace service +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxServer.cpp b/src/QxService/QxServer.cpp new file mode 100644 index 0000000..716de01 --- /dev/null +++ b/src/QxService/QxServer.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include +#include +#include +#include + +#include + +namespace qx +{ + namespace service + { + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void QxServer::incomingConnection(qintptr socketDescriptor) +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + void QxServer::incomingConnection(int socketDescriptor) +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + { + QMutexLocker locker(&m_mutex); + QxThread *pThread = getAvailable(); + if (m_pThreadPool && m_pThreadPool->isStopped()) + { + return; + } + if (!pThread) + { + if (m_pThreadPool) + { + m_pThreadPool->raiseError("[QxOrm] no service available : cannot accept incoming connection (increase thread count value)", QxTransaction_ptr()); + } + return; + } + pThread->execute(socketDescriptor); + } + + QxThread *QxServer::getAvailable() const + { + if (!m_pThreadPool) + { + qAssert(false); + return NULL; + } + if (m_pThreadPool->isStopped()) + { + return NULL; + } + QxThread *pThread = m_pThreadPool->getAvailable(); + if (pThread) + { + return pThread; + } + qDebug("[QxOrm] qx::service::QxServer no service available : %s", "need to wait (try to increase thread count value)"); + + int iCurrRetryCount = 0; + int iMaxRetryCount = QxConnect::getSingleton()->getMaxWait(); + while ((!pThread) && (iCurrRetryCount < iMaxRetryCount)) + { + if (m_pThreadPool->isStopped()) + { + return NULL; + } + qx::service::QxThreadPool::sleepThread(1); + pThread = m_pThreadPool->getAvailable(); + iCurrRetryCount++; + } + + return pThread; + } + + } // namespace service +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxThread.cpp b/src/QxService/QxThread.cpp new file mode 100644 index 0000000..2cc7f66 --- /dev/null +++ b/src/QxService/QxThread.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#ifndef QT_NO_SSL +#ifndef QT_NO_OPENSSL +#define QX_THREAD_SSL +#endif // QT_NO_OPENSSL +#endif // QT_NO_SSL +#ifndef QX_THREAD_SSL +#define QX_THREAD_NO_SSL +#endif // QX_THREAD_SSL + +namespace qx +{ + namespace service + { + + void QxThread::init() + { + QObject::connect(this, SIGNAL(incomingConnection()), this, SLOT(onIncomingConnection())); + } + + bool QxThread::isAvailable() + { + QMutexLocker locker(&m_mutex); + return ((m_pTransaction.get() == NULL) && (m_iSocketDescriptor == 0)); + } + + void QxThread::stop() + { + QMutexLocker locker(&m_mutex); + m_bIsStopped = true; + if (m_iSocketDescriptor == 0) + { + quit(); + } + } + + void QxThread::wait() + { + if (m_pThread) + { + m_pThread->wait(); + } + } + + void QxThread::quit() + { + Q_EMIT finished(); + if (m_pThread) + { + m_pThread->quit(); + } + } + + bool QxThread::hasBeenStopped() + { + QMutexLocker locker(&m_mutex); + return m_bIsStopped; + } + + void QxThread::execute(QX_TYPE_SOCKET_DESC socketDescriptor) + { + QMutexLocker locker(&m_mutex); + if (m_bIsStopped) + { + return; + } + if (m_iSocketDescriptor != 0) + { + qAssert(false); + return; + } + m_iSocketDescriptor = socketDescriptor; + if (m_iSocketDescriptor != 0) + { + Q_EMIT incomingConnection(); + } + } + + QX_TYPE_SOCKET_DESC QxThread::getSocketDescriptor() + { + QMutexLocker locker(&m_mutex); + return m_iSocketDescriptor; + } + + void QxThread::onIncomingConnection() + { + if (getSocketDescriptor() == 0) + { + qAssert(false); + return; + } + if (hasBeenStopped()) + { + quit(); + return; + } + std::unique_ptr socket; + m_bIsDisconnected = false; + +#ifndef QX_THREAD_NO_SSL + bool bSSLEnabled = QxConnect::getSingleton()->getSSLEnabled(); + if (bSSLEnabled) + { + socket.reset(initSocketSSL()); + } + else + { + socket.reset(new QTcpSocket()); + } +#else // QX_THREAD_NO_SSL + socket.reset(new QTcpSocket()); +#endif // QX_THREAD_NO_SSL + + QObject::connect(socket.get(), SIGNAL(disconnected()), this, SLOT(onSocketDisconnected())); + QObject::connect(socket.get(), SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); + + if (socket->setSocketDescriptor(getSocketDescriptor())) + { +#ifndef QX_THREAD_NO_SSL + if ((!bSSLEnabled) || (checkSocketSSLEncrypted(socket.get()))) + { +#endif // QX_THREAD_NO_SSL + do + { + doProcess(*socket); + } while (checkKeepAlive(*socket) && (!hasBeenStopped()) && (!m_bIsDisconnected)); + socket->disconnectFromHost(); + if ((!m_bIsDisconnected) && (socket->state() != QAbstractSocket::UnconnectedState)) + { + socket->waitForDisconnected(QxConnect::getSingleton()->getMaxWait()); + } +#ifndef QX_THREAD_NO_SSL + } + else + { + Q_EMIT error("[QxOrm] SSL socket encrypted error : " + socket->errorString(), QxTransaction_ptr()); + } +#endif // QX_THREAD_NO_SSL + } + else + { + Q_EMIT error("[QxOrm] invalid socket descriptor : cannot start transaction (" + socket->errorString() + ")", QxTransaction_ptr()); + } + + clearData(); + if (m_pThreadPool) + { + m_pThreadPool->setAvailable(this); + } + if (hasBeenStopped()) + { + quit(); + } + } + + bool QxThread::checkKeepAlive(QTcpSocket &socket) + { + if (m_pTransaction && (m_pTransaction->getForceConnectionStatus() == qx::service::QxTransaction::conn_close)) + { + return false; + } + long lKeepAlive = QxConnect::getSingleton()->getKeepAlive(); + if (lKeepAlive == 0) + { + return false; + } + + long lCurrRetry = 0; + long lMaxRetry = lKeepAlive; + do + { + if (socket.waitForReadyRead(1)) + { + return true; + } + if (socket.bytesAvailable() > 0) + { + return true; + } + if (hasBeenStopped() || m_bIsDisconnected) + { + return false; + } + QCoreApplication::processEvents(); + lCurrRetry++; + } while ((lMaxRetry == -1) || (lCurrRetry < lMaxRetry)); + return false; + } + +#ifndef QX_THREAD_NO_SSL + + bool QxThread::checkSocketSSLEncrypted(QTcpSocket *socket) + { + if (!QxConnect::getSingleton()->getSSLEnabled()) + { + qAssert(false); + return false; + } + QSslSocket *ssl = static_cast(socket); + ssl->startServerEncryption(); + return ssl->waitForEncrypted(QxConnect::getSingleton()->getMaxWait()); + } + + QSslSocket *QxThread::initSocketSSL() + { + QSslSocket *socket = new QSslSocket(); + QxConnect *settings = QxConnect::getSingleton(); + QSslConfiguration config = settings->getSSLConfiguration(); + if (config.isNull()) + { + config = QSslConfiguration::defaultConfiguration(); + } + QList allCACertificates = settings->getSSLCACertificates(); + config.setCaCertificates(allCACertificates); // because QSslSocket::setCaCertificates() is obsolete + + QObject::connect(socket, SIGNAL(encrypted()), this, SLOT(onSocketSSLEncrypted())); + QObject::connect(socket, SIGNAL(sslErrors(const QList &)), this, SLOT(onSocketSSLErrors(const QList &))); + QObject::connect(socket, SIGNAL(peerVerifyError(const QSslError &)), this, SLOT(onSocketSSLPeerVerifyError(const QSslError &))); + + socket->setSslConfiguration(config); + socket->ignoreSslErrors(settings->getSSLIgnoreErrors()); + socket->setProtocol(settings->getSSLProtocol()); + socket->setPeerVerifyName(settings->getSSLPeerVerifyName()); + socket->setPeerVerifyMode(settings->getSSLPeerVerifyMode()); + socket->setPeerVerifyDepth(settings->getSSLPeerVerifyDepth()); + socket->setPrivateKey(settings->getSSLPrivateKey()); + socket->setLocalCertificate(settings->getSSLLocalCertificate()); + + return socket; + } + +#endif // QX_THREAD_NO_SSL + + void QxThread::clearData() + { + QMutexLocker locker(&m_mutex); + m_pTransaction.reset(); + m_iSocketDescriptor = 0; + m_bIsDisconnected = false; + } + + void QxThread::doProcess(QTcpSocket &socket) + { + long lMaxWait = QxConnect::getSingleton()->getMaxWait(); + bool bModeHTTP = QxConnect::getSingleton()->getModeHTTP(); + if (bModeHTTP) + { + m_pTransaction = std::make_shared(); + } + else + { + m_pTransaction = std::make_shared(); + } + QObject::connect(m_pTransaction.get(), SIGNAL(onCustomRequestHandler()), this, SLOT(onCustomRequestHandler()), Qt::DirectConnection); + + qx_bool bReadOk = m_pTransaction->readSocketServer(socket); + if (!bReadOk) + { + Q_EMIT error(QString("[QxOrm] unable to read request from socket : '") + bReadOk.getDesc() + QString("'"), QxTransaction_ptr()); + return; + } + if (hasBeenStopped() || m_bIsDisconnected) + { + return; + } + socket.readAll(); + + Q_EMIT transactionStarted(m_pTransaction); + try + { + m_pTransaction->executeServer(); + } + catch (const qx::exception &x) + { + qx_bool xb = x.toQxBool(); + m_pTransaction->setMessageReturn(xb); + } + catch (const std::exception &e) + { + m_pTransaction->setMessageReturn(qx_bool(QX_ERROR_UNKNOWN, e.what())); + } + catch (...) + { + m_pTransaction->setMessageReturn(qx_bool(QX_ERROR_UNKNOWN, "unknown error")); + } + if (hasBeenStopped() || m_bIsDisconnected) + { + return; + } + + qx_bool bWriteOk = m_pTransaction->writeSocketServer(socket); + if (!bWriteOk) + { + Q_EMIT error(QString("[QxOrm] unable to write reply to socket : '") + bWriteOk.getDesc() + QString("'"), m_pTransaction); + } + + long lCurrRetry = 0; + while ((socket.bytesToWrite() > 0) && ((lMaxWait == -1) || (lCurrRetry < lMaxWait)) && (!hasBeenStopped()) && (!m_bIsDisconnected)) + { + socket.waitForBytesWritten(1); + QCoreApplication::processEvents(); + lCurrRetry++; + } + Q_EMIT transactionFinished(m_pTransaction); + } + + void QxThread::onCustomRequestHandler() + { + if (m_pTransaction) + { + Q_EMIT customRequestHandler(m_pTransaction); + } + else + { + qAssert(false); + } + } + + void QxThread::onSocketDisconnected() + { + m_bIsDisconnected = true; + } + + void QxThread::onSocketReadyRead() + { + /* Nothing here */ + } + +#ifndef QX_THREAD_NO_SSL + + void QxThread::onSocketSSLEncrypted() + { + /* Nothing here */ + } + + void QxThread::onSocketSSLErrors(const QList &errors) + { + for (int i = 0; i < errors.count(); i++) + { + QSslError err = errors.at(i); + QString msg = err.errorString(); + qDebug("[QxOrm] qx::service::QxThread::onSocketSSLErrors() : %s", qPrintable(msg)); + } + } + + void QxThread::onSocketSSLPeerVerifyError(const QSslError &error) + { + QString msg = error.errorString(); + qDebug("[QxOrm] qx::service::QxThread::onSocketSSLPeerVerifyError() : %s", qPrintable(msg)); + } + +#endif // QX_THREAD_NO_SSL + + } // namespace service +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxThreadPool.cpp b/src/QxService/QxThreadPool.cpp new file mode 100644 index 0000000..ba38d54 --- /dev/null +++ b/src/QxService/QxThreadPool.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include +#include +#include + +#include + +#include + +namespace qx +{ + namespace service + { + + bool QxThreadPool::isStopped() const { return m_bIsStopped; } + + QxThread *QxThreadPool::getAvailable() + { + if (m_bIsStopped) + { + return NULL; + } + QMutexLocker locker(&m_mutex); + QxThread *p = (m_lstAvailable.isEmpty() ? NULL : m_lstAvailable.dequeue()); + if (p) + { + qAssert(p->isAvailable()); + } + return ((p && p->isAvailable()) ? p : NULL); + } + + void QxThreadPool::setAvailable(QxThread *p) + { + if (m_bIsStopped) + { + return; + } + QMutexLocker locker(&m_mutex); + if ((p == NULL) || (!p->isAvailable())) + { + qAssert(false); + return; + } + for (long l = 0; l < m_lstAvailable.count(); l++) + { + if (m_lstAvailable.at(l) == p) + { + qAssert(false); + return; + } + } + m_lstAvailable.enqueue(p); + } + + void QxThreadPool::raiseError(const QString &err, QxTransaction_ptr transaction) + { + qAssert(!err.isEmpty()); + if (!err.isEmpty()) + { + Q_EMIT error(err, transaction); + } + } + + void QxThreadPool::run() + { + // To be sure that HTTP session manager event loop is running on this thread + qx::QxHttpSessionManager::deleteSingleton(); + qx::QxHttpSessionManager::getSingleton(); + + initServices(); + runServer(); + m_bIsStopped = true; + clearServices(); + qx::QxHttpSessionManager::deleteSingleton(); + } + + void QxThreadPool::runServer() + { + QxServer server(this); + server.setMaxPendingConnections(QxConnect::getSingleton()->getThreadCount()); + quint16 serverPort = (quint16)(QxConnect::getSingleton()->getPort()); + if (!server.listen(QHostAddress::Any, serverPort)) + { + raiseError(QString("[QxOrm] cannot run server : '") + server.errorString() + QString("'"), QxTransaction_ptr()); + return; + } + Q_EMIT serverIsRunning(true, (&server)); + exec(); + Q_EMIT serverIsRunning(false, NULL); + } + + void QxThreadPool::initServices() + { + QMutexLocker locker(&m_mutex); + qRegisterMetaType("qx::service::QxTransaction_ptr"); + qRegisterMetaType("QxTransaction_ptr"); + for (long l = 0; l < QxConnect::getSingleton()->getThreadCount(); l++) + { + QThread *pThread = new QThread(); + QxThread *pWorker = new QxThread(this, pThread); + pWorker->moveToThread(pThread); + QObject::connect(pWorker, SIGNAL(error(const QString &, qx::service::QxTransaction_ptr)), this, SIGNAL(error(const QString &, qx::service::QxTransaction_ptr))); + QObject::connect(pWorker, SIGNAL(transactionStarted(qx::service::QxTransaction_ptr)), this, SIGNAL(transactionStarted(qx::service::QxTransaction_ptr))); + QObject::connect(pWorker, SIGNAL(transactionFinished(qx::service::QxTransaction_ptr)), this, SIGNAL(transactionFinished(qx::service::QxTransaction_ptr))); + QObject::connect(pWorker, SIGNAL(customRequestHandler(qx::service::QxTransaction_ptr)), this, SIGNAL(customRequestHandler(qx::service::QxTransaction_ptr)), Qt::DirectConnection); + QObject::connect(pWorker, SIGNAL(finished()), pThread, SLOT(quit())); + QObject::connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater())); + m_lstAllServices.append(pWorker); + m_lstAvailable.enqueue(pWorker); + pWorker->init(); + pThread->start(); + } + } + + void QxThreadPool::clearServices() + { + QMutexLocker locker(&m_mutex); + for (long l = 0; l < m_lstAllServices.count(); l++) + { + m_lstAllServices.at(l)->stop(); + } + for (long l = 0; l < m_lstAllServices.count(); l++) + { + m_lstAllServices.at(l)->wait(); + } + for (long l = 0; l < m_lstAllServices.count(); l++) + { + delete m_lstAllServices.at(l); + } + m_lstAllServices.clear(); + m_lstAvailable.clear(); + } + + } // namespace service +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxTools.cpp b/src/QxService/QxTools.cpp new file mode 100644 index 0000000..f1bcd10 --- /dev/null +++ b/src/QxService/QxTools.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#define QX_SERVICE_TOOLS_HEADER_SIZE (sizeof(quint32) + sizeof(quint16) + sizeof(quint16) + sizeof(quint16)) // (serialized data size) + (serialization type) + (compress data) + (encrypt data) +#define QX_SERVICE_MIN_SIZE_TO_COMPRESS_DATA 2000 + +namespace qx +{ + namespace service + { + + qx_bool QxTools::readSocket(QTcpSocket &socket, QxTransaction &transaction, quint32 &size) + { + while (socket.bytesAvailable() < (qint64)(QX_SERVICE_TOOLS_HEADER_SIZE)) + { + if (!socket.waitForReadyRead(QxConnect::getSingleton()->getMaxWait())) + { + return qx_bool(QX_ERROR_SERVICE_READ_ERROR, "invalid bytes count available to retrieve transaction header (" + socket.errorString() + ")"); + } + } + + quint32 uiSerializedSize = 0; + quint16 uiSerializationType(0), uiCompressData(0), uiEncryptData(0); + QByteArray dataHeader = socket.read((qint64)(QX_SERVICE_TOOLS_HEADER_SIZE)); + qAssert(dataHeader.size() == (int)(QX_SERVICE_TOOLS_HEADER_SIZE)); + QDataStream in(&dataHeader, QIODevice::ReadOnly); + in.setVersion(QDataStream::Qt_4_5); + in >> uiSerializedSize; + in >> uiSerializationType; + in >> uiCompressData; + in >> uiEncryptData; + + while (socket.bytesAvailable() < (qint64)(uiSerializedSize)) + { + if (!socket.waitForReadyRead(QxConnect::getSingleton()->getMaxWait())) + { + return qx_bool(QX_ERROR_SERVICE_READ_ERROR, "invalid bytes count available to retrieve transaction serialized data (" + socket.errorString() + ")"); + } + } + + QByteArray dataSerialized = socket.read((qint64)(uiSerializedSize)); + qAssert(dataSerialized.size() == (int)(uiSerializedSize)); + size = (quint32)(QX_SERVICE_TOOLS_HEADER_SIZE + uiSerializedSize); + + if (uiEncryptData != 0) + { + QxSimpleCrypt crypto(QxConnect::getSingleton()->getEncryptKey()); + QByteArray decrypted = crypto.decryptToByteArray(dataSerialized); + if ((crypto.lastError() != QxSimpleCrypt::ErrorNoError) || decrypted.isEmpty()) + { + return qx_bool(QX_ERROR_UNKNOWN, "an error occured during decryption of data"); + } + dataSerialized = decrypted; + } + + if (uiCompressData != 0) + { + QByteArray uncompressed = qUncompress(dataSerialized); + if (!uncompressed.isEmpty()) + { + dataSerialized = uncompressed; + } + } + + qx_bool bDeserializeOk; + switch (static_cast(uiSerializationType)) + { +#if _QX_SERIALIZE_BINARY + case QxConnect::serialization_binary: + bDeserializeOk = qx::serialization::binary::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_BINARY +#if _QX_SERIALIZE_XML + case QxConnect::serialization_xml: + bDeserializeOk = qx::serialization::xml::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_XML +#if _QX_SERIALIZE_TEXT + case QxConnect::serialization_text: + bDeserializeOk = qx::serialization::text::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_TEXT +#if _QX_SERIALIZE_PORTABLE_BINARY + case QxConnect::serialization_portable_binary: + bDeserializeOk = qx::serialization::portable_binary::from_byte_array(transaction, dataSerialized, 0); + break; +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#if _QX_SERIALIZE_WIDE_BINARY + case QxConnect::serialization_wide_binary: + bDeserializeOk = qx::serialization::wide::binary::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_WIDE_BINARY +#if _QX_SERIALIZE_WIDE_XML + case QxConnect::serialization_wide_xml: + bDeserializeOk = qx::serialization::wide::xml::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_WIDE_XML +#if _QX_SERIALIZE_WIDE_TEXT + case QxConnect::serialization_wide_text: + bDeserializeOk = qx::serialization::wide::text::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_WIDE_TEXT +#if _QX_SERIALIZE_POLYMORPHIC + case QxConnect::serialization_polymorphic_binary: + bDeserializeOk = qx::serialization::polymorphic_binary::from_byte_array(transaction, dataSerialized); + break; + case QxConnect::serialization_polymorphic_xml: + bDeserializeOk = qx::serialization::polymorphic_xml::from_byte_array(transaction, dataSerialized); + break; + case QxConnect::serialization_polymorphic_text: + bDeserializeOk = qx::serialization::polymorphic_text::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_SERIALIZE_POLYMORPHIC + case QxConnect::serialization_qt: + bDeserializeOk = qx::serialization::qt::from_byte_array(transaction, dataSerialized); + break; +#ifndef _QX_NO_JSON + case QxConnect::serialization_json: + bDeserializeOk = qx::serialization::json::from_byte_array(transaction, dataSerialized); + break; +#endif // _QX_NO_JSON + default: + return qx_bool(QX_ERROR_UNKNOWN, "unknown serialization type to read data from socket"); + } + + return bDeserializeOk; + } + + qx_bool QxTools::writeSocket(QTcpSocket &socket, QxTransaction &transaction, quint32 &size) + { + QByteArray dataSerialized; + std::string owner; + Q_UNUSED(owner); + std::wstring w_owner; + Q_UNUSED(w_owner); + switch (QxConnect::getSingleton()->getSerializationType()) + { +#if _QX_SERIALIZE_BINARY + case QxConnect::serialization_binary: + dataSerialized = qx::serialization::binary::to_byte_array(transaction, (&owner)); + break; +#endif // _QX_SERIALIZE_BINARY +#if _QX_SERIALIZE_XML + case QxConnect::serialization_xml: + dataSerialized = qx::serialization::xml::to_byte_array(transaction, (&owner)); + break; +#endif // _QX_SERIALIZE_XML +#if _QX_SERIALIZE_TEXT + case QxConnect::serialization_text: + dataSerialized = qx::serialization::text::to_byte_array(transaction, (&owner)); + break; +#endif // _QX_SERIALIZE_TEXT +#if _QX_SERIALIZE_PORTABLE_BINARY + case QxConnect::serialization_portable_binary: + dataSerialized = qx::serialization::portable_binary::to_byte_array(transaction, (&owner), 0); + break; +#endif // _QX_SERIALIZE_PORTABLE_BINARY +#if _QX_SERIALIZE_WIDE_BINARY + case QxConnect::serialization_wide_binary: + dataSerialized = qx::serialization::wide::binary::to_byte_array(transaction, (&w_owner)); + break; +#endif // _QX_SERIALIZE_WIDE_BINARY +#if _QX_SERIALIZE_WIDE_XML + case QxConnect::serialization_wide_xml: + dataSerialized = qx::serialization::wide::xml::to_byte_array(transaction, (&w_owner)); + break; +#endif // _QX_SERIALIZE_WIDE_XML +#if _QX_SERIALIZE_WIDE_TEXT + case QxConnect::serialization_wide_text: + dataSerialized = qx::serialization::wide::text::to_byte_array(transaction, (&w_owner)); + break; +#endif // _QX_SERIALIZE_WIDE_TEXT +#if _QX_SERIALIZE_POLYMORPHIC + case QxConnect::serialization_polymorphic_binary: + dataSerialized = qx::serialization::polymorphic_binary::to_byte_array(transaction, (&owner)); + break; + case QxConnect::serialization_polymorphic_xml: + dataSerialized = qx::serialization::polymorphic_xml::to_byte_array(transaction, (&owner)); + break; + case QxConnect::serialization_polymorphic_text: + dataSerialized = qx::serialization::polymorphic_text::to_byte_array(transaction, (&owner)); + break; +#endif // _QX_SERIALIZE_POLYMORPHIC + case QxConnect::serialization_qt: + dataSerialized = qx::serialization::qt::to_byte_array(transaction, (&owner)); + break; +#ifndef _QX_NO_JSON + case QxConnect::serialization_json: + dataSerialized = qx::serialization::json::to_byte_array(transaction, (&owner)); + break; +#endif // _QX_NO_JSON + default: + return qx_bool(QX_ERROR_UNKNOWN, "unknown serialization type to write data to socket"); + } + + if (dataSerialized.isEmpty()) + { + return qx_bool(QX_ERROR_UNKNOWN, "an error occured during serialization of data"); + } + + quint16 uiCompressData = 0; + if (QxConnect::getSingleton()->getCompressData() && (dataSerialized.size() > QX_SERVICE_MIN_SIZE_TO_COMPRESS_DATA)) + { + QByteArray compressed = qCompress(dataSerialized, -1); + if (!compressed.isEmpty()) + { + dataSerialized = compressed; + uiCompressData = 1; + } + } + + quint16 uiEncryptData = 0; + if (QxConnect::getSingleton()->getEncryptData()) + { + QxSimpleCrypt crypto(QxConnect::getSingleton()->getEncryptKey()); + crypto.setCompressionMode(QxSimpleCrypt::CompressionNever); + crypto.setIntegrityProtectionMode(QxSimpleCrypt::ProtectionChecksum); + QByteArray encrypted = crypto.encryptToByteArray(dataSerialized); + if ((crypto.lastError() != QxSimpleCrypt::ErrorNoError) || encrypted.isEmpty()) + { + return qx_bool(QX_ERROR_UNKNOWN, "an error occured during encryption of data"); + } + dataSerialized = encrypted; + uiEncryptData = 1; + } + + QByteArray dataHeader; + QDataStream out(&dataHeader, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_5); + out << (quint32)(dataSerialized.size()); + out << (quint16)(QxConnect::getSingleton()->getSerializationType()); + out << (quint16)(uiCompressData); + out << (quint16)(uiEncryptData); + qAssert(dataHeader.size() == (int)(QX_SERVICE_TOOLS_HEADER_SIZE)); + + qint64 iTotalWritten = 0; + qint64 iTotalToWrite = (qint64)(dataHeader.size()); + const char *pDataHeader = dataHeader.constData(); + while (iTotalWritten < iTotalToWrite) + { + qint64 iWritten = socket.write((pDataHeader + iTotalWritten), (iTotalToWrite - iTotalWritten)); + if (iWritten == -1) + { + break; + } + iTotalWritten += iWritten; + } + + if (iTotalWritten != iTotalToWrite) + { + return qx_bool(QX_ERROR_SERVICE_WRITE_ERROR, "unable to write all data bytes (header) to socket (" + socket.errorString() + ")"); + } + + iTotalWritten = 0; + iTotalToWrite = (qint64)(dataSerialized.size()); + const char *pDataSerialized = dataSerialized.constData(); + while (iTotalWritten < iTotalToWrite) + { + qint64 iWritten = socket.write((pDataSerialized + iTotalWritten), (iTotalToWrite - iTotalWritten)); + if (iWritten == -1) + { + break; + } + iTotalWritten += iWritten; + } + + size = (quint32)(dataHeader.size() + dataSerialized.size()); + return ((iTotalWritten == iTotalToWrite) ? qx_bool(true) : qx_bool(QX_ERROR_SERVICE_WRITE_ERROR, "unable to write all data bytes (serialized data) to socket (" + socket.errorString() + ")")); + } + + } // namespace service +} // namespace qx + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxService/QxTransaction.cpp b/src/QxService/QxTransaction.cpp new file mode 100644 index 0000000..d0e9dc9 --- /dev/null +++ b/src/QxService/QxTransaction.cpp @@ -0,0 +1,612 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#ifdef _QX_ENABLE_QT_NETWORK + +#include + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + +QX_REGISTER_INTERNAL_HELPER_START_FILE_CPP(qx::service::QxTransaction) + +namespace qx +{ + namespace service + { + + void QxTransaction::clear() + { + m_sTransactionId = QString(); + m_uiInputTransactionSize = 0; + m_uiOutputTransactionSize = 0; + m_dtTransactionBegin = QDateTime(); + m_dtTransactionRequestSent = QDateTime(); + m_dtTransactionRequestReceived = QDateTime(); + m_dtTransactionReplySent = QDateTime(); + m_dtTransactionReplyReceived = QDateTime(); + m_dtTransactionEnd = QDateTime(); + m_sIpSource = QString(); + m_sIpTarget = QString(); + m_lPortSource = 0; + m_lPortTarget = 0; + m_sServiceName = QString(); + m_sServiceMethod = QString(); + m_bMessageReturn = qx_bool(); + m_pInputParameter.reset(); + m_pOutputParameter.reset(); + m_pServiceInstance.reset(); + } + + void QxTransaction::executeServer() + { + if (m_sServiceName.isEmpty()) + { + m_bMessageReturn = qx_bool(QX_ERROR_SERVICE_NOT_SPECIFIED, "[QxOrm] empty service name => cannot instantiate service and execute process"); + return; + } + if (m_sServiceMethod.isEmpty()) + { + m_bMessageReturn = qx_bool(QX_ERROR_SERVICE_NOT_SPECIFIED, "[QxOrm] empty service method => cannot execute process"); + return; + } + + qx::service::IxService *ptr = qx::create_nude_ptr(m_sServiceName); + if (ptr == NULL) + { + m_bMessageReturn = qx_bool(QX_ERROR_SERVICE_INVALID, "[QxOrm] invalid service name => cannot instantiate service and execute process"); + return; + } + m_pServiceInstance = IxService_ptr(ptr); + m_pServiceInstance->registerClass(); + m_pServiceInstance->setInputParameter(m_pInputParameter); + m_pServiceInstance->setServiceMethodName(m_sServiceMethod); + + try + { + m_pServiceInstance->onBeforeProcess(); + qx_bool bInvokeOk = qx::QxClassX::invoke(m_sServiceName, m_sServiceMethod, (*m_pServiceInstance)); + if (!bInvokeOk) + { + m_bMessageReturn = qx_bool(QX_ERROR_SERVICE_INVALID, "[QxOrm] invalid service method => cannot execute process"); + return; + } + m_pOutputParameter = m_pServiceInstance->getOutputParameter_BaseClass(); + m_bMessageReturn = m_pServiceInstance->getMessageReturn(); + m_pServiceInstance->onAfterProcess(); + } + catch (const qx::exception &x) + { + m_bMessageReturn = x.toQxBool(); + } + catch (const std::exception &e) + { + QString msg(e.what()); + if (msg.isEmpty()) + { + msg = "[QxOrm] unexpected error occured executing service method"; + }; + m_bMessageReturn = qx_bool(QX_ERROR_UNKNOWN, msg); + } + catch (...) + { + m_bMessageReturn = qx_bool(QX_ERROR_UNKNOWN, "[QxOrm] unknown error occured executing service method"); + } + m_pServiceInstance.reset(); + } + + qx_bool QxTransaction::writeSocketServer(QTcpSocket &socket) + { + quint32 uiTransactionSize = 0; + IxParameter_ptr pInputBackup = getInputParameter(); + setInputParameter(IxParameter_ptr()); + setTransactionReplySent(QDateTime::currentDateTime()); + qx_bool bWriteOk = QxTools::writeSocket(socket, (*this), uiTransactionSize); + setInputParameter(pInputBackup); + setOutputTransactionSize(uiTransactionSize); + return bWriteOk; + } + + qx_bool QxTransaction::readSocketServer(QTcpSocket &socket) + { + quint32 uiTransactionSize = 0; + qx_bool bReadOk = QxTools::readSocket(socket, (*this), uiTransactionSize); + if (!bReadOk) + { + return bReadOk; + } + setInputTransactionSize(uiTransactionSize); + setTransactionRequestReceived(QDateTime::currentDateTime()); + return bReadOk; + } + + void QxTransaction::executeClient(IxService *pService, const QString &sMethod) + { + if ((pService == NULL) || sMethod.isEmpty()) + { + qAssert(false); + return; + } + if (pService->getServiceName().isEmpty()) + { + pService->setMessageReturn(qx_bool(QX_ERROR_SERVICE_NOT_SPECIFIED, "[QxOrm] empty service name")); + return; + } + std::unique_ptr socket; + pService->registerClass(); + +#ifndef QT_NO_SSL + bool bSSLEnabled = QxConnect::getSingleton()->getSSLEnabled(); + if (bSSLEnabled) + { + socket.reset(initSocketSSL()); + } + else + { + socket.reset(new QTcpSocket()); + } +#else // QT_NO_SSL + socket.reset(new QTcpSocket()); +#endif // QT_NO_SSL + + QString serverName = QxConnect::getSingleton()->getIp(); + long serverPort = QxConnect::getSingleton()->getPort(); + +#ifndef QT_NO_SSL + if (bSSLEnabled) + { + static_cast(socket.get())->connectToHostEncrypted(serverName, serverPort); + } + else + { + socket->connectToHost(serverName, serverPort); + } + if (bSSLEnabled && (!checkSocketSSLEncrypted(socket.get()))) + { + pService->setMessageReturn(qx_bool(QX_ERROR_SERVICE_SSL_ENCRYPTED, "[QxOrm] SSL socket encrypted error : " + socket->errorString())); + return; + } +#else // QT_NO_SSL + socket->connectToHost(serverName, serverPort); +#endif // QT_NO_SSL + + if (!socket->waitForConnected(QxConnect::getSingleton()->getMaxWait())) + { + pService->setMessageReturn(qx_bool(QX_ERROR_SERVER_NOT_FOUND, "[QxOrm] unable to connect to server : " + socket->errorString())); + return; + } + + if (m_sTransactionId.isEmpty()) + { + setTransactionId(QUuid::createUuid().toString()); + } + + setIpSource(socket->localAddress().toString()); + setPortSource(socket->localPort()); + setIpTarget(serverName); + setPortTarget(serverPort); + setServiceName(pService->getServiceName()); + setServiceMethod(sMethod); + setTransactionBegin(QDateTime::currentDateTime()); + setInputParameter(pService->getInputParameter_BaseClass()); + + qx_bool bWriteOk = writeSocketClient(*socket); + if (!bWriteOk) + { + pService->setMessageReturn(qx_bool(QX_ERROR_SERVICE_WRITE_ERROR, QString("[QxOrm] unable to write request to socket : '") + bWriteOk.getDesc() + QString("'"))); + return; + } + qx_bool bReadOk = readSocketClient(*socket); + if (!bReadOk) + { + pService->setMessageReturn(qx_bool(QX_ERROR_SERVICE_READ_ERROR, QString("[QxOrm] unable to read reply from socket : '") + bReadOk.getDesc() + QString("'"))); + return; + } + + pService->setOutputParameter(getOutputParameter()); + pService->setMessageReturn(getMessageReturn()); + setTransactionEnd(QDateTime::currentDateTime()); + socket->disconnectFromHost(); + if (socket->state() != QAbstractSocket::UnconnectedState) + { + socket->waitForDisconnected(QxConnect::getSingleton()->getMaxWait()); + } + } + + qx_bool QxTransaction::writeSocketClient(QTcpSocket &socket) + { + quint32 uiTransactionSize = 0; + qx_bool bWriteOk = QxTools::writeSocket(socket, (*this), uiTransactionSize); + if (!bWriteOk) + { + return bWriteOk; + } + setTransactionRequestSent(QDateTime::currentDateTime()); + setInputTransactionSize(uiTransactionSize); + return bWriteOk; + } + + qx_bool QxTransaction::readSocketClient(QTcpSocket &socket) + { + QxTransaction tmp; + quint32 uiTransactionSize = 0; + qx_bool bReadOk = QxTools::readSocket(socket, tmp, uiTransactionSize); + if (!bReadOk) + { + return bReadOk; + } + setTransactionReplyReceived(QDateTime::currentDateTime()); + setTransactionRequestReceived(tmp.getTransactionRequestReceived()); + setTransactionReplySent(tmp.getTransactionReplySent()); + setOutputParameter(tmp.getOutputParameter()); + setMessageReturn(tmp.getMessageReturn()); + setOutputTransactionSize(uiTransactionSize); + return bReadOk; + } + + QString QxTransaction::getInfos() const + { + QString infos; +#ifndef _QX_NO_JSON + infos += "transaction_content (JSON format) :\n" + qx::serialization::json::to_string(*this) + "\n"; +#else // _QX_NO_JSON + infos += "transaction_id :\t\t" + m_sTransactionId + "\n"; + infos += "input_transaction_size :\t\t" + QString::number(m_uiInputTransactionSize) + "\n"; + infos += "output_transaction_size :\t\t" + QString::number(m_uiOutputTransactionSize) + "\n"; + infos += "dt_transaction_begin :\t\t" + m_dtTransactionBegin.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "dt_transaction_request_sent :\t\t" + m_dtTransactionRequestSent.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "dt_transaction_request_received :\t\t" + m_dtTransactionRequestReceived.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "dt_transaction_reply_sent :\t\t" + m_dtTransactionReplySent.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "dt_transaction_reply_received :\t\t" + m_dtTransactionReplyReceived.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "dt_transaction_end :\t\t" + m_dtTransactionEnd.toString("yyyyMMddhhmmsszzz") + "\n"; + infos += "ip_source :\t\t" + m_sIpSource + "\n"; + infos += "ip_target :\t\t" + m_sIpTarget + "\n"; + infos += "port_source :\t\t" + QString::number(m_lPortSource) + "\n"; + infos += "port_target :\t\t" + QString::number(m_lPortTarget) + "\n"; + infos += "service_name :\t\t" + m_sServiceName + "\n"; + infos += "service_method :\t\t" + m_sServiceMethod + "\n"; + infos += "message_return :\t\t" + (m_bMessageReturn ? QString("1") : QString("0")) + (m_bMessageReturn.getDesc().isEmpty() ? QString() : (QString(", ") + m_bMessageReturn.getDesc())) + ((m_bMessageReturn.getValue() == 0) ? QString() : (QString(", value=") + QString::number(m_bMessageReturn.getValue()))) + "\n"; +#endif // _QX_NO_JSON + return infos; + } + +#ifndef QT_NO_SSL + + QSslSocket *QxTransaction::initSocketSSL() + { + QSslSocket *socket = new QSslSocket(); + QxConnect *settings = QxConnect::getSingleton(); + QSslConfiguration config = settings->getSSLConfiguration(); + if (config.isNull()) + { + config = QSslConfiguration::defaultConfiguration(); + } + QList allCACertificates = settings->getSSLCACertificates(); + config.setCaCertificates(allCACertificates); // because QSslSocket::setCaCertificates() is obsolete + + socket->setSslConfiguration(config); + socket->ignoreSslErrors(settings->getSSLIgnoreErrors()); + socket->setProtocol(settings->getSSLProtocol()); + socket->setPeerVerifyName(settings->getSSLPeerVerifyName()); + socket->setPeerVerifyMode(settings->getSSLPeerVerifyMode()); + socket->setPeerVerifyDepth(settings->getSSLPeerVerifyDepth()); + socket->setPrivateKey(settings->getSSLPrivateKey()); + socket->setLocalCertificate(settings->getSSLLocalCertificate()); + + return socket; + } + + bool QxTransaction::checkSocketSSLEncrypted(QTcpSocket *socket) + { + if (!QxConnect::getSingleton()->getSSLEnabled()) + { + qAssert(false); + return false; + } + QSslSocket *ssl = static_cast(socket); + return ssl->waitForEncrypted(QxConnect::getSingleton()->getMaxWait()); + } + +#endif // QT_NO_SSL + + void execute_client(IxService *pService, const QString &sMethod) + { + if (pService == NULL) + { + qAssert(false); + return; + } + if (sMethod.isEmpty()) + { + qAssert(false); + return; + } + QxTransaction_ptr pTransaction; + pTransaction = std::make_shared(); + pService->setTransaction(pTransaction); + pTransaction->executeClient(pService, sMethod); + pTransaction->setMessageReturn(pService->getMessageReturn()); + } + + } // namespace service +} // namespace qx + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + +namespace boost +{ + namespace serialization + { + + template + inline void qx_save(Archive &ar, const qx::service::QxTransaction &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + + QString sTransactionId = t.getTransactionId(); + quint32 uiInputTransactionSize = t.getInputTransactionSize(); + quint32 uiOutputTransactionSize = t.getOutputTransactionSize(); + QDateTime dtTransactionBegin = t.getTransactionBegin(); + QDateTime dtTransactionRequestSent = t.getTransactionRequestSent(); + QDateTime dtTransactionRequestReceived = t.getTransactionRequestReceived(); + QDateTime dtTransactionReplySent = t.getTransactionReplySent(); + QDateTime dtTransactionReplyReceived = t.getTransactionReplyReceived(); + QDateTime dtTransactionEnd = t.getTransactionEnd(); + QString sIpSource = t.getIpSource(); + QString sIpTarget = t.getIpTarget(); + long lPortSource = t.getPortSource(); + long lPortTarget = t.getPortTarget(); + QString sServiceName = t.getServiceName(); + QString sServiceMethod = t.getServiceMethod(); + qx_bool bMessageReturn = t.getMessageReturn(); + qx::service::IxParameter_ptr pInputParameter = t.getInputParameter(); + qx::service::IxParameter_ptr pOutputParameter = t.getOutputParameter(); + + ar << boost::serialization::make_nvp("transaction_id", sTransactionId); + ar << boost::serialization::make_nvp("input_transaction_size", uiInputTransactionSize); + ar << boost::serialization::make_nvp("output_transaction_size", uiOutputTransactionSize); + ar << boost::serialization::make_nvp("dt_transaction_begin", dtTransactionBegin); + ar << boost::serialization::make_nvp("dt_transaction_request_sent", dtTransactionRequestSent); + ar << boost::serialization::make_nvp("dt_transaction_request_received", dtTransactionRequestReceived); + ar << boost::serialization::make_nvp("dt_transaction_reply_sent", dtTransactionReplySent); + ar << boost::serialization::make_nvp("dt_transaction_reply_received", dtTransactionReplyReceived); + ar << boost::serialization::make_nvp("dt_transaction_end", dtTransactionEnd); + ar << boost::serialization::make_nvp("ip_source", sIpSource); + ar << boost::serialization::make_nvp("ip_target", sIpTarget); + ar << boost::serialization::make_nvp("port_source", lPortSource); + ar << boost::serialization::make_nvp("port_target", lPortTarget); + ar << boost::serialization::make_nvp("service_name", sServiceName); + ar << boost::serialization::make_nvp("service_method", sServiceMethod); + ar << boost::serialization::make_nvp("message_return", bMessageReturn); + ar << boost::serialization::make_nvp("input_parameter", pInputParameter); + ar << boost::serialization::make_nvp("output_parameter", pOutputParameter); + } + + template + inline void qx_load(Archive &ar, qx::service::QxTransaction &t, const unsigned int file_version) + { + Q_UNUSED(file_version); + QString sTransactionId; + quint32 uiInputTransactionSize(0); + quint32 uiOutputTransactionSize(0); + QDateTime dtTransactionBegin; + QDateTime dtTransactionRequestSent; + QDateTime dtTransactionRequestReceived; + QDateTime dtTransactionReplySent; + QDateTime dtTransactionReplyReceived; + QDateTime dtTransactionEnd; + QString sIpSource; + QString sIpTarget; + long lPortSource(0); + long lPortTarget(0); + QString sServiceName; + QString sServiceMethod; + qx_bool bMessageReturn; + qx::service::IxParameter_ptr pInputParameter; + qx::service::IxParameter_ptr pOutputParameter; + + ar >> boost::serialization::make_nvp("transaction_id", sTransactionId); + ar >> boost::serialization::make_nvp("input_transaction_size", uiInputTransactionSize); + ar >> boost::serialization::make_nvp("output_transaction_size", uiOutputTransactionSize); + ar >> boost::serialization::make_nvp("dt_transaction_begin", dtTransactionBegin); + ar >> boost::serialization::make_nvp("dt_transaction_request_sent", dtTransactionRequestSent); + ar >> boost::serialization::make_nvp("dt_transaction_request_received", dtTransactionRequestReceived); + ar >> boost::serialization::make_nvp("dt_transaction_reply_sent", dtTransactionReplySent); + ar >> boost::serialization::make_nvp("dt_transaction_reply_received", dtTransactionReplyReceived); + ar >> boost::serialization::make_nvp("dt_transaction_end", dtTransactionEnd); + ar >> boost::serialization::make_nvp("ip_source", sIpSource); + ar >> boost::serialization::make_nvp("ip_target", sIpTarget); + ar >> boost::serialization::make_nvp("port_source", lPortSource); + ar >> boost::serialization::make_nvp("port_target", lPortTarget); + ar >> boost::serialization::make_nvp("service_name", sServiceName); + ar >> boost::serialization::make_nvp("service_method", sServiceMethod); + ar >> boost::serialization::make_nvp("message_return", bMessageReturn); + ar >> boost::serialization::make_nvp("input_parameter", pInputParameter); + ar >> boost::serialization::make_nvp("output_parameter", pOutputParameter); + + t.setTransactionId(sTransactionId); + t.setInputTransactionSize(uiInputTransactionSize); + t.setOutputTransactionSize(uiOutputTransactionSize); + t.setTransactionBegin(dtTransactionBegin); + t.setTransactionRequestSent(dtTransactionRequestSent); + t.setTransactionRequestReceived(dtTransactionRequestReceived); + t.setTransactionReplySent(dtTransactionReplySent); + t.setTransactionReplyReceived(dtTransactionReplyReceived); + t.setTransactionEnd(dtTransactionEnd); + t.setIpSource(sIpSource); + t.setIpTarget(sIpTarget); + t.setPortSource(lPortSource); + t.setPortTarget(lPortTarget); + t.setServiceName(sServiceName); + t.setServiceMethod(sServiceMethod); + t.setMessageReturn(bMessageReturn); + t.setInputParameter(pInputParameter); + t.setOutputParameter(pOutputParameter); + } + + } // namespace serialization +} // namespace boost + +#endif // _QX_ENABLE_BOOST_SERIALIZATION + +QX_REGISTER_INTERNAL_HELPER_END_FILE_CPP(qx::service::QxTransaction) + +QDataStream &operator<<(QDataStream &stream, const qx::service::QxTransaction &t) +{ + stream << t.m_sTransactionId; + stream << t.m_uiInputTransactionSize; + stream << t.m_uiOutputTransactionSize; + stream << t.m_dtTransactionBegin; + stream << t.m_dtTransactionRequestSent; + stream << t.m_dtTransactionRequestReceived; + stream << t.m_dtTransactionReplySent; + stream << t.m_dtTransactionReplyReceived; + stream << t.m_dtTransactionEnd; + stream << t.m_sIpSource; + stream << t.m_sIpTarget; + stream << (qint64)(t.m_lPortSource); + stream << (qint64)(t.m_lPortTarget); + stream << t.m_sServiceName; + stream << t.m_sServiceMethod; + stream << t.m_bMessageReturn; + + qint16 iIsNull = (t.m_pInputParameter ? 0 : 1); + stream << iIsNull; + if (t.m_pInputParameter) + { + t.m_pInputParameter->registerClass(); + QString sClassName = t.m_pInputParameter->getClassName(); + stream << sClassName; + t.m_pInputParameter->save(stream); + } + + iIsNull = (t.m_pOutputParameter ? 0 : 1); + stream << iIsNull; + if (t.m_pOutputParameter) + { + t.m_pOutputParameter->registerClass(); + QString sClassName = t.m_pOutputParameter->getClassName(); + stream << sClassName; + t.m_pOutputParameter->save(stream); + } + + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::service::QxTransaction &t) +{ + qint64 iTemp = 0; + stream >> t.m_sTransactionId; + stream >> t.m_uiInputTransactionSize; + stream >> t.m_uiOutputTransactionSize; + stream >> t.m_dtTransactionBegin; + stream >> t.m_dtTransactionRequestSent; + stream >> t.m_dtTransactionRequestReceived; + stream >> t.m_dtTransactionReplySent; + stream >> t.m_dtTransactionReplyReceived; + stream >> t.m_dtTransactionEnd; + stream >> t.m_sIpSource; + stream >> t.m_sIpTarget; + stream >> iTemp; + t.m_lPortSource = static_cast(iTemp); + stream >> iTemp; + t.m_lPortTarget = static_cast(iTemp); + stream >> t.m_sServiceName; + stream >> t.m_sServiceMethod; + stream >> t.m_bMessageReturn; + + qint16 iIsNull = 0; + stream >> iIsNull; + if (iIsNull) + { + t.m_pInputParameter.reset(); + } + else + { + QString sClassName; + stream >> sClassName; + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::service::QxTransaction, loading QDataStream", "unable to create nude pointer for input parameter"); + } + else + { + ptr->registerClass(); + ptr->load(stream); + } + t.m_pInputParameter.reset(ptr); + } + + iIsNull = 0; + stream >> iIsNull; + if (iIsNull) + { + t.m_pOutputParameter.reset(); + } + else + { + QString sClassName; + stream >> sClassName; + qx::service::IxParameter *ptr = qx::create_nude_ptr(sClassName); + if (!ptr) + { + qAssertMsg(false, "[QxOrm] qx::service::QxTransaction, loading QDataStream", "unable to create nude pointer for output parameter"); + } + else + { + ptr->registerClass(); + ptr->load(stream); + } + t.m_pOutputParameter.reset(ptr); + } + + return stream; +} + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxSingleton/IxSingleton.cpp b/src/QxSingleton/IxSingleton.cpp new file mode 100644 index 0000000..67cef3b --- /dev/null +++ b/src/QxSingleton/IxSingleton.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + IxSingleton::IxSingleton(const QString &sKey) : m_sKeySingleton(sKey) + { +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::IxSingleton constructor '%s'", qPrintable(m_sKeySingleton)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + + QxSingletonX::addSingleton(m_sKeySingleton, this); + } + + IxSingleton::~IxSingleton() + { +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::IxSingleton destructor '%s'", qPrintable(m_sKeySingleton)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + + QxSingletonX::removeSingleton(m_sKeySingleton); + } + + void IxSingleton::initQxSingletonX() + { + static bool bDone = false; + if (!bDone && QCoreApplication::instance()) + { + bDone = true; + QxSingletonX::getSingleton(); + } + } + +} // namespace qx diff --git a/src/QxSingleton/QxSingletonInit.cpp b/src/QxSingleton/QxSingletonInit.cpp new file mode 100644 index 0000000..49c6860 --- /dev/null +++ b/src/QxSingleton/QxSingletonInit.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxDataMemberX) + +#ifdef _QX_ENABLE_QT_NETWORK + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxDataMemberX) + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxClass) +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxDataMemberX) + +#endif // _QX_ENABLE_QT_NETWORK diff --git a/src/QxSingleton/QxSingletonX.cpp b/src/QxSingleton/QxSingletonX.cpp new file mode 100644 index 0000000..a781fc7 --- /dev/null +++ b/src/QxSingleton/QxSingletonX.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +#include + +#include + +#ifdef _QX_STATIC_BUILD +#undef _QX_USE_QX_SINGLETON_X +#define _QX_USE_QX_SINGLETON_X 0 +#endif // _QX_STATIC_BUILD + +QX_DLL_EXPORT_QX_SINGLETON_CPP(qx::QxSingletonX) + +namespace qx +{ + + /* -- We replaced these static class members by static class methods to avoid (with some compilers) the 'static initialization order fiasco' -- + QHash QxSingletonX::m_mapSingletonX; // replaced by 'getMapSingletonX()' + QMutex QxSingletonX::m_oMutexSingletonX; // replaced by 'getMutexSingletonX()' + bool QxSingletonX::m_bOnClearSingletonX = false; // replaced by 'getOnClearSingletonX()' + */ + + QxSingletonX::QxSingletonX() : QxSingleton("qx::QxSingletonX") + { +#if _QX_USE_QX_SINGLETON_X + int iResult = std::atexit(&QxSingletonX::deleteAllSingleton); + Q_UNUSED(iResult); + QString sAssertMsg = QString("cannot register 'qx::QxSingletonX::deleteAllSingleton()' function at exit program (using 'std::atexit')"); + Q_UNUSED(sAssertMsg); + qAssertMsg((iResult == 0), "[QxOrm] qx::QxSingletonX() constructor", qPrintable(sAssertMsg)); +#endif // _QX_USE_QX_SINGLETON_X + } + + QHash &QxSingletonX::getMapSingletonX() + { + // There is a 'very small' memory leak here : this is to avoid (with some compilers) the 'static initialization order fiasco' + // More details here : https://isocpp.org/wiki/faq/ctors#static-init-order + static QHash *p = new QHash(); + return (*p); + } + + QMutex *QxSingletonX::getMutexSingletonX() + { + // There is a 'very small' memory leak here : this is to avoid (with some compilers) the 'static initialization order fiasco' + // More details here : https://isocpp.org/wiki/faq/ctors#static-init-order + static QMutex *p = new QMutex(); + return p; + } + + bool &QxSingletonX::getOnClearSingletonX() + { + // There is a 'very small' memory leak here : this is to avoid (with some compilers) the 'static initialization order fiasco' + // More details here : https://isocpp.org/wiki/faq/ctors#static-init-order + static bool *p = new bool(false); + return (*p); + } + + bool QxSingletonX::addSingleton(const QString &sKey, IxSingleton *pSingleton) + { +#if _QX_USE_QX_SINGLETON_X +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::QxSingletonX::addSingleton() : '%s'", qPrintable(sKey)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + QMutex *pMutex = (QCoreApplication::instance() ? getMutexSingletonX() : NULL); + QMutexLocker locker(pMutex); + bool bExist = getMapSingletonX().contains(sKey); + QString sAssertMsg = QString("singleton key '%1' already exists or is empty").arg(sKey); + Q_UNUSED(sAssertMsg); + qAssertMsg((!bExist && !sKey.isEmpty()), "[QxOrm] qx::QxSingletonX::addSingleton()", qPrintable(sAssertMsg)); + if (!pSingleton || bExist || sKey.isEmpty()) + { + return false; + } + getMapSingletonX().insert(sKey, pSingleton); + return true; +#else // _QX_USE_QX_SINGLETON_X + Q_UNUSED(sKey); + Q_UNUSED(pSingleton); + return false; +#endif // _QX_USE_QX_SINGLETON_X + } + + bool QxSingletonX::removeSingleton(const QString &sKey) + { +#if _QX_USE_QX_SINGLETON_X + bool &bOnClearSingletonX = getOnClearSingletonX(); + if (bOnClearSingletonX) + { + return false; + } +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::QxSingletonX::removeSingleton() : '%s'", qPrintable(sKey)); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + QMutex *pMutex = (QCoreApplication::instance() ? getMutexSingletonX() : NULL); + QMutexLocker locker(pMutex); + QString sAssertMsg = QString("singleton key '%1' doesn't exist in the singleton manager").arg(sKey); + Q_UNUSED(sAssertMsg); + qAssertMsg((getMapSingletonX().contains(sKey)), "[QxOrm] qx::QxSingletonX::removeSingleton()", qPrintable(sAssertMsg)); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool bRemoveOk = getMapSingletonX().remove(sKey); +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool bRemoveOk = (getMapSingletonX().remove(sKey) > 0); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + return bRemoveOk; +#else // _QX_USE_QX_SINGLETON_X + Q_UNUSED(sKey); + return false; +#endif // _QX_USE_QX_SINGLETON_X + } + + void QxSingletonX::deleteAllSingleton() + { +#if _QX_USE_QX_SINGLETON_X +#ifdef _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + qDebug("[QxOrm] qx::QxSingletonX : %s", "execute deleteAllSingleton() function"); +#endif // _QX_TRACE_CONSTRUCTOR_DESTRUCTOR + QMutex *pMutex = (QCoreApplication::instance() ? getMutexSingletonX() : NULL); + QMutexLocker locker(pMutex); + bool &bOnClearSingletonX = getOnClearSingletonX(); + bOnClearSingletonX = true; + + QHash &mapSingletonX = getMapSingletonX(); + QHashIterator itr(mapSingletonX); + while (itr.hasNext()) + { + itr.next(); + IxSingleton *pSingleton = itr.value(); + if (pSingleton && (pSingleton != QxSingletonX::getSingleton())) + pSingleton->deleteInstance(); + } + + QxSingletonX::deleteSingleton(); + mapSingletonX.clear(); + bOnClearSingletonX = false; +#endif // _QX_USE_QX_SINGLETON_X + } + +} // namespace qx diff --git a/src/QxTraits/unit_test_is_container.cpp b/src/QxTraits/unit_test_is_container.cpp new file mode 100644 index 0000000..4775183 --- /dev/null +++ b/src/QxTraits/unit_test_is_container.cpp @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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_MODE_RELEASE + +#include + +#include +#include +#include + +#include + +#include + +namespace qx +{ + namespace unit_test + { + + void unit_test_is_container() + { + static_assert(!qx::trait::is_container::value, "unit_test_is_container"); + static_assert(!qx::trait::is_container::value, "unit_test_is_container"); + static_assert(!qx::trait::is_container::value, "unit_test_is_container"); + static_assert(!qx::trait::is_container::value, "unit_test_is_container"); + + typedef qx::QxCollection qx_coll_string_to_double; + typedef std::vector std_vector_object; + typedef QHash qt_hash_double_to_string; + typedef std::set std_set_int; + + static_assert(qx::trait::is_container::value, "unit_test_is_container"); + static_assert(qx::trait::is_container::value, "unit_test_is_container"); + static_assert(qx::trait::is_container::value, "unit_test_is_container"); + static_assert(qx::trait::is_container::value, "unit_test_is_container"); + + static_assert(qx::trait::is_std_vector>::value, "unit_test_is_container"); + static_assert(!qx::trait::is_qt_vector>::value, "unit_test_is_container"); + + static_assert(qx::trait::is_container_to_pod::value, "unit_test_is_container"); + static_assert(qx::trait::is_container_key_value::value, "unit_test_is_container"); + +#ifdef _QX_ENABLE_BOOST + + typedef boost::unordered_map boost_unordered_map_string_to_object_ptr; + + static_assert(!qx::trait::is_boost_unordered_map>::value, "unit_test_is_container"); + static_assert(qx::trait::is_container_key_value::value, "unit_test_is_container"); + +#endif // _QX_ENABLE_BOOST + } + + } // namespace unit_test +} // namespace qx + +#endif // _QX_MODE_RELEASE diff --git a/src/QxTraits/unit_test_is_smart_ptr.cpp b/src/QxTraits/unit_test_is_smart_ptr.cpp new file mode 100644 index 0000000..2dafebb --- /dev/null +++ b/src/QxTraits/unit_test_is_smart_ptr.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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_MODE_RELEASE + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace qx +{ + namespace unit_test + { + + void unit_test_is_smart_ptr() + { +#ifdef _QX_ENABLE_BOOST + + static_assert(!qx::trait::is_boost_intrusive_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_intrusive_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_intrusive_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_boost_intrusive_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_boost_intrusive_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_boost_scoped_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_scoped_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_scoped_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_scoped_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_boost_scoped_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_boost_shared_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_boost_weak_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_qt_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_weak_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_scoped_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_intrusive_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_boost_weak_ptr>::value, "unit_test_is_smart_ptr"); + +#endif // _QX_ENABLE_BOOST + + static_assert(!qx::trait::is_qt_shared_data_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_qt_shared_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_qt_shared_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_qt_weak_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_qt_weak_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_smart_ptr::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_smart_ptr::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_smart_ptr_to_pod>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr_to_pod>::value, "unit_test_is_smart_ptr"); + + static_assert(qx::trait::is_std_shared_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_std_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + + static_assert(!qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_std_weak_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(qx::trait::is_smart_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_smart_ptr_to_pod>::value, "unit_test_is_smart_ptr"); + + static_assert(qx::trait::is_std_unique_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_data_ptr>::value, "unit_test_is_smart_ptr"); + static_assert(!qx::trait::is_qt_shared_ptr>::value, "unit_test_is_smart_ptr"); + } + + } // namespace unit_test +} // namespace qx + +#endif // _QX_MODE_RELEASE diff --git a/src/QxValidator/IxValidator.cpp b/src/QxValidator/IxValidator.cpp new file mode 100644 index 0000000..bad2814 --- /dev/null +++ b/src/QxValidator/IxValidator.cpp @@ -0,0 +1,323 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include +#include + +#include + +#include + +#include + +namespace qx +{ + + IxValidator::IxValidator(IxValidator::validator_type type) : QxPropertyBag(), m_type(type), m_pDataMember(NULL) { initDefaultMessage(); } + + IxValidator::~IxValidator() { ; } + + IxValidator::validator_type IxValidator::getType() const { return m_type; } + + QString IxValidator::getMessage() const { return m_message; } + + QString IxValidator::getGroup() const { return m_group; } + + QVariant IxValidator::getConstraint() const { return ((m_Constraints.count() > 0) ? m_Constraints.at(0) : QVariant()); } + + QVariantList IxValidator::getConstraints() const { return m_Constraints; } + + IxDataMember *IxValidator::getDataMember() const { return m_pDataMember; } + + void IxValidator::setMessage(const QString &s) { m_message = s; } + + void IxValidator::setGroup(const QString &s) { m_group = s; } + + void IxValidator::setConstraint(const QVariant &v) + { + m_Constraints.clear(); + m_Constraints.append(v); + } + + void IxValidator::setConstraints(const QVariantList &lst) { m_Constraints = lst; } + + void IxValidator::setDataMember(IxDataMember *p) { m_pDataMember = p; } + + void IxValidator::validate(void *pOwner, QxInvalidValueX &lstInvalidValues) const + { + if (!pOwner) + { + qAssert(false); + return; + } + if (!m_pDataMember) + { + return; + } + QVariant val = m_pDataMember->toVariant(pOwner); + + switch (m_type) + { + case not_null: + validateNotNull(val, lstInvalidValues); + break; + case not_empty: + validateNotEmpty(val, lstInvalidValues); + break; + case min_value: + validateMinValue(val, lstInvalidValues); + break; + case max_value: + validateMaxValue(val, lstInvalidValues); + break; + case min_length: + validateMinLength(val, lstInvalidValues); + break; + case max_length: + validateMaxLength(val, lstInvalidValues); + break; + case date_past: + validateDatePast(val, lstInvalidValues); + break; + case date_future: + validateDateFuture(val, lstInvalidValues); + break; + case min_decimal: + validateMinDecimal(val, lstInvalidValues); + break; + case max_decimal: + validateMaxDecimal(val, lstInvalidValues); + break; + case regular_expression: + validateRegularExpression(val, lstInvalidValues); + break; + case e_mail: + validateEMail(val, lstInvalidValues); + break; + default: + break; + } + } + + void IxValidator::initDefaultMessage() + { + QHash *lstMessage = QxClassX::getAllValidatorMessage(); + if (!lstMessage) + { + qAssert(false); + return; + } + + switch (m_type) + { + case not_null: + m_message = lstMessage->value("not_null"); + break; + case not_empty: + m_message = lstMessage->value("not_empty"); + break; + case min_value: + m_message = lstMessage->value("min_value"); + break; + case max_value: + m_message = lstMessage->value("max_value"); + break; + case min_length: + m_message = lstMessage->value("min_length"); + break; + case max_length: + m_message = lstMessage->value("max_length"); + break; + case date_past: + m_message = lstMessage->value("date_past"); + break; + case date_future: + m_message = lstMessage->value("date_future"); + break; + case min_decimal: + m_message = lstMessage->value("min_decimal"); + break; + case max_decimal: + m_message = lstMessage->value("max_decimal"); + break; + case regular_expression: + m_message = lstMessage->value("regular_expression"); + break; + case e_mail: + m_message = lstMessage->value("e_mail"); + break; + default: + m_message = ""; + break; + } + } + + void IxValidator::validateNotNull(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + if (v.isNull()) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateNotEmpty(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QString s = v.toString(); + if (s.size() <= 0) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMinValue(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + long d = (long)v.toLongLong(); + long constraint = (long)getConstraint().toLongLong(); + if (d < constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMaxValue(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + long d = (long)v.toLongLong(); + long constraint = (long)getConstraint().toLongLong(); + if (d > constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMinDecimal(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + double d = v.toDouble(); + double constraint = getConstraint().toDouble(); + if (d < constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMaxDecimal(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + double d = v.toDouble(); + double constraint = getConstraint().toDouble(); + if (d > constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMinLength(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QString s = v.toString(); + long constraint = (long)getConstraint().toLongLong(); + if (s.size() < constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateMaxLength(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QString s = v.toString(); + long constraint = (long)getConstraint().toLongLong(); + if (s.size() > constraint) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateDatePast(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QDateTime dt = v.toDateTime(); + if (!dt.isValid() || (dt > QDateTime::currentDateTime())) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateDateFuture(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QDateTime dt = v.toDateTime(); + if (!dt.isValid() || (dt < QDateTime::currentDateTime())) + { + lstInvalidValues.insert(this); + } + } + + void IxValidator::validateRegularExpression(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QString s = v.toString(); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegularExpression constraint(getConstraint().toString()); + if (!constraint.match(s).hasMatch()) + { + lstInvalidValues.insert(this); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegExp constraint(getConstraint().toString()); + if (!constraint.exactMatch(s)) + { + lstInvalidValues.insert(this); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + } + + void IxValidator::validateEMail(const QVariant &v, QxInvalidValueX &lstInvalidValues) const + { + QString s = v.toString(); + QString pattern = "\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b"; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegularExpression constraint(pattern, QRegularExpression::CaseInsensitiveOption); + if (!constraint.match(s).hasMatch()) + { + lstInvalidValues.insert(this); + } +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + QRegExp constraint(pattern, Qt::CaseInsensitive); + if (!constraint.exactMatch(s)) + { + lstInvalidValues.insert(this); + } +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + } + +} // namespace qx diff --git a/src/QxValidator/IxValidatorX.cpp b/src/QxValidator/IxValidatorX.cpp new file mode 100644 index 0000000..93392e4 --- /dev/null +++ b/src/QxValidator/IxValidatorX.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + IxValidatorX::IxValidatorX() : m_pClass(NULL) { ; } + + IxValidatorX::~IxValidatorX() { ; } + + void IxValidatorX::setClass(IxClass *p) { m_pClass = p; } + + IxDataMember *IxValidatorX::getDataMember(const QString &sPropertyKey) const + { + if (sPropertyKey.isEmpty() || !m_pClass) + { + return NULL; + } + IxDataMember *pDataMember = QxClassX::getDataMember(m_pClass->getKey(), sPropertyKey, true); + if (!pDataMember) + { + qDebug("[QxOrm] qx::IxValidatorX::getDataMember() : '%s'", "property key not found"); + qAssert(false); + return NULL; + } + return pDataMember; + } + + QStringList IxValidatorX::getAllGroup() const + { + QStringList lstGroup; + for (long l = 0; l < m_lstValidatorByGroup.count(); l++) + { + QString sGroup = m_lstValidatorByGroup.getKeyByIndex(l); + lstGroup.append(sGroup); + } + return lstGroup; + } + + QList IxValidatorX::getAllValidatorByGroup(const QString &group) const + { + if (!m_lstValidatorByGroup.exist(group)) + { + return QList(); + } + type_lst_validator_ptr lst = m_lstValidatorByGroup.getByKey(group); + return (*lst); + } + + QxInvalidValueX IxValidatorX::validate(void *pOwner, const QString &sGroup /* = QString() */) const + { + QxInvalidValueX invalidValues; + if (!m_pClass) + { + qAssert(false); + return invalidValues; + } + + if (m_pClass->getBaseClass()) + { + IxValidatorX *pAllValidator = m_pClass->getBaseClass()->getAllValidator(); + if (pAllValidator) + { + invalidValues.insert(pAllValidator->validate(pOwner, sGroup)); + } + } + + if (!m_lstValidatorByGroup.exist(sGroup)) + { + return invalidValues; + } + type_lst_validator_ptr lstValidator = m_lstValidatorByGroup.getByKey(sGroup); + if (!lstValidator) + { + return invalidValues; + } + + for (long l = 0; l < lstValidator->count(); l++) + { + IxValidator_ptr validator = lstValidator->at(l); + if (validator) + { + validator->validate(pOwner, invalidValues); + } + } + + return invalidValues; + } + + void IxValidatorX::insertIntoGroup(IxValidator_ptr pValidator, const QString &sGroup) + { + if (!pValidator) + { + qAssert(false); + return; + } + + if (!m_lstValidatorByGroup.exist(sGroup)) + { + type_lst_validator_ptr newLstValidator; + newLstValidator = std::make_shared(); + m_lstValidatorByGroup.insert(sGroup, newLstValidator); + } + + type_lst_validator_ptr lstValidator = m_lstValidatorByGroup.getByKey(sGroup); + lstValidator->append(pValidator); + } + + IxValidator_ptr IxValidatorX::createValidator(IxValidator::validator_type type, const QString &sPropertyKey, const QString &sMessage, const QString &sGroup) + { + IxValidator_ptr pValidator; + pValidator = std::make_shared(type); + if (!sMessage.isEmpty()) + { + pValidator->setMessage(sMessage); + } + if (!sGroup.isEmpty()) + { + pValidator->setGroup(sGroup); + } + pValidator->setDataMember(getDataMember(sPropertyKey)); + return pValidator; + } + + IxValidator *IxValidatorX::add_NotNull(const QString &sPropertyKey, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::not_null, sPropertyKey, sMessage, sGroup); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_NotEmpty(const QString &sPropertyKey, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::not_empty, sPropertyKey, sMessage, sGroup); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MinValue(const QString &sPropertyKey, long lMinValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_value, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMinValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MaxValue(const QString &sPropertyKey, long lMaxValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::max_value, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMaxValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_Range(const QString &sPropertyKey, long lMinValue, long lMaxValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_value, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMinValue); + insertIntoGroup(pValidator, sGroup); + + pValidator = createValidator(IxValidator::max_value, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMaxValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MinDecimal(const QString &sPropertyKey, double dMinValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_decimal, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint(dMinValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MaxDecimal(const QString &sPropertyKey, double dMaxValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::max_decimal, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint(dMaxValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_RangeDecimal(const QString &sPropertyKey, double dMinValue, double dMaxValue, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_decimal, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint(dMinValue); + insertIntoGroup(pValidator, sGroup); + + pValidator = createValidator(IxValidator::max_decimal, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint(dMaxValue); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MinLength(const QString &sPropertyKey, long lMinLength, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_length, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMinLength); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_MaxLength(const QString &sPropertyKey, long lMaxLength, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::max_length, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMaxLength); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_Size(const QString &sPropertyKey, long lMinLength, long lMaxLength, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::min_length, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMinLength); + insertIntoGroup(pValidator, sGroup); + + pValidator = createValidator(IxValidator::max_length, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint((qlonglong)lMaxLength); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_DatePast(const QString &sPropertyKey, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::date_past, sPropertyKey, sMessage, sGroup); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_DateFuture(const QString &sPropertyKey, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::date_future, sPropertyKey, sMessage, sGroup); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_RegExp(const QString &sPropertyKey, const QString &sPattern, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::regular_expression, sPropertyKey, sMessage, sGroup); + pValidator->setConstraint(sPattern); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + + IxValidator *IxValidatorX::add_EMail(const QString &sPropertyKey, const QString &sMessage /* = QString() */, const QString &sGroup /* = QString() */) + { + IxValidator_ptr pValidator = createValidator(IxValidator::e_mail, sPropertyKey, sMessage, sGroup); + insertIntoGroup(pValidator, sGroup); + return pValidator.get(); + } + +} // namespace qx diff --git a/src/QxValidator/QxInvalidValue.cpp b/src/QxValidator/QxInvalidValue.cpp new file mode 100644 index 0000000..366c567 --- /dev/null +++ b/src/QxValidator/QxInvalidValue.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace qx +{ + + QxInvalidValue::QxInvalidValue() : QxPropertyBag(), m_pValidator(NULL) { ; } + + QxInvalidValue::~QxInvalidValue() { ; } + + const IxValidator *QxInvalidValue::getValidator() const { return m_pValidator; } + + void QxInvalidValue::setValidator(const IxValidator *p) { m_pValidator = p; } + + QString QxInvalidValue::getFullName() const + { + QString sResult = m_sPath; + sResult += ((!m_sPath.isEmpty() && !m_sPropertyName.isEmpty()) ? QString(".") : QString("")); + sResult += m_sPropertyName; + return sResult; + } + +} // namespace qx + +QDataStream &operator<<(QDataStream &stream, const qx::QxInvalidValue &t) +{ + stream << t.m_sMessage; + stream << t.m_sPropertyName; + stream << t.m_sPath; + stream << t.m_lstPropertyBag; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxInvalidValue &t) +{ + stream >> t.m_sMessage; + stream >> t.m_sPropertyName; + stream >> t.m_sPath; + stream >> t.m_lstPropertyBag; + return stream; +} diff --git a/src/QxValidator/QxInvalidValueX.cpp b/src/QxValidator/QxInvalidValueX.cpp new file mode 100644 index 0000000..28cee5e --- /dev/null +++ b/src/QxValidator/QxInvalidValueX.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include +#include + +#include + +#include + +namespace qx +{ + + QxInvalidValueX::QxInvalidValueX() { ; } + + QxInvalidValueX::~QxInvalidValueX() { ; } + + QString QxInvalidValueX::getCurrentPath() const { return m_sCurrentPath; } + + void QxInvalidValueX::setCurrentPath(const QString &s) { m_sCurrentPath = s; } + + long QxInvalidValueX::count() const { return m_lstInvalidValues.count(); } + + void QxInvalidValueX::dump() const + { + QString s = text(); + qDebug("[QxOrm] %s", qPrintable(s)); + } + + QxInvalidValue QxInvalidValueX::at(long l) const { return (((l < 0) || (l >= m_lstInvalidValues.count())) ? QxInvalidValue() : m_lstInvalidValues.at(l)); } + + QString QxInvalidValueX::text() const + { + if (m_lstInvalidValues.count() <= 0) + { + return "There is no invalid value"; + } + QString sResult = "List of invalid values (" + QString::number(m_lstInvalidValues.count()) + ") :"; + + for (long l = 0; l < m_lstInvalidValues.count(); l++) + { + QxInvalidValue invalidValue = m_lstInvalidValues.at(l); + sResult += "\n\t- " + invalidValue.getMessage(); + sResult += " (" + invalidValue.getFullName() + ")"; + } + + return sResult; + } + + void QxInvalidValueX::insert(const IxValidator *pValidator) + { + if (!pValidator) + { + return; + } + IxDataMember *pDataMember = pValidator->getDataMember(); + QString sMessage = pValidator->getMessage(); + sMessage.replace("%NAME%", (pDataMember ? pDataMember->getName() : QString())); + sMessage.replace("%CONSTRAINT%", pValidator->getConstraint().toString()); + QVariantList lstConstraints = pValidator->getConstraints(); + for (long l = 0; l < lstConstraints.count(); l++) + { + sMessage.replace("%CONSTRAINT_" + QString::number(l) + "%", lstConstraints.at(l).toString()); + } + if (sMessage.isEmpty()) + { + qAssert(false); + return; + } + + QxInvalidValue invalidValue; + invalidValue.setValidator(pValidator); + invalidValue.setMessage(sMessage); + invalidValue.setPropertyName(pDataMember ? pDataMember->getName() : QString()); + invalidValue.setPath(m_sCurrentPath); + m_lstInvalidValues.append(invalidValue); + } + + void QxInvalidValueX::insert(const QString &sMessage) + { + if (sMessage.isEmpty()) + { + qAssert(false); + return; + } + QxInvalidValue invalidValue; + invalidValue.setMessage(sMessage); + invalidValue.setPath(m_sCurrentPath); + m_lstInvalidValues.append(invalidValue); + } + + void QxInvalidValueX::insert(const QxInvalidValue &invalidValue) + { + if (invalidValue.getMessage().isEmpty()) + { + qAssert(false); + return; + } + QxInvalidValue clone = invalidValue; + clone.setPath(m_sCurrentPath); + m_lstInvalidValues.append(clone); + } + + void QxInvalidValueX::insert(const QxInvalidValueX &other) + { + for (long l = 0; l < other.count(); l++) + { + QxInvalidValue invalidValue = other.at(l); + if (invalidValue.getMessage().isEmpty()) + { + qAssert(false); + continue; + } + QString sOtherPath = invalidValue.getPath(); + QString sCurrPath = m_sCurrentPath; + sCurrPath += ((!m_sCurrentPath.isEmpty() && !sOtherPath.isEmpty()) ? QString(".") : QString("")); + sCurrPath += sOtherPath; + invalidValue.setPath(sCurrPath); + m_lstInvalidValues.append(invalidValue); + } + } + +} // namespace qx + +QDataStream &operator<<(QDataStream &stream, const qx::QxInvalidValueX &t) +{ + stream << t.m_lstInvalidValues; + stream << t.m_sCurrentPath; + return stream; +} + +QDataStream &operator>>(QDataStream &stream, qx::QxInvalidValueX &t) +{ + stream >> t.m_lstInvalidValues; + stream >> t.m_sCurrentPath; + return stream; +} diff --git a/src/QxXml/QxXmlReader.cpp b/src/QxXml/QxXmlReader.cpp new file mode 100644 index 0000000..0e2021a --- /dev/null +++ b/src/QxXml/QxXmlReader.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + + void QxXmlReader::addBinaryData(const QxXmlReader::type_hash_bin_data &other, bool bClear) + { + if (bClear) + { + m_mapBinaryData.clear(); + } + QxXmlReader::type_hash_bin_data_itr itr(other); + + while (itr.hasNext()) + { + itr.next(); + addBinaryData(itr.key(), itr.value()); + } + } + + void QxXmlReader::addBinaryData(const QString &sKey, QxXmlReader::type_byte_arr_ptr pData) + { + if (sKey.isEmpty()) + { + return; + } + if (m_mapBinaryData.contains(sKey)) + { + qAssert(false); + return; + } + + m_mapBinaryData.insert(sKey, pData); + } + + void QxXmlReader::removeBinaryData(const QString &sKey) + { + m_mapBinaryData.remove(sKey); + } + + void QxXmlReader::removeAllBinaryData() + { + m_mapBinaryData.clear(); + } + + bool QxXmlReader::isStartBinaryData() const + { + if (!isStartElement()) + { + return false; + } + if (!attributes().hasAttribute(QX_XML_ATTRIBUTE_IS_BINARY_DATA)) + { + return false; + } + if (attributes().value(QX_XML_ATTRIBUTE_IS_BINARY_DATA) != "1") + { + return false; + } + + return true; + } + + QxXmlReader::type_byte_arr_ptr QxXmlReader::readBinaryData() + { + if (!isStartBinaryData()) + { + return QxXmlReader::type_byte_arr_ptr(); + } + + QString sKey = readElementText(); + if (sKey.isEmpty() || !m_mapBinaryData.contains(sKey)) + { + return QxXmlReader::type_byte_arr_ptr(); + } + + return m_mapBinaryData.value(sKey); + } + +} // namespace qx + +QDataStream &operator>>(QDataStream &stream, qx::QxXmlReader &xmlReader) +{ + QString sXml; + stream >> sXml; + qint32 lBinDataCount; + stream >> lBinDataCount; + + xmlReader.addData(sXml); + + for (qint32 l = 0; l < lBinDataCount; l++) + { + QString sKey; + stream >> sKey; + QByteArray pBuff; + stream >> pBuff; + + qx::QxXmlReader::type_byte_arr_ptr pBinData; + pBinData.reset(new QByteArray(pBuff)); + xmlReader.addBinaryData(sKey, pBinData); + } + + return stream; +} diff --git a/src/QxXml/QxXmlWriter.cpp b/src/QxXml/QxXmlWriter.cpp new file mode 100644 index 0000000..9f7157b --- /dev/null +++ b/src/QxXml/QxXmlWriter.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#include + +#include + +namespace qx +{ + + QString QxXmlWriter::writeBinaryData(const QString &namespaceUri, const QString &name, QxXmlWriter::type_byte_arr_ptr pData) + { + QString sKey(getNextKeyBinaryData()); + m_mapBinaryData.insert(sKey, pData); + + writeStartElement(namespaceUri, name); + writeAttribute(QX_XML_ATTRIBUTE_IS_BINARY_DATA, "1"); + writeCharacters(sKey); + writeEndElement(); + + return sKey; + } + + QString QxXmlWriter::writeBinaryData(const QString &qualifiedName, QxXmlWriter::type_byte_arr_ptr pData) + { + QString sKey(getNextKeyBinaryData()); + m_mapBinaryData.insert(sKey, pData); + + writeStartElement(qualifiedName); + writeAttribute(QX_XML_ATTRIBUTE_IS_BINARY_DATA, "1"); + writeCharacters(sKey); + writeEndElement(); + + return sKey; + } + +} // namespace qx + +QDataStream &operator<<(QDataStream &stream, const qx::QxXmlWriter &xmlWriter) +{ + stream << xmlWriter.getXml(); + stream << (qint32)(xmlWriter.getBinaryDataCount()); + + qx::QxXmlWriter::type_hash_bin_data_itr itr = xmlWriter.getBinaryDataItr(); + + while (itr.hasNext()) + { + itr.next(); + stream << itr.key(); + stream << (*itr.value()); + } + + return stream; +} diff --git a/src/all.cpp b/src/all.cpp new file mode 100644 index 0000000..609555a --- /dev/null +++ b/src/all.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +/*! + * \file all.cpp + * \author XDL Team + * \brief all.cpp file can be used to perform a Unity Build to reduce compilation times (http://stackoverflow.com/questions/543697/include-all-cpp-files-into-a-single-compilation-unit) : _QX_UNITY_BUILD compilation option must be defined (see QxOrm.pri configuration file for more details) + */ + +#ifdef _QX_UNITY_BUILD + +#include + +#include "./QxMemLeak/bool_array.cpp" +#include "./QxMemLeak/debug_new.cpp" +#include "./QxMemLeak/mem_pool_base.cpp" +#include "./QxMemLeak/static_mem_pool.cpp" + +#include "./QxSingleton/IxSingleton.cpp" +#include "./QxSingleton/QxSingletonX.cpp" +#include "./QxSingleton/QxSingletonInit.cpp" + +#include "./QxFactory/IxFactory.cpp" +#include "./QxFactory/QxFactoryX.cpp" + +#include "./QxCollection/QxCollection.cpp" + +#include "./QxCommon/QxBool.cpp" +#include "./QxCommon/QxCache.cpp" +#include "./QxCommon/QxSimpleCrypt.cpp" + +#include "./QxConvert/QxConvert_Export.cpp" + +#include "./QxRegister/IxClass.cpp" +#include "./QxRegister/QxClassX.cpp" + +#include "./QxDataMember/IxDataMember.cpp" +#include "./QxDataMember/IxDataMemberX.cpp" +#include "./QxDataMember/QxDataMember_QObject.cpp" + +#include "./QxTraits/unit_test_is_smart_ptr.cpp" +#include "./QxTraits/unit_test_is_container.cpp" + +// #include "./QxXml/QxXmlReader.cpp" +// #include "./QxXml/QxXmlWriter.cpp" + +#include "./QxDao/IxSqlQueryBuilder.cpp" +#include "./QxDao/QxSqlDatabase.cpp" +#include "./QxDao/IxSqlRelation.cpp" +#include "./QxDao/QxSqlQuery.cpp" +#include "./QxDao/QxSession.cpp" +#include "./QxDao/IxDao_Helper.cpp" +#include "./QxDao/IxPersistable.cpp" +#include "./QxDao/IxPersistableCollection.cpp" +#include "./QxDao/IxPersistableList.cpp" +#include "./QxDao/QxSqlRelationLinked.cpp" +#include "./QxDao/QxDaoAsync.cpp" +#include "./QxDao/QxSqlRelationParams.cpp" +#include "./QxDao/QxSoftDelete.cpp" +#include "./QxDao/QxDateNeutral.cpp" +#include "./QxDao/QxDateTimeNeutral.cpp" +#include "./QxDao/QxTimeNeutral.cpp" + +#include "./QxDao/QxSqlElement/IxSqlElement.cpp" +#include "./QxDao/QxSqlElement/QxSqlCompare.cpp" +#include "./QxDao/QxSqlElement/QxSqlElementTemp.cpp" +#include "./QxDao/QxSqlElement/QxSqlEmbedQuery.cpp" +#include "./QxDao/QxSqlElement/QxSqlExpression.cpp" +#include "./QxDao/QxSqlElement/QxSqlFreeText.cpp" +#include "./QxDao/QxSqlElement/QxSqlIn.cpp" +#include "./QxDao/QxSqlElement/QxSqlIsBetween.cpp" +#include "./QxDao/QxSqlElement/QxSqlIsNull.cpp" +#include "./QxDao/QxSqlElement/QxSqlLimit.cpp" +#include "./QxDao/QxSqlElement/QxSqlSort.cpp" + +#include "./QxDao/QxSqlGenerator/IxSqlGenerator.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_MySQL.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_Oracle.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_PostgreSQL.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_SQLite.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_MSSQLServer.cpp" +#include "./QxDao/QxSqlGenerator/QxSqlGenerator_Standard.cpp" + +#include "./QxDao/QxRepository/IxRepository.cpp" +#include "./QxDao/QxRepository/QxRepositoryX.cpp" + +#ifdef _QX_ENABLE_MONGODB +#include "./QxDao/QxMongoDB/QxMongoDB_Helper.cpp" +#endif // _QX_ENABLE_MONGODB + +#include "./QxSerialize/QxSerializeCheckInstance.cpp" + +#include "./QxSerialize/QxBoostSerializeHelper/IxBoostSerializeRegisterHelper.cpp" +#include "./QxSerialize/QxBoostSerializeHelper/QxBoostSerializeRegisterHelperX.cpp" + +#include "./QxSerialize/boost/QxExportDllBoostArchive.cpp" + +#include "./QxSerialize/Qt/QxSerialize_QBrush.cpp" +#include "./QxSerialize/Qt/QxSerialize_QByteArray.cpp" +#include "./QxSerialize/Qt/QxSerialize_QColor.cpp" +#include "./QxSerialize/Qt/QxSerialize_QDate.cpp" +#include "./QxSerialize/Qt/QxSerialize_QDateTime.cpp" +#include "./QxSerialize/Qt/QxSerialize_QFont.cpp" +#include "./QxSerialize/Qt/QxSerialize_QImage.cpp" +#include "./QxSerialize/Qt/QxSerialize_QMatrix.cpp" +#include "./QxSerialize/Qt/QxSerialize_QObject.cpp" +#include "./QxSerialize/Qt/QxSerialize_QPicture.cpp" +#include "./QxSerialize/Qt/QxSerialize_QPixmap.cpp" +#include "./QxSerialize/Qt/QxSerialize_QPoint.cpp" +#include "./QxSerialize/Qt/QxSerialize_QRect.cpp" +#include "./QxSerialize/Qt/QxSerialize_QRegExp.cpp" +#include "./QxSerialize/Qt/QxSerialize_QRegion.cpp" +#include "./QxSerialize/Qt/QxSerialize_QSize.cpp" +#include "./QxSerialize/Qt/QxSerialize_QString.cpp" +#include "./QxSerialize/Qt/QxSerialize_QStringList.cpp" +#include "./QxSerialize/Qt/QxSerialize_QTime.cpp" +#include "./QxSerialize/Qt/QxSerialize_QUrl.cpp" +#include "./QxSerialize/Qt/QxSerialize_QUuid.cpp" +#include "./QxSerialize/Qt/QxSerialize_QVariant.cpp" +#include "./QxSerialize/Qt/QxSerialize_QSqlError.cpp" + +#include "./QxSerialize/QDataStream/QxSerializeQDataStream_primitive_type.cpp" +#include "./QxSerialize/QDataStream/QxSerializeQDataStream_QObject.cpp" +#include "./QxSerialize/QDataStream/QxSerializeQDataStream_QSqlError.cpp" +#include "./QxSerialize/QDataStream/QxSerializeQDataStream_std_string.cpp" +#include "./QxSerialize/QDataStream/QxSerializeQDataStream_qx_registered_class.cpp" + +#include "./QxSerialize/QJson/QxSerializeQJson_qx_registered_class.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_IxService.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_IxSqlElement.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QBrush.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QColor.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QFont.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QImage.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QMatrix.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QObject.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QPicture.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QPixmap.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QPoint.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QRect.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QRegExp.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QRegion.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QSize.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QSqlError.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QStringList.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QxInvalidValue.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QxInvalidValueX.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QxSqlQuery.cpp" +#include "./QxSerialize/QJson/QxSerializeQJson_QxTransaction.cpp" + +#include "./QxRestApi/QxRestApi.cpp" + +#include "./QxService/IxParameter.cpp" +#include "./QxService/IxService.cpp" +#include "./QxService/QxConnect.cpp" +#include "./QxService/QxServer.cpp" +#include "./QxService/QxThread.cpp" +#include "./QxService/QxThreadPool.cpp" +#include "./QxService/QxTools.cpp" +#include "./QxService/QxTransaction.cpp" + +#include "./QxHttpServer/QxHttpRequest.cpp" +#include "./QxHttpServer/QxHttpResponse.cpp" +#include "./QxHttpServer/QxHttpServer.cpp" +#include "./QxHttpServer/QxHttpTransaction.cpp" +#include "./QxHttpServer/QxHttpCookie.cpp" +#include "./QxHttpServer/QxHttpSession.cpp" +#include "./QxHttpServer/QxHttpSessionManager.cpp" + +#include "./QxValidator/IxValidator.cpp" +#include "./QxValidator/IxValidatorX.cpp" +#include "./QxValidator/QxInvalidValue.cpp" +#include "./QxValidator/QxInvalidValueX.cpp" + +#include "./QxModelView/IxModel.cpp" +#include "./QxModelView/QxNestedModel.cpp" +#include "./QxModelView/QxModelRowCompare.cpp" + +#include "./main.cpp" + +#endif // _QX_UNITY_BUILD diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..4b37fe5 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include + +#ifdef Q_OS_WIN +#ifndef _QX_STATIC_BUILD + +#include + +extern "C" int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReservedt */) +{ + Q_UNUSED(hInstance); + Q_UNUSED(dwReason); + +#ifndef _QX_NO_TRACE_DLL_ATTACH_DETACH + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + ::OutputDebugStringA("QxOrm.DllMain() ---> DLL_PROCESS_ATTACH\n"); + break; + case DLL_PROCESS_DETACH: + ::OutputDebugStringA("QxOrm.DllMain() ---> DLL_PROCESS_DETACH\n"); + break; + case DLL_THREAD_ATTACH: + ::OutputDebugStringA("QxOrm.DllMain() ---> DLL_THREAD_ATTACH\n"); + break; + case DLL_THREAD_DETACH: + ::OutputDebugStringA("QxOrm.DllMain() ---> DLL_THREAD_DETACH\n"); + break; + } +#endif // _QX_NO_TRACE_DLL_ATTACH_DETACH + + return 1; +} + +#endif // _QX_STATIC_BUILD +#endif // Q_OS_WIN diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..6eb5156 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.1) + +project(QxOrmAllTests LANGUAGES CXX) + +add_subdirectory(../ ./QxOrm) + +add_subdirectory(qxBlog) +add_subdirectory(qxBlogCompositeKey) +add_subdirectory(qxBlogCpp11) +add_subdirectory(qxBlogModelView) +add_subdirectory(qxDllSample) +add_subdirectory(qxClientServer) +add_subdirectory(qxBlogMongoDB) +add_subdirectory(qxBlogPImpl) +add_subdirectory(qxBlogRestApi) diff --git a/test/_bin/.gitignore b/test/_bin/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/_bin/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlog/CMakeLists.txt b/test/qxBlog/CMakeLists.txt new file mode 100644 index 0000000..371d12e --- /dev/null +++ b/test/qxBlog/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlog LANGUAGES CXX) + +include(../../QxOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ) + +add_executable(qxBlog ${SRCS} ${HEADERS}) + +target_compile_definitions(qxBlog PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlog PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlog ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxBlog PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlog PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxBlog/debug/.gitignore b/test/qxBlog/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlog/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlog/include/author.h b/test/qxBlog/include/author.h new file mode 100644 index 0000000..1bbdbcb --- /dev/null +++ b/test/qxBlog/include/author.h @@ -0,0 +1,33 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; +// -- enum + enum enum_sex { male, female, unknown }; +// -- properties + QString m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; +// -- contructor, virtual destructor + author() : m_id("0"), m_sex(unknown) { ; } + virtual ~author() { ; } +// -- methods + int age() const; +}; + +QX_REGISTER_PRIMARY_KEY(author, QString) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlog/include/blog.h b/test/qxBlog/include/blog.h new file mode 100644 index 0000000..0529d99 --- /dev/null +++ b/test/qxBlog/include/blog.h @@ -0,0 +1,28 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog +{ +public: +// -- properties + long m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; +// -- contructor, virtual destructor + blog() : m_id(0) { ; } + virtual ~blog() { ; } +}; + +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlog/include/category.h b/test/qxBlog/include/category.h new file mode 100644 index 0000000..2840089 --- /dev/null +++ b/test/qxBlog/include/category.h @@ -0,0 +1,27 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; +// -- properties + long m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; +// -- contructor, virtual destructor + category() : m_id(0) { ; } + virtual ~category() { ; } +}; + +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlog/include/comment.h b/test/qxBlog/include/comment.h new file mode 100644 index 0000000..a2bdb6f --- /dev/null +++ b/test/qxBlog/include/comment.h @@ -0,0 +1,26 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; +// -- properties + long m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; +// -- contructor, virtual destructor + comment() : m_id(0) { ; } + virtual ~comment() { ; } +}; + +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlog/include/export.h b/test/qxBlog/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlog/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlog/include/precompiled.h b/test/qxBlog/include/precompiled.h new file mode 100644 index 0000000..0d8b994 --- /dev/null +++ b/test/qxBlog/include/precompiled.h @@ -0,0 +1,8 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlog/qt/moc/.gitignore b/test/qxBlog/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlog/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlog/qxBlog.pro b/test/qxBlog/qxBlog.pro new file mode 100644 index 0000000..326ad74 --- /dev/null +++ b/test/qxBlog/qxBlog.pro @@ -0,0 +1,34 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogd +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlog +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxBlog/release/.gitignore b/test/qxBlog/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlog/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlog/src/author.cpp b/test/qxBlog/src/author.cpp new file mode 100644 index 0000000..7fafb3b --- /dev/null +++ b/test/qxBlog/src/author.cpp @@ -0,0 +1,28 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, "author_id"); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate"); + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, "list_blog", "author_id"); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} diff --git a/test/qxBlog/src/blog.cpp b/test/qxBlog/src/blog.cpp new file mode 100644 index 0000000..dd0aa68 --- /dev/null +++ b/test/qxBlog/src/blog.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, "blog_id"); + + t.data(& blog::m_text, "blog_text"); + t.data(& blog::m_dt_creation, "date_creation"); + + t.relationManyToOne(& blog::m_author, "author_id"); + t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); + t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", "blog_id", "category_id"); +}} diff --git a/test/qxBlog/src/category.cpp b/test/qxBlog/src/category.cpp new file mode 100644 index 0000000..723fda5 --- /dev/null +++ b/test/qxBlog/src/category.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, "category_id"); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id"); +}} diff --git a/test/qxBlog/src/comment.cpp b/test/qxBlog/src/comment.cpp new file mode 100644 index 0000000..d2d5cd5 --- /dev/null +++ b/test/qxBlog/src/comment.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, "comment_id"); + + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, "blog_id"); +}} diff --git a/test/qxBlog/src/main.cpp b/test/qxBlog/src/main.cpp new file mode 100644 index 0000000..895de56 --- /dev/null +++ b/test/qxBlog/src/main.cpp @@ -0,0 +1,425 @@ +#include "../include/precompiled.h" + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +int main(int argc, char * argv[]) +{ + // Qt application + QCoreApplication app(argc, argv); + QFile::remove("./qxBlog.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::QxSqlDatabase::getSingleton()->setFormatSqlQueryBeforeLogging(true); + qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->m_id = "author_id_1"; author_1->m_name = "author_1"; + author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate(); + author_2->m_id = "author_id_2"; author_2->m_name = "author_2"; + author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate(); + author_3->m_id = "author_id_3"; author_3->m_name = "author_3"; + author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate(); + + list_author authorX; + authorX.insert(author_1->m_id, author_1); + authorX.insert(author_2->m_id, author_2); + authorX.insert(author_3->m_id, author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Delete all authors in database and try to insert them using exec batch method + daoError = qx::dao::delete_all(); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 0); + daoError = qx::dao::insert(authorX, NULL, true); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone(* author_2); + qAssert(author_clone->m_id == "author_id_2"); + qAssert(author_clone->m_sex == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author, false); + qx::dump(list_of_female_author, true); + + // Test qx::QxSqlQuery::freeText() with/without placeholders + query = qx_query(); query.freeText("WHERE author.sex = " + QString::number(static_cast(author::female))); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + query = qx_query(); query.freeText("WHERE author.sex = :sex", QVariantList() << author::female); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + query = qx_query(); query.freeText("WHERE author.sex=:sex AND author.author_id=:author_id", QVariantList() << author::female << "author_id_2"); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 1); + query = qx_query(); query.freeText("WHERE (author.sex = :sex) AND (author.author_id = :author_id)", QVariantList() << author::female << "author_id_2"); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 1); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->m_id != 0); + qAssert(category_2->m_id != 0); + qAssert(category_3->m_id != 0); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(qx::dao::count() == 2); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->m_categoryX.insert(category_1->m_id, category_1); + blog_1->m_categoryX.insert(category_3->m_id, category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp, false); + qx::dump(blog_tmp, true); + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + list_blog lstBlogComplexRelation; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *", lstBlogComplexRelation); + qx::dump(lstBlogComplexRelation); + qAssert(lstBlogComplexRelation.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_dt_creation.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_blog); + + // Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... } + list_blog lstBlogComplexRelation2; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "-{ blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *", lstBlogComplexRelation2); + qx::dump(lstBlogComplexRelation2); + qAssert(lstBlogComplexRelation2.size() > 0); + qAssert(lstBlogComplexRelation2[0]->m_text == ""); // Not fetched + qAssert(! lstBlogComplexRelation2[0]->m_dt_creation.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_sex != author::unknown); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_name == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX.size() > 0); + qAssert(! lstBlogComplexRelation2[0]->m_commentX[0]->m_dt_create.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_text == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_blog); + +#ifndef _QX_NO_JSON + // Custom JSON serialization process + QString customJsonFull = qx::serialization::json::to_string(blog_tmp, 1); + QString customJsonFiltered = qx::serialization::json::to_string(blog_tmp, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + qDebug("[QxOrm] custom JSON serialization process (full) : \n%s", qPrintable(customJsonFull)); + qDebug("[QxOrm] custom JSON serialization process (filtered) : \n%s", qPrintable(customJsonFiltered)); + + blog_ptr blogFromJsonFull; blogFromJsonFull.reset(new blog()); + blog_ptr blogFromJsonFiltered; blogFromJsonFiltered.reset(new blog()); + qx::serialization::json::from_string(blogFromJsonFull, customJsonFull, 1); + qx::serialization::json::from_string(blogFromJsonFiltered, customJsonFull, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + + qx::dump(blogFromJsonFull); + qAssert(blogFromJsonFull->m_commentX.count() == 2); + qAssert(blogFromJsonFull->m_categoryX.count() == 2); + qAssert(blogFromJsonFull->m_text == "update blog_text_1"); + qAssert(blogFromJsonFull->m_author && blogFromJsonFull->m_author->m_id == "author_id_2"); + + qx::dump(blogFromJsonFiltered); + qAssert(blogFromJsonFiltered->m_text != ""); // Fetched + qAssert(blogFromJsonFiltered->m_dt_creation.isNull()); // Not fetched + qAssert(blogFromJsonFiltered->m_author->m_sex == author::unknown); // Not fetched + qAssert(blogFromJsonFiltered->m_author->m_name != ""); // Fetched + qAssert(blogFromJsonFiltered->m_commentX.size() > 0); + qAssert(blogFromJsonFiltered->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(blogFromJsonFiltered->m_commentX[0]->m_text != ""); // Fetched + qAssert(blogFromJsonFiltered->m_commentX[0]->m_blog); +#endif // _QX_NO_JSON + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + custom table alias using syntax + custom table alias suffix using syntax <..._my_alias_suffix> + list_blog lstBlogComplexRelation3; + daoError = qx::dao::fetch_all_with_relation(QStringList() << " { blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> * <..._my_alias_suffix>", lstBlogComplexRelation3); + qx::dump(lstBlogComplexRelation3); + qAssert(lstBlogComplexRelation3.size() > 0); + qAssert(lstBlogComplexRelation3[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_dt_creation.isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_blog); + + // Test to add join SQL sub-queries (inside LEFT OUTER JOIN or INNER JOIN) + list_blog lstBlogWithJoinQueries; + query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1"); + query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL"); + query.addJoinQuery("author_alias", qx_query().freeText("AND author_alias.sex = :sex", QVariantList() << author::female)); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_text }" << "author_id { name, birthdate, sex }" << "list_comment { comment_text }", query, lstBlogWithJoinQueries); + qx::dump(lstBlogWithJoinQueries); + qAssert(lstBlogWithJoinQueries.size() > 0); + qAssert(lstBlogWithJoinQueries[0]->m_text == "update blog_text_1"); + qAssert(lstBlogWithJoinQueries[0]->m_author->m_sex == author::female); + + // When join SQL sub-queries are used, then relationships should keep user defined order (in this example : 'list_comment' before 'author') + lstBlogWithJoinQueries.clear(); + query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1"); + query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL"); + query.addJoinQuery("author_alias", qx_query("AND author_alias.sex = :sex", QVariantList() << author::female)); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_text }" << "list_comment { comment_text }" << "author_id { name, birthdate, sex }", query, lstBlogWithJoinQueries); + qx::dump(lstBlogWithJoinQueries); + qAssert(lstBlogWithJoinQueries.size() > 0); + qAssert(lstBlogWithJoinQueries[0]->m_text == "update blog_text_1"); + qAssert(lstBlogWithJoinQueries[0]->m_author->m_sex == author::female); + + // Check qx::dao::save_with_relation_recursive() function + daoError = qx::dao::save_with_relation_recursive(blog_tmp); + qAssert(! daoError.isValid()); + daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only); + qAssert(! daoError.isValid()); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // Check count with relations and filter + long lBlogCountWithRelation = 0; qx_query queryBlogCountWithRelation; + daoError = qx::dao::count_with_relation(lBlogCountWithRelation, QStringList() << "author_id" << "list_comment -> blog_id -> *", queryBlogCountWithRelation); + qAssert(! daoError.isValid() && (lBlogCountWithRelation > 0)); + + // 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, false); + qx::dump(blog_isdirty, true); + + // 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, false); + qx::dump(container_isdirty, true); + + // 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].get() != NULL)) + { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); } + qx::dump(lst_blog_with_only_date_creation, false); + qx::dump(lst_blog_with_only_date_creation, true); + + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + // Call a custom SQL query or a stored procedure + qx_query testStoredProc("SELECT * FROM author"); + daoError = qx::dao::call_query(testStoredProc); + qAssert(! daoError.isValid()); + testStoredProc.dumpSqlResult(); + QVariant valFromSqlResult = testStoredProc.getSqlResultAt(0, "birthdate"); qAssert(! valFromSqlResult.isNull()); + valFromSqlResult = testStoredProc.getSqlResultAt(0, "BIRTHDATE", false); qAssert(! valFromSqlResult.isNull()); + valFromSqlResult = testStoredProc.getSqlResultAt(0, "BIRTHDATE", true); qAssert(valFromSqlResult.isNull()); + + // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items) + qx_query testStoredProcBis("SELECT * FROM author"); + authorX.clear(); + daoError = qx::dao::execute_query(testStoredProcBis, authorX); + qAssert(! daoError.isValid()); qAssert(authorX.count() > 0); + qx::dump(authorX, false); + qx::dump(authorX, true); + + // Call a custom SQL query or a stored procedure and fetch automatically properties + qx_query testStoredProcThird("SELECT name, category_id FROM category"); + category_ptr category_tmp = category_ptr(new category()); + daoError = qx::dao::execute_query(testStoredProcThird, category_tmp); + qAssert(! daoError.isValid()); qAssert(category_tmp->m_id != 0); + qx::dump(category_tmp, false); + qx::dump(category_tmp, true); + + // Test SQL DISTINCT keyword + QList listOfBlogDistinct; + qx_query queryDistinct; queryDistinct.distinct().limit(10); + daoError = qx::dao::fetch_by_query(queryDistinct, listOfBlogDistinct, NULL, QStringList() << "blog_text"); + qAssert(! daoError.isValid()); + qx::dump(listOfBlogDistinct); + qAssert(listOfBlogDistinct.count() > 0); + qAssert(listOfBlogDistinct.at(0).m_id == 0); + qAssert(! listOfBlogDistinct.at(0).m_text.isEmpty()); + + // Test SQL DISTINCT keyword with relationships + listOfBlogDistinct.clear(); + qx_query queryDistinctWithRelations; queryDistinctWithRelations.distinct().limit(10); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_text }" << "list_comment { comment_text }" << "author_id { name, birthdate }", queryDistinctWithRelations, listOfBlogDistinct); + qAssert(! daoError.isValid()); + qx::dump(listOfBlogDistinct); + qAssert(listOfBlogDistinct.count() > 0); + qAssert(listOfBlogDistinct.at(0).m_id == 0); + qAssert(! listOfBlogDistinct.at(0).m_text.isEmpty()); + qAssert(listOfBlogDistinct.at(0).m_author.get() != NULL); + qAssert(listOfBlogDistinct.at(0).m_author->m_id == "0"); // Not fetched + qAssert(! listOfBlogDistinct.at(0).m_author->m_name.isEmpty()); + qAssert(listOfBlogDistinct.at(0).m_commentX.size() > 1); + qAssert(listOfBlogDistinct.at(0).m_commentX.at(0)->m_id == 0); // Not fetched + qAssert(! listOfBlogDistinct.at(0).m_commentX.at(0)->m_text.isEmpty()); + + // Test SQL DISTINCT keyword with relationships forcing ID in root level + listOfBlogDistinct.clear(); + qx_query queryDistinctWithRelationsAndId; queryDistinctWithRelationsAndId.distinct().limit(10); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_id, blog_text }" << "list_comment { comment_text }" << "author_id { name, birthdate }", queryDistinctWithRelationsAndId, listOfBlogDistinct); + qAssert(! daoError.isValid()); + qx::dump(listOfBlogDistinct); + qAssert(listOfBlogDistinct.count() > 0); + qAssert(listOfBlogDistinct.at(0).m_id != 0); // Force fetched even if DISTINCT keyword is used + qAssert(! listOfBlogDistinct.at(0).m_text.isEmpty()); + qAssert(listOfBlogDistinct.at(0).m_author.get() != NULL); + qAssert(listOfBlogDistinct.at(0).m_author->m_id == "0"); // Not fetched + qAssert(! listOfBlogDistinct.at(0).m_author->m_name.isEmpty()); + qAssert(listOfBlogDistinct.at(0).m_commentX.size() > 1); + qAssert(listOfBlogDistinct.at(0).m_commentX.at(0)->m_id == 0); // Not fetched + qAssert(! listOfBlogDistinct.at(0).m_commentX.at(0)->m_text.isEmpty()); + + // Test fetch relationships (with alias) only in LEFT OUTER/INNER JOIN and WHERE clauses (so no columns in SELECT part) : use {NULL} syntax to define no relation columns in SELECT part + list_blog lstBlogComplexRelation4; + daoError = qx::dao::fetch_all_with_relation(QStringList() << " { blog_text }" << "author_id { NULL }" << "list_comment { NULL }", lstBlogComplexRelation4); + qAssert(! daoError.isValid()); + qx::dump(lstBlogComplexRelation4); + qAssert((lstBlogComplexRelation4.size() > 0) && (lstBlogComplexRelation4[0].get() != NULL)); + qAssert(lstBlogComplexRelation4[0]->m_author.get() == NULL); // Not fetched + qAssert(lstBlogComplexRelation4[0]->m_commentX.size() == 0); // Not fetched + + return 0; +} diff --git a/test/qxBlogCompositeKey/CMakeLists.txt b/test/qxBlogCompositeKey/CMakeLists.txt new file mode 100644 index 0000000..604f240 --- /dev/null +++ b/test/qxBlogCompositeKey/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogCompositeKey LANGUAGES CXX) + +include(../../QxOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ) + +add_executable(qxBlogCompositeKey ${SRCS} ${HEADERS}) + +target_compile_definitions(qxBlogCompositeKey PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogCompositeKey PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogCompositeKey ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxBlogCompositeKey PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogCompositeKey PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxBlogCompositeKey/debug/.gitignore b/test/qxBlogCompositeKey/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCompositeKey/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCompositeKey/include/author.h b/test/qxBlogCompositeKey/include/author.h new file mode 100644 index 0000000..0ac8879 --- /dev/null +++ b/test/qxBlogCompositeKey/include/author.h @@ -0,0 +1,57 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author +{ + + QX_REGISTER_FRIEND_CLASS(author) + +public: + +// -- composite key (multi-column primary key in database) + typedef std::tuple type_composite_key; + static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; + +// -- enum + enum enum_sex { male, female, unknown }; + +// -- properties + type_composite_key m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; + +// -- contructor, virtual destructor + author() : m_id("", 0, ""), m_sex(unknown) { ; } + virtual ~author() { ; } + +// -- methods + int age() const; + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + QString getId_0() const { return std::get<0>(m_id); } + long getId_1() const { return std::get<1>(m_id); } + QString getId_2() const { return std::get<2>(m_id); } + +// -- methods "set" to composite key + void setId_0(const QString & s) { std::get<0>(m_id) = s; } + void setId_1(long l) { std::get<1>(m_id) = l; } + void setId_2(const QString & s) { std::get<2>(m_id) = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogCompositeKey/include/blog.h b/test/qxBlogCompositeKey/include/blog.h new file mode 100644 index 0000000..59c72d7 --- /dev/null +++ b/test/qxBlogCompositeKey/include/blog.h @@ -0,0 +1,48 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog +{ + + QX_REGISTER_FRIEND_CLASS(blog) + +public: + +// -- composite key (multi-column primary key in database) + typedef QPair type_composite_key; + static QString str_composite_key() { return "blog_id_0|blog_id_1"; } + +// -- properties + type_composite_key m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; + +// -- contructor, virtual destructor + blog() : m_id(0, "") { ; } + virtual ~blog() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + long getId_0() const { return m_id.first; } + QString getId_1() const { return m_id.second; } + +// -- methods "set" to composite key + void setId_0(long l) { m_id.first = l; } + void setId_1(const QString & s) { m_id.second = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(blog, blog::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogCompositeKey/include/category.h b/test/qxBlogCompositeKey/include/category.h new file mode 100644 index 0000000..62d6c8c --- /dev/null +++ b/test/qxBlogCompositeKey/include/category.h @@ -0,0 +1,52 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ + + QX_REGISTER_FRIEND_CLASS(category) + +public: + +// -- composite key (multi-column primary key in database) + typedef std::tuple type_composite_key; + static QString str_composite_key() { return "category_id_0|category_id_1|category_id_2|category_id_3"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; + +// -- properties + type_composite_key m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; + +// -- contructor, virtual destructor + category() : m_id("", 0, "", 0) { ; } + virtual ~category() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + QString getId_0() const { return std::get<0>(m_id); } + long getId_1() const { return std::get<1>(m_id); } + QString getId_2() const { return std::get<2>(m_id); } + long getId_3() const { return std::get<3>(m_id); } + +// -- methods "set" to composite key + void setId_0(const QString & s) { std::get<0>(m_id) = s; } + void setId_1(long l) { std::get<1>(m_id) = l; } + void setId_2(const QString & s) { std::get<2>(m_id) = s; } + void setId_3(long l) { std::get<3>(m_id) = l; } + +}; + +QX_REGISTER_PRIMARY_KEY(category, category::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogCompositeKey/include/comment.h b/test/qxBlogCompositeKey/include/comment.h new file mode 100644 index 0000000..797cdd5 --- /dev/null +++ b/test/qxBlogCompositeKey/include/comment.h @@ -0,0 +1,47 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ + + QX_REGISTER_FRIEND_CLASS(comment) + +public: + +// -- composite key (multi-column primary key in database) + typedef std::tuple type_composite_key; + static QString str_composite_key() { return "comment_id_0|comment_id_1"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + +// -- properties + type_composite_key m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; + +// -- contructor, virtual destructor + comment() : m_id(0, "") { ; } + virtual ~comment() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + long getId_0() const { return std::get<0>(m_id); } + QString getId_1() const { return std::get<1>(m_id); } + +// -- methods "set" to composite key + void setId_0(long l) { std::get<0>(m_id) = l; } + void setId_1(const QString & s) { std::get<1>(m_id) = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(comment, comment::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogCompositeKey/include/export.h b/test/qxBlogCompositeKey/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogCompositeKey/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogCompositeKey/include/precompiled.h b/test/qxBlogCompositeKey/include/precompiled.h new file mode 100644 index 0000000..0d8b994 --- /dev/null +++ b/test/qxBlogCompositeKey/include/precompiled.h @@ -0,0 +1,8 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogCompositeKey/qt/moc/.gitignore b/test/qxBlogCompositeKey/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCompositeKey/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCompositeKey/qxBlog.pro b/test/qxBlogCompositeKey/qxBlog.pro new file mode 100644 index 0000000..9a7727d --- /dev/null +++ b/test/qxBlogCompositeKey/qxBlog.pro @@ -0,0 +1,34 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogCompositeKeyd +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogCompositeKey +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxBlogCompositeKey/release/.gitignore b/test/qxBlogCompositeKey/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCompositeKey/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCompositeKey/src/author.cpp b/test/qxBlogCompositeKey/src/author.cpp new file mode 100644 index 0000000..d08db6b --- /dev/null +++ b/test/qxBlogCompositeKey/src/author.cpp @@ -0,0 +1,28 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, author::str_composite_key()); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate"); + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key()); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} diff --git a/test/qxBlogCompositeKey/src/blog.cpp b/test/qxBlogCompositeKey/src/blog.cpp new file mode 100644 index 0000000..481cb8e --- /dev/null +++ b/test/qxBlogCompositeKey/src/blog.cpp @@ -0,0 +1,60 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +void logCustomSqlCallback(qx::IxDataMemberSqlCallbackParams & params, const QString & fctName) +{ + QString msg = "-- " + fctName + " : " + params.pDataMember->getNameParent() + "::" + params.pDataMember->getName() + " --"; + msg += "\nSQL query generated by QxOrm library for this data member : " + params.sSQL; + if (params.pSqlQueryBuilder) { msg += "\nCurrent building full SQL query (not finished yet) : " + params.pSqlQueryBuilder->getCurrentBuildingSql(); } + msg += "\n"; + qDebug(qPrintable(msg)); +} + +void myCustomGetSqlName(qx::IxDataMemberSqlCallbackParams & params) +{ + logCustomSqlCallback(params, "myCustomGetSqlName"); +} + +void myCustomGetSqlTablePointNameAsAlias(qx::IxDataMemberSqlCallbackParams & params) +{ + logCustomSqlCallback(params, "myCustomGetSqlTablePointNameAsAlias"); +} + +void myCustomGetSqlNameEqualToPlaceHolder(qx::IxDataMemberSqlCallbackParams & params) +{ + logCustomSqlCallback(params, "myCustomGetSqlNameEqualToPlaceHolder"); +} + +void myCustomGetSqlAliasEqualToPlaceHolder(qx::IxDataMemberSqlCallbackParams & params) +{ + logCustomSqlCallback(params, "myCustomGetSqlAliasEqualToPlaceHolder"); +} + +void myCustomGetSqlAlias(qx::IxDataMemberSqlCallbackParams & params) +{ + logCustomSqlCallback(params, "myCustomGetSqlAlias"); +} + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, blog::str_composite_key()); + + t.data(& blog::m_text, "blog_text"); + qx::IxDataMember * pData = t.data(& blog::m_dt_creation, "date_creation"); + + pData->customGetSqlName(myCustomGetSqlName); + pData->customGetSqlTablePointNameAsAlias(myCustomGetSqlTablePointNameAsAlias); + pData->customGetSqlNameEqualToPlaceHolder(myCustomGetSqlNameEqualToPlaceHolder); + pData->customGetSqlAliasEqualToPlaceHolder(myCustomGetSqlAliasEqualToPlaceHolder); + pData->customGetSqlAlias(myCustomGetSqlAlias); + + t.relationManyToOne(& blog::m_author, author::str_composite_key()); + t.relationOneToMany(& blog::m_commentX, comment::str_composite_key(), blog::str_composite_key()); + t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", blog::str_composite_key(), category::str_composite_key()); +}} diff --git a/test/qxBlogCompositeKey/src/category.cpp b/test/qxBlogCompositeKey/src/category.cpp new file mode 100644 index 0000000..cc27505 --- /dev/null +++ b/test/qxBlogCompositeKey/src/category.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, category::str_composite_key()); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", category::str_composite_key(), blog::str_composite_key()); +}} diff --git a/test/qxBlogCompositeKey/src/comment.cpp b/test/qxBlogCompositeKey/src/comment.cpp new file mode 100644 index 0000000..339995c --- /dev/null +++ b/test/qxBlogCompositeKey/src/comment.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, comment::str_composite_key()); + + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, blog::str_composite_key()); +}} diff --git a/test/qxBlogCompositeKey/src/main.cpp b/test/qxBlogCompositeKey/src/main.cpp new file mode 100644 index 0000000..853b908 --- /dev/null +++ b/test/qxBlogCompositeKey/src/main.cpp @@ -0,0 +1,225 @@ +#include "../include/precompiled.h" + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +int main(int argc, char * argv[]) +{ + // Qt application + QCoreApplication app(argc, argv); + QFile::remove("./qxBlogCompositeKey.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlogCompositeKey.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::QxSqlDatabase::getSingleton()->setAddSqlSquareBracketsForTableName(true); + qx::QxSqlDatabase::getSingleton()->setAddSqlSquareBracketsForColumnName(true); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + qx::IxSqlRelation::setTraceRelationInit(true); + qx::QxClassX::registerAllClasses(); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->setId_0("_111_"); author_1->setId_1(100); author_1->setId_2("1_1"); + author_1->m_name = "author_1"; author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate(); + author_2->setId_0("_222_"); author_2->setId_1(200); author_2->setId_2("2_2"); + author_2->m_name = "author_2"; author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate(); + author_3->setId_0("_333_"); author_3->setId_1(300); author_3->setId_2("3_3"); + author_3->m_name = "author_3"; author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate(); + + list_author authorX; + authorX.insert(author_1->getId(), author_1); + authorX.insert(author_2->getId(), author_2); + authorX.insert(author_3->getId(), author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone(* author_2); + qAssert(author_clone->getId() == author::type_composite_key("_222_", 200, "2_2")); + qAssert(author_clone->m_sex == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->setId_0("101"); category_1->setId_1(10); + category_1->setId_2("__11_XX"); category_1->setId_3(10010); + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->setId_0("202"); category_2->setId_1(20); + category_2->setId_2("__22_XX"); category_2->setId_3(20020); + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->setId_0("303"); category_3->setId_1(30); + category_3->setId_2("__33_XX"); category_3->setId_3(30030); + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->getId() == category::type_composite_key("101", 10, "__11_XX", 10010)); + qAssert(category_2->getId() == category::type_composite_key("202", 20, "__22_XX", 20020)); + qAssert(category_3->getId() == category::type_composite_key("303", 30, "__33_XX", 30030)); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->setId_0(1); + blog_1->setId_1("blog 1"); + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->setId_0(1); + comment_1->setId_1("comment 1"); + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->setId_0(2); + comment_2->setId_1("comment 2"); + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(! daoError.isValid() && (qx::dao::count() == 2)); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->m_categoryX.insert(category_1->getId(), category_1); + blog_1->m_categoryX.insert(category_3->getId(), category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->setId_0(blog_1->getId_0()); + blog_tmp->setId_1(blog_1->getId_1()); + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(! daoError.isValid()); + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->getId() == author::type_composite_key("_222_", 200, "2_2")); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp); + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + list_blog lstBlogComplexRelation; + daoError = qx::dao::fetch_all_with_relation(QStringList() << author::str_composite_key() + " { name, birthdate }" << comment::str_composite_key() + " { comment_text } -> " + blog::str_composite_key() + " -> *", lstBlogComplexRelation); + qx::dump(lstBlogComplexRelation); + qAssert(lstBlogComplexRelation.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_blog); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // Test 'isDirty()' method + qx::dao::ptr blog_isdirty = qx::dao::ptr(new blog()); + blog_isdirty->setId_0(blog_1->getId_0()); + blog_isdirty->setId_1(blog_1->getId_1()); + 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("|"))); } + + daoError = qx::dao::update(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("|"))); } + + daoError = qx::dao::save(container_isdirty); + qAssert(! daoError.isValid() && ! container_isdirty.isDirty()); + qx::dump(container_isdirty); + + return 0; +} diff --git a/test/qxBlogCpp11/CMakeLists.txt b/test/qxBlogCpp11/CMakeLists.txt new file mode 100644 index 0000000..ecd4e98 --- /dev/null +++ b/test/qxBlogCpp11/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogCpp11 LANGUAGES CXX) + +include(../../QxOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ) + +add_executable(qxBlogCpp11 ${SRCS} ${HEADERS}) + +target_compile_definitions(qxBlogCpp11 PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogCpp11 PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogCpp11 ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxBlogCpp11 PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogCpp11 PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxBlogCpp11/debug/.gitignore b/test/qxBlogCpp11/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCpp11/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCpp11/include/author.h b/test/qxBlogCpp11/include/author.h new file mode 100644 index 0000000..6ee2023 --- /dev/null +++ b/test/qxBlogCpp11/include/author.h @@ -0,0 +1,57 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author +{ + + QX_REGISTER_FRIEND_CLASS(author) + +public: + +// -- composite key (multi-column primary key in database) + typedef QX_TUPLE type_composite_key; + static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; + +// -- enum + enum enum_sex { male, female, unknown }; + +// -- properties + type_composite_key m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; + +// -- contructor, virtual destructor + author() : m_id("", 0, ""), m_sex(unknown) { ; } + virtual ~author() { ; } + +// -- methods + int age() const; + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + QString getId_0() const { return QX_TUPLE_GET<0>(m_id); } + long getId_1() const { return QX_TUPLE_GET<1>(m_id); } + QString getId_2() const { return QX_TUPLE_GET<2>(m_id); } + +// -- methods "set" to composite key + void setId_0(const QString & s) { QX_TUPLE_GET<0>(m_id) = s; } + void setId_1(long l) { QX_TUPLE_GET<1>(m_id) = l; } + void setId_2(const QString & s) { QX_TUPLE_GET<2>(m_id) = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(author, author::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogCpp11/include/blog.h b/test/qxBlogCpp11/include/blog.h new file mode 100644 index 0000000..59c72d7 --- /dev/null +++ b/test/qxBlogCpp11/include/blog.h @@ -0,0 +1,48 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog +{ + + QX_REGISTER_FRIEND_CLASS(blog) + +public: + +// -- composite key (multi-column primary key in database) + typedef QPair type_composite_key; + static QString str_composite_key() { return "blog_id_0|blog_id_1"; } + +// -- properties + type_composite_key m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; + +// -- contructor, virtual destructor + blog() : m_id(0, "") { ; } + virtual ~blog() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + long getId_0() const { return m_id.first; } + QString getId_1() const { return m_id.second; } + +// -- methods "set" to composite key + void setId_0(long l) { m_id.first = l; } + void setId_1(const QString & s) { m_id.second = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(blog, blog::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogCpp11/include/category.h b/test/qxBlogCpp11/include/category.h new file mode 100644 index 0000000..ff90f5d --- /dev/null +++ b/test/qxBlogCpp11/include/category.h @@ -0,0 +1,52 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ + + QX_REGISTER_FRIEND_CLASS(category) + +public: + +// -- composite key (multi-column primary key in database) + typedef QX_TUPLE type_composite_key; + static QString str_composite_key() { return "category_id_0|category_id_1|category_id_2|category_id_3"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; + +// -- properties + type_composite_key m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; + +// -- contructor, virtual destructor + category() : m_id("", 0, "", 0) { ; } + virtual ~category() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + QString getId_0() const { return QX_TUPLE_GET<0>(m_id); } + long getId_1() const { return QX_TUPLE_GET<1>(m_id); } + QString getId_2() const { return QX_TUPLE_GET<2>(m_id); } + long getId_3() const { return QX_TUPLE_GET<3>(m_id); } + +// -- methods "set" to composite key + void setId_0(const QString & s) { QX_TUPLE_GET<0>(m_id) = s; } + void setId_1(long l) { QX_TUPLE_GET<1>(m_id) = l; } + void setId_2(const QString & s) { QX_TUPLE_GET<2>(m_id) = s; } + void setId_3(long l) { QX_TUPLE_GET<3>(m_id) = l; } + +}; + +QX_REGISTER_PRIMARY_KEY(category, category::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogCpp11/include/comment.h b/test/qxBlogCpp11/include/comment.h new file mode 100644 index 0000000..bb4a682 --- /dev/null +++ b/test/qxBlogCpp11/include/comment.h @@ -0,0 +1,47 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ + + QX_REGISTER_FRIEND_CLASS(comment) + +public: + +// -- composite key (multi-column primary key in database) + typedef QX_TUPLE type_composite_key; + static QString str_composite_key() { return "comment_id_0|comment_id_1"; } + +// -- typedef + typedef std::shared_ptr blog_ptr; + +// -- properties + type_composite_key m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; + +// -- contructor, virtual destructor + comment() : m_id(0, "") { ; } + virtual ~comment() { ; } + +// -- methods "get" to composite key + type_composite_key getId() const { return m_id; } + long getId_0() const { return QX_TUPLE_GET<0>(m_id); } + QString getId_1() const { return QX_TUPLE_GET<1>(m_id); } + +// -- methods "set" to composite key + void setId_0(long l) { QX_TUPLE_GET<0>(m_id) = l; } + void setId_1(const QString & s) { QX_TUPLE_GET<1>(m_id) = s; } + +}; + +QX_REGISTER_PRIMARY_KEY(comment, comment::type_composite_key) +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogCpp11/include/export.h b/test/qxBlogCpp11/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogCpp11/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogCpp11/include/precompiled.h b/test/qxBlogCpp11/include/precompiled.h new file mode 100644 index 0000000..79e12d4 --- /dev/null +++ b/test/qxBlogCpp11/include/precompiled.h @@ -0,0 +1,24 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +/* +// To resolve a problem with MSVC++ 2010 and MSVC++ 2012 (and later ?) : +// These compilers provide a tuple header but BOOST_NO_CXX11_HDR_TUPLE macro is defined ! +// This is because these compilers doesn't provide variadic templates +#if (defined(_QX_CPP_11_TUPLE) && !defined(BOOST_NO_CXX11_HDR_TUPLE)) +#define QX_TUPLE std::tuple +#define QX_TUPLE_GET std::get +#else // (defined(_QX_CPP_11_TUPLE) && !defined(BOOST_NO_CXX11_HDR_TUPLE)) +#define QX_TUPLE boost::tuple +#define QX_TUPLE_GET boost::tuples::get +#endif // (defined(_QX_CPP_11_TUPLE) && !defined(BOOST_NO_CXX11_HDR_TUPLE)) +*/ + +#define QX_TUPLE std::tuple +#define QX_TUPLE_GET std::get + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogCpp11/qt/moc/.gitignore b/test/qxBlogCpp11/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCpp11/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCpp11/qxBlog.pro b/test/qxBlogCpp11/qxBlog.pro new file mode 100644 index 0000000..6cf9e47 --- /dev/null +++ b/test/qxBlogCpp11/qxBlog.pro @@ -0,0 +1,36 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +CONFIG += c++11 + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogCpp11d +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogCpp11 +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxBlogCpp11/release/.gitignore b/test/qxBlogCpp11/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogCpp11/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogCpp11/src/author.cpp b/test/qxBlogCpp11/src/author.cpp new file mode 100644 index 0000000..d08db6b --- /dev/null +++ b/test/qxBlogCpp11/src/author.cpp @@ -0,0 +1,28 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, author::str_composite_key()); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate"); + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key()); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} diff --git a/test/qxBlogCpp11/src/blog.cpp b/test/qxBlogCpp11/src/blog.cpp new file mode 100644 index 0000000..3e1e4eb --- /dev/null +++ b/test/qxBlogCpp11/src/blog.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, blog::str_composite_key()); + + t.data(& blog::m_text, "blog_text"); + t.data(& blog::m_dt_creation, "date_creation"); + + t.relationManyToOne(& blog::m_author, author::str_composite_key()); + t.relationOneToMany(& blog::m_commentX, comment::str_composite_key(), blog::str_composite_key()); + t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", blog::str_composite_key(), category::str_composite_key()); +}} diff --git a/test/qxBlogCpp11/src/category.cpp b/test/qxBlogCpp11/src/category.cpp new file mode 100644 index 0000000..cc27505 --- /dev/null +++ b/test/qxBlogCpp11/src/category.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, category::str_composite_key()); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", category::str_composite_key(), blog::str_composite_key()); +}} diff --git a/test/qxBlogCpp11/src/comment.cpp b/test/qxBlogCpp11/src/comment.cpp new file mode 100644 index 0000000..339995c --- /dev/null +++ b/test/qxBlogCpp11/src/comment.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, comment::str_composite_key()); + + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, blog::str_composite_key()); +}} diff --git a/test/qxBlogCpp11/src/main.cpp b/test/qxBlogCpp11/src/main.cpp new file mode 100644 index 0000000..e76c835 --- /dev/null +++ b/test/qxBlogCpp11/src/main.cpp @@ -0,0 +1,209 @@ +#include "../include/precompiled.h" + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +int main(int argc, char * argv[]) +{ + // Qt application + QCoreApplication app(argc, argv); + QFile::remove("./qxBlogCpp11.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlogCpp11.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->setId_0("_111_"); author_1->setId_1(100); author_1->setId_2("1_1"); + author_1->m_name = "author_1"; author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate(); + author_2->setId_0("_222_"); author_2->setId_1(200); author_2->setId_2("2_2"); + author_2->m_name = "author_2"; author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate(); + author_3->setId_0("_333_"); author_3->setId_1(300); author_3->setId_2("3_3"); + author_3->m_name = "author_3"; author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate(); + + list_author authorX; + authorX.insert(author_1->getId(), author_1); + authorX.insert(author_2->getId(), author_2); + authorX.insert(author_3->getId(), author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone_to_std_shared_ptr(* author_2); + qAssert(author_clone->getId() == author::type_composite_key("_222_", 200, "2_2")); + qAssert(author_clone->m_sex == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->setId_0("101"); category_1->setId_1(10); + category_1->setId_2("__11_XX"); category_1->setId_3(10010); + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->setId_0("202"); category_2->setId_1(20); + category_2->setId_2("__22_XX"); category_2->setId_3(20020); + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->setId_0("303"); category_3->setId_1(30); + category_3->setId_2("__33_XX"); category_3->setId_3(30030); + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->getId() == category::type_composite_key("101", 10, "__11_XX", 10010)); + qAssert(category_2->getId() == category::type_composite_key("202", 20, "__22_XX", 20020)); + qAssert(category_3->getId() == category::type_composite_key("303", 30, "__33_XX", 30030)); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->setId_0(1); + blog_1->setId_1("blog 1"); + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->setId_0(1); + comment_1->setId_1("comment 1"); + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->setId_0(2); + comment_2->setId_1("comment 2"); + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(! daoError.isValid() && (qx::dao::count() == 2)); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->m_categoryX.insert(category_1->getId(), category_1); + blog_1->m_categoryX.insert(category_3->getId(), category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->setId_0(blog_1->getId_0()); + blog_tmp->setId_1(blog_1->getId_1()); + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(! daoError.isValid()); + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->getId() == author::type_composite_key("_222_", 200, "2_2")); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // Test 'isDirty()' method + qx::dao::ptr blog_isdirty = qx::dao::ptr(new blog()); + blog_isdirty->setId_0(blog_1->getId_0()); + blog_isdirty->setId_1(blog_1->getId_1()); + 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("|"))); } + + daoError = qx::dao::update(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("|"))); } + + daoError = qx::dao::save(container_isdirty); + qAssert(! daoError.isValid() && ! container_isdirty.isDirty()); + qx::dump(container_isdirty); + + return 0; +} diff --git a/test/qxBlogModelView/CMakeLists.txt b/test/qxBlogModelView/CMakeLists.txt new file mode 100644 index 0000000..48e7b60 --- /dev/null +++ b/test/qxBlogModelView/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogModelView LANGUAGES CXX) + +include(../../QxOrm.cmake) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Widgets Quick Qml REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ./include/model_view_from_qxee/author.model_view.gen.h + ./include/model_view_from_qxee/blog.model_view.gen.h + ./include/model_view_from_qxee/category.model_view.gen.h + ./include/model_view_from_qxee/comment.model_view.gen.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ./src/model_view_from_qxee/author.model_view.gen.cpp + ./src/model_view_from_qxee/blog.model_view.gen.cpp + ./src/model_view_from_qxee/category.model_view.gen.cpp + ./src/model_view_from_qxee/comment.model_view.gen.cpp + ) + +set(QRCS + ./qt/rcc/qxBlogModelView.qrc + ) + +if(COMMAND qt_add_resources) +qt_add_resources(QRCS_HDRS ${QRCS}) +else() # (COMMAND qt_add_resources) +qt5_add_resources(QRCS_HDRS ${QRCS}) +endif() # (COMMAND qt_add_resources) + +add_executable(qxBlogModelView ${SRCS} ${HEADERS} ${QRCS_HDRS}) + +target_compile_definitions(qxBlogModelView PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogModelView PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogModelView ${QX_LIBRARIES} QxOrm Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Qml) + +set_target_properties(qxBlogModelView PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogModelView PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxBlogModelView/debug/.gitignore b/test/qxBlogModelView/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogModelView/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogModelView/include/author.h b/test/qxBlogModelView/include/author.h new file mode 100644 index 0000000..b778fe3 --- /dev/null +++ b/test/qxBlogModelView/include/author.h @@ -0,0 +1,49 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; + typedef std::vector type_list_of_blog; +// -- enum + enum enum_sex { male, female, unknown }; +// -- properties + QString m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; +// -- contructor, virtual destructor + author() : m_id("0"), m_sex(unknown) { ; } + virtual ~author() { ; } +// -- methods + int age() const; + + QString getauthor_id() const; + QString getname() const; + QDate getbirthdate() const; + enum_sex getsex() const; + type_list_of_blog getlist_of_blog() const; + type_list_of_blog & list_of_blog(); + const type_list_of_blog & list_of_blog() const; + + void setauthor_id(const QString & val); + void setname(const QString & val); + void setbirthdate(const QDate & val); + void setsex(const enum_sex & val); + void setlist_of_blog(const type_list_of_blog & val); + +}; + +QX_REGISTER_PRIMARY_KEY(author, QString) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogModelView/include/blog.h b/test/qxBlogModelView/include/blog.h new file mode 100644 index 0000000..e84c7f6 --- /dev/null +++ b/test/qxBlogModelView/include/blog.h @@ -0,0 +1,53 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog +{ +public: + + typedef std::shared_ptr type_author; + typedef QList type_list_of_comment; + typedef qx::QxCollection type_list_of_category; + +// -- properties + long m_id; + QString m_title; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; +// -- contructor, virtual destructor + blog() : m_id(0) { ; } + virtual ~blog() { ; } + + long getblog_id() const; + QString gettitle() const; + QString gettext() const; + type_author getauthor() const; + type_list_of_comment getlist_of_comment() const; + type_list_of_comment & list_of_comment(); + const type_list_of_comment & list_of_comment() const; + type_list_of_category getlist_of_category() const; + type_list_of_category & list_of_category(); + const type_list_of_category & list_of_category() const; + + void setblog_id(const long & val); + void settitle(const QString & val); + void settext(const QString & val); + void setauthor(const type_author & val); + void setlist_of_comment(const type_list_of_comment & val); + void setlist_of_category(const type_list_of_category & val); + +}; + +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogModelView/include/category.h b/test/qxBlogModelView/include/category.h new file mode 100644 index 0000000..40d1d92 --- /dev/null +++ b/test/qxBlogModelView/include/category.h @@ -0,0 +1,41 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; + typedef qx::QxCollection type_list_of_blog; +// -- properties + long m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; +// -- contructor, virtual destructor + category() : m_id(0) { ; } + virtual ~category() { ; } + + long getcategory_id() const; + QString getname() const; + QString getdescription() const; + type_list_of_blog getlist_of_blog() const; + type_list_of_blog & list_of_blog(); + const type_list_of_blog & list_of_blog() const; + + void setcategory_id(const long & val); + void setname(const QString & val); + void setdescription(const QString & val); + void setlist_of_blog(const type_list_of_blog & val); + +}; + +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogModelView/include/comment.h b/test/qxBlogModelView/include/comment.h new file mode 100644 index 0000000..e2e97af --- /dev/null +++ b/test/qxBlogModelView/include/comment.h @@ -0,0 +1,39 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::shared_ptr type_blog_id; +// -- properties + long m_id; + QString m_title; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; +// -- contructor, virtual destructor + comment() : m_id(0) { ; } + virtual ~comment() { ; } + + long getcomment_id() const; + QString gettitle() const; + QString gettext() const; + type_blog_id getblog_id() const; + + void setcomment_id(const long & val); + void settitle(const QString & val); + void settext(const QString & val); + void setblog_id(const type_blog_id & val); + +}; + +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogModelView/include/export.h b/test/qxBlogModelView/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogModelView/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogModelView/include/model_view_from_qxee/author.model_view.gen.h b/test/qxBlogModelView/include/model_view_from_qxee/author.model_view.gen.h new file mode 100644 index 0000000..99d203d --- /dev/null +++ b/test/qxBlogModelView/include/model_view_from_qxee/author.model_view.gen.h @@ -0,0 +1,50 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#ifndef _QXBLOG_AUTHOR_MODEL_VIEW_H_ +#define _QXBLOG_AUTHOR_MODEL_VIEW_H_ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../../include/author.h" + +namespace model_view { + +typedef qx::QxModel author_model_base_class; + +class QX_BLOG_DLL_EXPORT author_model : public author_model_base_class +{ + + Q_OBJECT + +public: + + author_model(QObject * parent = 0); + author_model(qx::IxModel * other, QObject * parent); + virtual ~author_model(); + + Q_INVOKABLE QObject * list_of_blog(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + + /* List of properties exposed by the model (5) : + - author_id + - firstname + - lastname + - birthdate + - sex + */ + +protected: + + virtual void syncNestedModel(int row, const QStringList & relation); + virtual void syncAllNestedModel(const QStringList & relation); + +}; + +} // namespace model_view + +#endif // _QXBLOG_AUTHOR_MODEL_VIEW_H_ diff --git a/test/qxBlogModelView/include/model_view_from_qxee/blog.model_view.gen.h b/test/qxBlogModelView/include/model_view_from_qxee/blog.model_view.gen.h new file mode 100644 index 0000000..a7be9ea --- /dev/null +++ b/test/qxBlogModelView/include/model_view_from_qxee/blog.model_view.gen.h @@ -0,0 +1,50 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#ifndef _QXBLOG_BLOG_MODEL_VIEW_H_ +#define _QXBLOG_BLOG_MODEL_VIEW_H_ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../../include/blog.h" + +namespace model_view { + +typedef qx::QxModel blog_model_base_class; + +class QX_BLOG_DLL_EXPORT blog_model : public blog_model_base_class +{ + + Q_OBJECT + +public: + + blog_model(QObject * parent = 0); + blog_model(qx::IxModel * other, QObject * parent); + virtual ~blog_model(); + + Q_INVOKABLE QObject * author_id(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + Q_INVOKABLE QObject * list_of_comment(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + Q_INVOKABLE QObject * list_of_category(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + + /* List of properties exposed by the model (3) : + - blog_id + - title + - text + */ + +protected: + + virtual void syncNestedModel(int row, const QStringList & relation); + virtual void syncAllNestedModel(const QStringList & relation); + +}; + +} // namespace model_view + +#endif // _QXBLOG_BLOG_MODEL_VIEW_H_ diff --git a/test/qxBlogModelView/include/model_view_from_qxee/category.model_view.gen.h b/test/qxBlogModelView/include/model_view_from_qxee/category.model_view.gen.h new file mode 100644 index 0000000..96ea941 --- /dev/null +++ b/test/qxBlogModelView/include/model_view_from_qxee/category.model_view.gen.h @@ -0,0 +1,48 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#ifndef _QXBLOG_CATEGORY_MODEL_VIEW_H_ +#define _QXBLOG_CATEGORY_MODEL_VIEW_H_ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../../include/category.h" + +namespace model_view { + +typedef qx::QxModel category_model_base_class; + +class QX_BLOG_DLL_EXPORT category_model : public category_model_base_class +{ + + Q_OBJECT + +public: + + category_model(QObject * parent = 0); + category_model(qx::IxModel * other, QObject * parent); + virtual ~category_model(); + + Q_INVOKABLE QObject * list_of_blog(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + + /* List of properties exposed by the model (3) : + - category_id + - name + - description + */ + +protected: + + virtual void syncNestedModel(int row, const QStringList & relation); + virtual void syncAllNestedModel(const QStringList & relation); + +}; + +} // namespace model_view + +#endif // _QXBLOG_CATEGORY_MODEL_VIEW_H_ diff --git a/test/qxBlogModelView/include/model_view_from_qxee/comment.model_view.gen.h b/test/qxBlogModelView/include/model_view_from_qxee/comment.model_view.gen.h new file mode 100644 index 0000000..7ec418d --- /dev/null +++ b/test/qxBlogModelView/include/model_view_from_qxee/comment.model_view.gen.h @@ -0,0 +1,48 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#ifndef _QXBLOG_COMMENT_MODEL_VIEW_H_ +#define _QXBLOG_COMMENT_MODEL_VIEW_H_ + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../../include/comment.h" + +namespace model_view { + +typedef qx::QxModel comment_model_base_class; + +class QX_BLOG_DLL_EXPORT comment_model : public comment_model_base_class +{ + + Q_OBJECT + +public: + + comment_model(QObject * parent = 0); + comment_model(qx::IxModel * other, QObject * parent); + virtual ~comment_model(); + + Q_INVOKABLE QObject * blog_id(int row, bool bLoadFromDatabase = false, const QString & sAppendRelations = QString()); + + /* List of properties exposed by the model (3) : + - comment_id + - title + - text + */ + +protected: + + virtual void syncNestedModel(int row, const QStringList & relation); + virtual void syncAllNestedModel(const QStringList & relation); + +}; + +} // namespace model_view + +#endif // _QXBLOG_COMMENT_MODEL_VIEW_H_ diff --git a/test/qxBlogModelView/include/precompiled.h b/test/qxBlogModelView/include/precompiled.h new file mode 100644 index 0000000..e5cbe6c --- /dev/null +++ b/test/qxBlogModelView/include/precompiled.h @@ -0,0 +1,9 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogModelView/qt/moc/.gitignore b/test/qxBlogModelView/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogModelView/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogModelView/qt/rcc/documents/main.qml b/test/qxBlogModelView/qt/rcc/documents/main.qml new file mode 100644 index 0000000..183fe1d --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/documents/main.qml @@ -0,0 +1,37 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 + +Item { + width: 400 + height: 300 + Row { + height: 20 + spacing: 20 + Button { + text: "Clear" + onClicked: myModel.clear() + } + Button { + text: "Fetch All" + onClicked: myModel.qxFetchAll_() + } + Button { + text: "Save" + onClicked: myModel.qxSave_() + } + } + ListView { + y: 30 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "id: " + author_id } + TextField { + text: name + onTextChanged: name = text + } + } + } +} diff --git a/test/qxBlogModelView/qt/rcc/documents/main_qt4.qml b/test/qxBlogModelView/qt/rcc/documents/main_qt4.qml new file mode 100644 index 0000000..7ba8d21 --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/documents/main_qt4.qml @@ -0,0 +1,16 @@ +import QtQuick 1.0 + +Item { + width: 400 + height: 300 + ListView { + anchors.fill: parent + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "id: " + author_id } + Text { text: "name: " + name } + } + } +} diff --git a/test/qxBlogModelView/qt/rcc/documents/main_qt6.qml b/test/qxBlogModelView/qt/rcc/documents/main_qt6.qml new file mode 100644 index 0000000..d278f59 --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/documents/main_qt6.qml @@ -0,0 +1,37 @@ +import QtQuick +import QtQuick.Controls + +Item { + width: 400 + height: 300 + Row { + height: 20 + spacing: 20 + Button { + text: "Clear" + onClicked: myModel.clear() + } + Button { + text: "Fetch All" + onClicked: myModel.qxFetchAll_() + } + Button { + text: "Save" + onClicked: myModel.qxSave_() + } + } + ListView { + y: 30 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "id: " + author_id } + TextField { + text: name + onTextChanged: name = text + } + } + } +} diff --git a/test/qxBlogModelView/qt/rcc/documents/main_relationship.qml b/test/qxBlogModelView/qt/rcc/documents/main_relationship.qml new file mode 100644 index 0000000..9bba5fc --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/documents/main_relationship.qml @@ -0,0 +1,93 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 + +Item { + width: 500 + height: 300 + + /* + 1- How to display a relationship value : + * root model : blog + * child model : author + * display author name using getModelValue() method of qx::IxModel base class + */ + Text { + y: 30 + color: "blue" + text: "--- 1. display relationship author name using getModelValue() method of qx::IxModel base class ---" + } + ListView { + y: 50 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + Text { text: "author name : " + myModel.author_id(0).getModelValue(0, "name") } // display author name using getModelValue() method of qx::IxModel base class + } + } + + /* + 2- How to display a relationship value : + * root model : blog + * child model : author + * display author name passing the author child model to another QML component, then using the role value + */ + Text { + y: 80 + color: "blue" + text: "--- 2. display relationship author name passing the author child model to another QML component, then using the author 'name' role value ---" + } + ListView { + y: 100 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + ListView { + x: 200 + height: 270 + model: myModel.author_id(0) // pass the author child model to another QML component + delegate: Row { + Text { text: "author name : " + name } // use role 'name' defined in author class to display the author name + } + } + } + } + + /* + 3- Display the author row id in database using the 'author_id' role defined in blog class + */ + Text { + y: 130 + color: "blue" + text: "--- 3. display the author row id in database using the 'author_id' role defined in blog class ---" + } + ListView { + y: 150 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + Text { text: "author id : " + author_id } + } + } + +} diff --git a/test/qxBlogModelView/qt/rcc/documents/main_relationship_qt6.qml b/test/qxBlogModelView/qt/rcc/documents/main_relationship_qt6.qml new file mode 100644 index 0000000..78637b5 --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/documents/main_relationship_qt6.qml @@ -0,0 +1,93 @@ +import QtQuick +import QtQuick.Controls + +Item { + width: 500 + height: 300 + + /* + 1- How to display a relationship value : + * root model : blog + * child model : author + * display author name using getModelValue() method of qx::IxModel base class + */ + Text { + y: 30 + color: "blue" + text: "--- 1. display relationship author name using getModelValue() method of qx::IxModel base class ---" + } + ListView { + y: 50 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + Text { text: "author name : " + myModel.author_id(0).getModelValue(0, "name") } // display author name using getModelValue() method of qx::IxModel base class + } + } + + /* + 2- How to display a relationship value : + * root model : blog + * child model : author + * display author name passing the author child model to another QML component, then using the role value + */ + Text { + y: 80 + color: "blue" + text: "--- 2. display relationship author name passing the author child model to another QML component, then using the author 'name' role value ---" + } + ListView { + y: 100 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + ListView { + x: 200 + height: 270 + model: myModel.author_id(0) // pass the author child model to another QML component + delegate: Row { + Text { text: "author name : " + name } // use role 'name' defined in author class to display the author name + } + } + } + } + + /* + 3- Display the author row id in database using the 'author_id' role defined in blog class + */ + Text { + y: 130 + color: "blue" + text: "--- 3. display the author row id in database using the 'author_id' role defined in blog class ---" + } + ListView { + y: 150 + height: 270 + model: myModel + delegate: Row { + height: 20 + spacing: 10 + Text { text: "blog id : " + blog_id } + TextField { + text: blog_text + onTextChanged: blog_text = text + } + Text { text: "author id : " + author_id } + } + } + +} diff --git a/test/qxBlogModelView/qt/rcc/images/.gitignore b/test/qxBlogModelView/qt/rcc/images/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/images/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogModelView/qt/rcc/qxBlogModelView.qrc b/test/qxBlogModelView/qt/rcc/qxBlogModelView.qrc new file mode 100644 index 0000000..43b3c12 --- /dev/null +++ b/test/qxBlogModelView/qt/rcc/qxBlogModelView.qrc @@ -0,0 +1,9 @@ + + + documents/main.qml + documents/main_qt4.qml + documents/main_qt6.qml + documents/main_relationship.qml + documents/main_relationship_qt6.qml + + diff --git a/test/qxBlogModelView/qxBlog.pro b/test/qxBlogModelView/qxBlog.pro new file mode 100644 index 0000000..12d02ae --- /dev/null +++ b/test/qxBlogModelView/qxBlog.pro @@ -0,0 +1,53 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" +QT += gui + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +greaterThan(QT_MAJOR_VERSION, 4) { +QT += widgets +QT += quick +QT += qml +} else { +QT += declarative +} + +CONFIG(debug, debug|release) { +TARGET = qxBlogModelViewd +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogModelView +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +HEADERS += ./include/model_view_from_qxee/author.model_view.gen.h +HEADERS += ./include/model_view_from_qxee/blog.model_view.gen.h +HEADERS += ./include/model_view_from_qxee/category.model_view.gen.h +HEADERS += ./include/model_view_from_qxee/comment.model_view.gen.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp + +SOURCES += ./src/model_view_from_qxee/author.model_view.gen.cpp +SOURCES += ./src/model_view_from_qxee/blog.model_view.gen.cpp +SOURCES += ./src/model_view_from_qxee/category.model_view.gen.cpp +SOURCES += ./src/model_view_from_qxee/comment.model_view.gen.cpp + +RESOURCES += ./qt/rcc/qxBlogModelView.qrc diff --git a/test/qxBlogModelView/release/.gitignore b/test/qxBlogModelView/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogModelView/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogModelView/src/author.cpp b/test/qxBlogModelView/src/author.cpp new file mode 100644 index 0000000..f76c8e1 --- /dev/null +++ b/test/qxBlogModelView/src/author.cpp @@ -0,0 +1,52 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, "author_id"); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate"); + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, "list_blog", "author_id"); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} + +QString author::getauthor_id() const { return m_id; } + +QString author::getname() const { return m_name; } + +QDate author::getbirthdate() const { return m_birthdate; } + +author::enum_sex author::getsex() const { return m_sex; } + +author::type_list_of_blog author::getlist_of_blog() const { return m_blogX; } + +author::type_list_of_blog & author::list_of_blog() { return m_blogX; } + +const author::type_list_of_blog & author::list_of_blog() const { return m_blogX; } + +void author::setauthor_id(const QString & val) { m_id = val; } + +void author::setname(const QString & val) { m_name = val; } + +void author::setbirthdate(const QDate & val) { m_birthdate = val; } + +void author::setsex(const author::enum_sex & val) { m_sex = val; } + +void author::setlist_of_blog(const author::type_list_of_blog & val) { m_blogX = val; } diff --git a/test/qxBlogModelView/src/blog.cpp b/test/qxBlogModelView/src/blog.cpp new file mode 100644 index 0000000..d6251b8 --- /dev/null +++ b/test/qxBlogModelView/src/blog.cpp @@ -0,0 +1,53 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, "blog_id"); + + t.data(& blog::m_title, "blog_title"); + t.data(& blog::m_text, "blog_text"); + t.data(& blog::m_dt_creation, "date_creation"); + + t.relationManyToOne(& blog::m_author, "author_id"); + t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); + t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", "blog_id", "category_id"); +}} + +long blog::getblog_id() const { return m_id; } + +QString blog::gettitle() const { return m_title; } + +QString blog::gettext() const { return m_text; } + +blog::type_author blog::getauthor() const { return m_author; } + +blog::type_list_of_comment blog::getlist_of_comment() const { return m_commentX; } + +blog::type_list_of_comment & blog::list_of_comment() { return m_commentX; } + +const blog::type_list_of_comment & blog::list_of_comment() const { return m_commentX; } + +blog::type_list_of_category blog::getlist_of_category() const { return m_categoryX; } + +blog::type_list_of_category & blog::list_of_category() { return m_categoryX; } + +const blog::type_list_of_category & blog::list_of_category() const { return m_categoryX; } + +void blog::setblog_id(const long & val) { m_id = val; } + +void blog::settitle(const QString & val) { m_title = val; } + +void blog::settext(const QString & val) { m_text = val; } + +void blog::setauthor(const blog::type_author & val) { m_author = val; } + +void blog::setlist_of_comment(const blog::type_list_of_comment & val) { m_commentX = val; } + +void blog::setlist_of_category(const blog::type_list_of_category & val) { m_categoryX = val; } diff --git a/test/qxBlogModelView/src/category.cpp b/test/qxBlogModelView/src/category.cpp new file mode 100644 index 0000000..e2e6a2c --- /dev/null +++ b/test/qxBlogModelView/src/category.cpp @@ -0,0 +1,39 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, "category_id"); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id"); +}} + +long category::getcategory_id() const { return m_id; } + +QString category::getname() const { return m_name; } + +QString category::getdescription() const { return m_desc; } + +category::type_list_of_blog category::getlist_of_blog() const { return m_blogX; } + +category::type_list_of_blog & category::list_of_blog() { return m_blogX; } + +const category::type_list_of_blog & category::list_of_blog() const { return m_blogX; } + +void category::setcategory_id(const long & val) { m_id = val; } + +void category::setname(const QString & val) { m_name = val; } + +void category::setdescription(const QString & val) { m_desc = val; } + +void category::setlist_of_blog(const category::type_list_of_blog & val) { m_blogX = val; } diff --git a/test/qxBlogModelView/src/comment.cpp b/test/qxBlogModelView/src/comment.cpp new file mode 100644 index 0000000..3c18843 --- /dev/null +++ b/test/qxBlogModelView/src/comment.cpp @@ -0,0 +1,36 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, "comment_id"); + + t.data(& comment::m_title, "comment_title"); + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, "blog_id"); +}} + +long comment::getcomment_id() const { return m_id; } + +QString comment::gettitle() const { return m_title; } + +QString comment::gettext() const { return m_text; } + +comment::type_blog_id comment::getblog_id() const { return m_blog; } + +void comment::setcomment_id(const long & val) { m_id = val; } + +void comment::settitle(const QString & val) { m_title = val; } + +void comment::settext(const QString & val) { m_text = val; } + +void comment::setblog_id(const comment::type_blog_id & val) { m_blog = val; } diff --git a/test/qxBlogModelView/src/main.cpp b/test/qxBlogModelView/src/main.cpp new file mode 100644 index 0000000..3052c32 --- /dev/null +++ b/test/qxBlogModelView/src/main.cpp @@ -0,0 +1,325 @@ +#include "../include/precompiled.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#include +#include +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#include +#include +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include "../include/model_view_from_qxee/blog.model_view.gen.h" + +#include + +void init_data(); +void test_qt_widget(); +void test_qml_view(); +void test_qml_view_with_relationship(); + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); + init_data(); + test_qt_widget(); + test_qml_view(); + test_qml_view_with_relationship(); + return 0; +} + +void init_data() +{ + QFile::remove("./qxBlog.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->m_id = "author_id_1"; author_1->m_name = "author_1"; + author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate(); + author_2->m_id = "author_id_2"; author_2->m_name = "author_2"; + author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate(); + author_3->m_id = "author_id_3"; author_3->m_name = "author_3"; + author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate(); + + list_author authorX; + authorX.insert(author_1->m_id, author_1); + authorX.insert(author_2->m_id, author_2); + authorX.insert(author_3->m_id, author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone(* author_2); + qAssert(author_clone->m_id == "author_id_2"); + qAssert(author_clone->m_sex == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->m_id != 0); + qAssert(category_2->m_id != 0); + qAssert(category_3->m_id != 0); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(qx::dao::count() == 2); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->m_categoryX.insert(category_1->m_id, category_1); + blog_1->m_categoryX.insert(category_3->m_id, category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp); + + // Check qx::dao::save_with_relation_recursive() function + daoError = qx::dao::save_with_relation_recursive(blog_tmp); + qAssert(! daoError.isValid()); + daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only); + qAssert(! daoError.isValid()); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // 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].get() != NULL)) + { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); } + qx::dump(lst_blog_with_only_date_creation); + + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + // Call a custom SQL query or a stored procedure + qx_query testStoredProc("SELECT * FROM author"); + daoError = qx::dao::call_query(testStoredProc); + qAssert(! daoError.isValid()); + testStoredProc.dumpSqlResult(); + + // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items) + qx_query testStoredProcBis("SELECT * FROM author"); + authorX.clear(); + daoError = qx::dao::execute_query(testStoredProcBis, authorX); + qAssert(! daoError.isValid()); qAssert(authorX.count() > 0); + qx::dump(authorX); + + // Call a custom SQL query or a stored procedure and fetch automatically properties + qx_query testStoredProcThird("SELECT name, category_id FROM category"); + category_ptr category_tmp = category_ptr(new category()); + daoError = qx::dao::execute_query(testStoredProcThird, category_tmp); + qAssert(! daoError.isValid()); qAssert(category_tmp->m_id != 0); + qx::dump(category_tmp); + + // Just to test compilation of nested models + qx::IxModel * pNestedModel1 = qx::model_view::create_nested_model(NULL, QModelIndex(), category_tmp); Q_UNUSED(pNestedModel1); + qx::IxModel * pNestedModel2 = qx::model_view::create_nested_model(NULL, QModelIndex(), authorX); Q_UNUSED(pNestedModel2); +} + +void test_qt_widget() +{ + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + + QTableView tableView; + tableView.setModel(pModel); + tableView.setSortingEnabled(true); + tableView.show(); + qApp->exec(); +} + +void test_qml_view() +{ + qx::IxModel * pModel = new qx::QxModel(); + pModel->qxFetchAll(); + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QQuickView qmlView; + QString sQmlFile = "qrc:/documents/main_qt6.qml"; +#elif (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QQuickView qmlView; + QString sQmlFile = "qrc:/documents/main.qml"; +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QDeclarativeView qmlView; + QString sQmlFile = "qrc:/documents/main_qt4.qml"; +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + + qmlView.rootContext()->setContextProperty("myModel", pModel); + qmlView.setSource(QUrl(sQmlFile)); + qmlView.show(); + qApp->exec(); +} + +void test_qml_view_with_relationship() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + qx::IxModel * pModel = new model_view::blog_model(); + pModel->qxFetchAll(QStringList() << "*"); + + QQuickView qmlView; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/main_relationship_qt6.qml"; +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/main_relationship.qml"; +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + + qmlView.rootContext()->setContextProperty("myModel", pModel); + qmlView.setSource(QUrl(sQmlFile)); + qmlView.show(); + qApp->exec(); +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +} diff --git a/test/qxBlogModelView/src/model_view_from_qxee/author.model_view.gen.cpp b/test/qxBlogModelView/src/model_view_from_qxee/author.model_view.gen.cpp new file mode 100644 index 0000000..09b42c8 --- /dev/null +++ b/test/qxBlogModelView/src/model_view_from_qxee/author.model_view.gen.cpp @@ -0,0 +1,75 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#include "../../include/precompiled.h" + +#include "../../include/model_view_from_qxee/author.model_view.gen.h" +#include "../../include/model_view_from_qxee/blog.model_view.gen.h" + +#include + +namespace model_view { + +author_model::author_model(QObject * parent /* = 0 */) : author_model_base_class(parent) { ; } + +author_model::author_model(qx::IxModel * other, QObject * parent) : author_model_base_class(other, parent) { ; } + +author_model::~author_model() { ; } + +QObject * author_model::list_of_blog(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "list_blog"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + author_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + QString id = ptr->getauthor_id(); + author::type_list_of_blog value = ptr->getlist_of_blog(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + author tmp; + tmp.setauthor_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getlist_of_blog(); + ptr->setlist_of_blog(value); + } + + model_view::blog_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "list_blog", pChild); } + return static_cast(pChild); +} + +void author_model::syncNestedModel(int row, const QStringList & relation) +{ + Q_UNUSED(relation); + qx::IxModel * pNestedModel = NULL; + if ((row < 0) || (row >= this->m_model.count())) { return; } + author_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { return; } + + pNestedModel = this->getChild(row, "list_blog"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + author::type_list_of_blog value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setlist_of_blog(value); + } +} + +void author_model::syncAllNestedModel(const QStringList & relation) +{ + if (this->m_lstChild.count() <= 0) { return; } + for (long l = 0; l < this->m_model.count(); l++) + { this->syncNestedModel(static_cast(l), relation); } +} + +} // namespace model_view diff --git a/test/qxBlogModelView/src/model_view_from_qxee/blog.model_view.gen.cpp b/test/qxBlogModelView/src/model_view_from_qxee/blog.model_view.gen.cpp new file mode 100644 index 0000000..314bbf2 --- /dev/null +++ b/test/qxBlogModelView/src/model_view_from_qxee/blog.model_view.gen.cpp @@ -0,0 +1,155 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#include "../../include/precompiled.h" + +#include "../../include/model_view_from_qxee/blog.model_view.gen.h" +#include "../../include/model_view_from_qxee/author.model_view.gen.h" +#include "../../include/model_view_from_qxee/comment.model_view.gen.h" +#include "../../include/model_view_from_qxee/category.model_view.gen.h" + +#include + +namespace model_view { + +blog_model::blog_model(QObject * parent /* = 0 */) : blog_model_base_class(parent) { ; } + +blog_model::blog_model(qx::IxModel * other, QObject * parent) : blog_model_base_class(other, parent) { ; } + +blog_model::~blog_model() { ; } + +QObject * blog_model::author_id(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "author_id"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + long id = ptr->getblog_id(); + blog::type_author value = ptr->getauthor(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + blog tmp; + tmp.setblog_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getauthor(); + ptr->setauthor(value); + } + + model_view::author_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "author_id", pChild); } + return static_cast(pChild); +} + +QObject * blog_model::list_of_comment(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "list_comment"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + long id = ptr->getblog_id(); + blog::type_list_of_comment value = ptr->getlist_of_comment(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + blog tmp; + tmp.setblog_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getlist_of_comment(); + ptr->setlist_of_comment(value); + } + + model_view::comment_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "list_comment", pChild); } + return static_cast(pChild); +} + +QObject * blog_model::list_of_category(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "list_category"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + long id = ptr->getblog_id(); + blog::type_list_of_category value = ptr->getlist_of_category(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + blog tmp; + tmp.setblog_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getlist_of_category(); + ptr->setlist_of_category(value); + } + + model_view::category_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "list_category", pChild); } + return static_cast(pChild); +} + +void blog_model::syncNestedModel(int row, const QStringList & relation) +{ + Q_UNUSED(relation); + qx::IxModel * pNestedModel = NULL; + if ((row < 0) || (row >= this->m_model.count())) { return; } + blog_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { return; } + + pNestedModel = this->getChild(row, "author_id"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + blog::type_author value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setauthor(value); + } + + pNestedModel = this->getChild(row, "list_comment"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + blog::type_list_of_comment value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setlist_of_comment(value); + } + + pNestedModel = this->getChild(row, "list_category"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + blog::type_list_of_category value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setlist_of_category(value); + } +} + +void blog_model::syncAllNestedModel(const QStringList & relation) +{ + if (this->m_lstChild.count() <= 0) { return; } + for (long l = 0; l < this->m_model.count(); l++) + { this->syncNestedModel(static_cast(l), relation); } +} + +} // namespace model_view diff --git a/test/qxBlogModelView/src/model_view_from_qxee/category.model_view.gen.cpp b/test/qxBlogModelView/src/model_view_from_qxee/category.model_view.gen.cpp new file mode 100644 index 0000000..bab816a --- /dev/null +++ b/test/qxBlogModelView/src/model_view_from_qxee/category.model_view.gen.cpp @@ -0,0 +1,75 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#include "../../include/precompiled.h" + +#include "../../include/model_view_from_qxee/category.model_view.gen.h" +#include "../../include/model_view_from_qxee/blog.model_view.gen.h" + +#include + +namespace model_view { + +category_model::category_model(QObject * parent /* = 0 */) : category_model_base_class(parent) { ; } + +category_model::category_model(qx::IxModel * other, QObject * parent) : category_model_base_class(other, parent) { ; } + +category_model::~category_model() { ; } + +QObject * category_model::list_of_blog(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "list_blog"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + category_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + long id = ptr->getcategory_id(); + category::type_list_of_blog value = ptr->getlist_of_blog(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + category tmp; + tmp.setcategory_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getlist_of_blog(); + ptr->setlist_of_blog(value); + } + + model_view::blog_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "list_blog", pChild); } + return static_cast(pChild); +} + +void category_model::syncNestedModel(int row, const QStringList & relation) +{ + Q_UNUSED(relation); + qx::IxModel * pNestedModel = NULL; + if ((row < 0) || (row >= this->m_model.count())) { return; } + category_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { return; } + + pNestedModel = this->getChild(row, "list_blog"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + category::type_list_of_blog value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setlist_of_blog(value); + } +} + +void category_model::syncAllNestedModel(const QStringList & relation) +{ + if (this->m_lstChild.count() <= 0) { return; } + for (long l = 0; l < this->m_model.count(); l++) + { this->syncNestedModel(static_cast(l), relation); } +} + +} // namespace model_view diff --git a/test/qxBlogModelView/src/model_view_from_qxee/comment.model_view.gen.cpp b/test/qxBlogModelView/src/model_view_from_qxee/comment.model_view.gen.cpp new file mode 100644 index 0000000..941ae44 --- /dev/null +++ b/test/qxBlogModelView/src/model_view_from_qxee/comment.model_view.gen.cpp @@ -0,0 +1,75 @@ +/************************************************************************************************ +** File created by QxEntityEditor 1.1.9 (2016/05/04 10:05) : please, do NOT modify this file ! ** +************************************************************************************************/ + +#include "../../include/precompiled.h" + +#include "../../include/model_view_from_qxee/comment.model_view.gen.h" +#include "../../include/model_view_from_qxee/blog.model_view.gen.h" + +#include + +namespace model_view { + +comment_model::comment_model(QObject * parent /* = 0 */) : comment_model_base_class(parent) { ; } + +comment_model::comment_model(qx::IxModel * other, QObject * parent) : comment_model_base_class(other, parent) { ; } + +comment_model::~comment_model() { ; } + +QObject * comment_model::blog_id(int row, bool bLoadFromDatabase /* = false */, const QString & sAppendRelations /* = QString() */) +{ + QString sRelation = "blog_id"; + qx::IxModel * pChild = (bLoadFromDatabase ? NULL : this->getChild(row, sRelation)); + if (pChild) { return static_cast(pChild); } + + if ((row < 0) || (row >= this->m_model.count())) { qAssert(false); return NULL; } + comment_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { qAssert(false); return NULL; } + long id = ptr->getcomment_id(); + comment::type_blog_id value = ptr->getblog_id(); + + if (bLoadFromDatabase) + { + if (! sAppendRelations.isEmpty() && ! sAppendRelations.startsWith("->") && ! sAppendRelations.startsWith(">>")) { sRelation += "->" + sAppendRelations; } + else if (! sAppendRelations.isEmpty()) { sRelation += sAppendRelations; } + comment tmp; + tmp.setcomment_id(id); + this->m_lastError = qx::dao::fetch_by_id_with_relation(sRelation, tmp); + if (this->m_lastError.isValid()) { return NULL; } + value = tmp.getblog_id(); + ptr->setblog_id(value); + } + + model_view::blog_model * pNewChild = NULL; + pChild = qx::model_view::create_nested_model_with_type(this, QModelIndex(), value, pNewChild); + if (pChild) { this->insertChild(row, "blog_id", pChild); } + return static_cast(pChild); +} + +void comment_model::syncNestedModel(int row, const QStringList & relation) +{ + Q_UNUSED(relation); + qx::IxModel * pNestedModel = NULL; + if ((row < 0) || (row >= this->m_model.count())) { return; } + comment_model_base_class::type_ptr ptr = this->m_model.getByIndex(row); + if (! ptr) { return; } + + pNestedModel = this->getChild(row, "blog_id"); + if (pNestedModel) + { + this->syncNestedModelRecursive(pNestedModel, relation); + comment::type_blog_id value; + qx::model_view::sync_nested_model(pNestedModel, value); + ptr->setblog_id(value); + } +} + +void comment_model::syncAllNestedModel(const QStringList & relation) +{ + if (this->m_lstChild.count() <= 0) { return; } + for (long l = 0; l < this->m_model.count(); l++) + { this->syncNestedModel(static_cast(l), relation); } +} + +} // namespace model_view diff --git a/test/qxBlogMongoDB/CMakeLists.txt b/test/qxBlogMongoDB/CMakeLists.txt new file mode 100644 index 0000000..e963565 --- /dev/null +++ b/test/qxBlogMongoDB/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogMongoDB LANGUAGES CXX) + +include(../../QxOrm.cmake) + +if(_QX_ENABLE_MONGODB) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ./include/TestQtProperty.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/TestQtProperty.cpp + ./src/main.cpp + ) + +add_executable(qxBlogMongoDB ${SRCS} ${HEADERS}) + +target_compile_definitions(qxBlogMongoDB PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogMongoDB PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogMongoDB ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxBlogMongoDB PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogMongoDB PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +else() # _QX_ENABLE_MONGODB + +message(STATUS "qxBlogMongoDB project not loaded because _QX_ENABLE_MONGODB option not enabled (QxOrm MongoDB database driver is not available)") + +endif() # _QX_ENABLE_MONGODB diff --git a/test/qxBlogMongoDB/debug/.gitignore b/test/qxBlogMongoDB/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogMongoDB/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogMongoDB/include/TestQtProperty.h b/test/qxBlogMongoDB/include/TestQtProperty.h new file mode 100644 index 0000000..b1a5239 --- /dev/null +++ b/test/qxBlogMongoDB/include/TestQtProperty.h @@ -0,0 +1,55 @@ +#ifndef _QX_TEST_QT_META_PROPERTY_H_ +#define _QX_TEST_QT_META_PROPERTY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +class QX_BLOG_DLL_EXPORT TestQtProperty : public QObject, public qx::IxPersistable +{ + + Q_OBJECT + QX_PERSISTABLE_HPP(TestQtProperty) + Q_PROPERTY(QString id READ id WRITE setId) + Q_PROPERTY(long number READ number WRITE setNumber) + Q_PROPERTY(QString desc READ desc WRITE setDesc) + Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate) + Q_PROPERTY(QVariant photo READ photo WRITE setPhoto) + +protected: + + QString m_id; + long m_number; + QString m_desc; + QDateTime m_birthDate; + QVariant m_photo; + +public: + + TestQtProperty() : QObject(), m_number(0) { ; } + virtual ~TestQtProperty() { ; } + + QString id() const { return m_id; } + long number() const { return m_number; } + QString desc() const { return m_desc; } + QDateTime birthDate() const { return m_birthDate; } + QVariant photo() const { return m_photo; } + + void setId(const QString & id) { m_id = id; } + void setNumber(long l) { m_number = l; } + void setDesc(const QString & s) { m_desc = s; } + void setBirthDate(const QDateTime & dt) { m_birthDate = dt; } + void setPhoto(const QVariant & v) { m_photo = v; } + +}; + +QX_REGISTER_PRIMARY_KEY(TestQtProperty, QString) +QX_REGISTER_HPP_QX_BLOG(TestQtProperty, QObject, 0) + +#endif // _QX_TEST_QT_META_PROPERTY_H_ diff --git a/test/qxBlogMongoDB/include/author.h b/test/qxBlogMongoDB/include/author.h new file mode 100644 index 0000000..71aca1a --- /dev/null +++ b/test/qxBlogMongoDB/include/author.h @@ -0,0 +1,33 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; +// -- enum + enum enum_sex { male, female, unknown }; +// -- properties + QString m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; +// -- contructor, virtual destructor + author() : m_sex(unknown) { ; } + virtual ~author() { ; } +// -- methods + int age() const; +}; + +QX_REGISTER_PRIMARY_KEY(author, QString) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogMongoDB/include/blog.h b/test/qxBlogMongoDB/include/blog.h new file mode 100644 index 0000000..5327a68 --- /dev/null +++ b/test/qxBlogMongoDB/include/blog.h @@ -0,0 +1,29 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog +{ +public: +// -- properties + QString m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; +// -- contructor, virtual destructor + blog() { ; } + virtual ~blog() { ; } +}; + +QX_REGISTER_PRIMARY_KEY(blog, QString) +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogMongoDB/include/category.h b/test/qxBlogMongoDB/include/category.h new file mode 100644 index 0000000..33362c9 --- /dev/null +++ b/test/qxBlogMongoDB/include/category.h @@ -0,0 +1,28 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; +// -- properties + QString m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; +// -- contructor, virtual destructor + category() { ; } + virtual ~category() { ; } +}; + +QX_REGISTER_PRIMARY_KEY(category, QString) +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogMongoDB/include/comment.h b/test/qxBlogMongoDB/include/comment.h new file mode 100644 index 0000000..78d65d5 --- /dev/null +++ b/test/qxBlogMongoDB/include/comment.h @@ -0,0 +1,27 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ +public: +// -- typedef + typedef std::shared_ptr blog_ptr; +// -- properties + QString m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; +// -- contructor, virtual destructor + comment() { ; } + virtual ~comment() { ; } +}; + +QX_REGISTER_PRIMARY_KEY(comment, QString) +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogMongoDB/include/export.h b/test/qxBlogMongoDB/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogMongoDB/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogMongoDB/include/precompiled.h b/test/qxBlogMongoDB/include/precompiled.h new file mode 100644 index 0000000..0d8b994 --- /dev/null +++ b/test/qxBlogMongoDB/include/precompiled.h @@ -0,0 +1,8 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogMongoDB/qt/moc/.gitignore b/test/qxBlogMongoDB/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogMongoDB/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogMongoDB/qxBlog.pro b/test/qxBlogMongoDB/qxBlog.pro new file mode 100644 index 0000000..8ec72c9 --- /dev/null +++ b/test/qxBlogMongoDB/qxBlog.pro @@ -0,0 +1,40 @@ +include(../../QxOrm.pri) + +!contains(DEFINES, _QX_ENABLE_MONGODB) { +error(unable to use QxOrm MongoDB database driver : please define _QX_ENABLE_MONGODB compilation option in QxOrm.pri configuration file) +} # !contains(DEFINES, _QX_ENABLE_MONGODB) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogMongoDBd +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogMongoDB +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h +HEADERS += ./include/TestQtProperty.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/TestQtProperty.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxBlogMongoDB/release/.gitignore b/test/qxBlogMongoDB/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogMongoDB/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogMongoDB/src/TestQtProperty.cpp b/test/qxBlogMongoDB/src/TestQtProperty.cpp new file mode 100644 index 0000000..6f9866d --- /dev/null +++ b/test/qxBlogMongoDB/src/TestQtProperty.cpp @@ -0,0 +1,25 @@ +#include "../include/precompiled.h" + +#include "../include/TestQtProperty.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(TestQtProperty) +QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id") +QX_PERSISTABLE_CPP(TestQtProperty) + +/* + Instead of using 'QX_REGISTER_ALL_QT_PROPERTIES(...)' macro, it's also + possible to write classic 'void qx::register_class(...)' function, like this : + + namespace qx { + template <> void register_class(QxClass & t) + { qx::register_all_qt_properties(t, "my_id"); } + } // namespace qx + + So, you can mix Qt meta-properties and classic registration data-member. + All is stored using the same interface : 'qx::IxDataMember *'. + To more details about advantages and disadvantages of using Qt meta-property, + go to the FAQ of QxOrm library : + - How to register automatically Qt meta-properties to QxOrm context ? +*/ diff --git a/test/qxBlogMongoDB/src/author.cpp b/test/qxBlogMongoDB/src/author.cpp new file mode 100644 index 0000000..e0813a2 --- /dev/null +++ b/test/qxBlogMongoDB/src/author.cpp @@ -0,0 +1,28 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, "author_id"); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate")->setIsIndex(true); // Index created automatically with qx::dao::mongodb::QxMongoDB_Helper::autoCreateIndexes() function + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, "list_blog", "author_id"); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} diff --git a/test/qxBlogMongoDB/src/blog.cpp b/test/qxBlogMongoDB/src/blog.cpp new file mode 100644 index 0000000..7322f40 --- /dev/null +++ b/test/qxBlogMongoDB/src/blog.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, "blog_id"); + + t.data(& blog::m_text, "blog_text"); + t.data(& blog::m_dt_creation, "date_creation"); + t.data(& blog::m_categoryX, "list_category"); + + t.relationManyToOne(& blog::m_author, "author_id"); + t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); +}} diff --git a/test/qxBlogMongoDB/src/category.cpp b/test/qxBlogMongoDB/src/category.cpp new file mode 100644 index 0000000..723fda5 --- /dev/null +++ b/test/qxBlogMongoDB/src/category.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, "category_id"); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id"); +}} diff --git a/test/qxBlogMongoDB/src/comment.cpp b/test/qxBlogMongoDB/src/comment.cpp new file mode 100644 index 0000000..d2d5cd5 --- /dev/null +++ b/test/qxBlogMongoDB/src/comment.cpp @@ -0,0 +1,19 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, "comment_id"); + + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, "blog_id"); +}} diff --git a/test/qxBlogMongoDB/src/main.cpp b/test/qxBlogMongoDB/src/main.cpp new file mode 100644 index 0000000..9e6e8eb --- /dev/null +++ b/test/qxBlogMongoDB/src/main.cpp @@ -0,0 +1,480 @@ +#include "../include/precompiled.h" + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" +#include "../include/TestQtProperty.h" + +#include + +void basicCRUDOnAuthor(bool withDelete); +void basicCRUDOnCategory(); +void basicCRUDOnBlog(); +void complexQueriesOnBlog(); +void miscellaneousOperations(); +void testQtProperty(); + +int main(int argc, char * argv[]) +{ + // Qt application + QCoreApplication app(argc, argv); + + // Following command is recommanded to initialize QxOrm introspection engine + qx::QxClassX::registerAllClasses(); + + // Parameters to connect to MongoDB database + qx::QxSqlDatabase * pDatabase = qx::QxSqlDatabase::getSingleton(); + pDatabase->setDriverName("QXMONGODB"); + pDatabase->setDatabaseName("qxBlog"); + pDatabase->setHostName("localhost"); + pDatabase->setPort(27017); + pDatabase->setUserName(""); + pDatabase->setPassword(""); + + // For debug purpose : log all replies from MongoDB database + qx::dao::mongodb::QxMongoDB_Helper::setLogDatabaseReply(true); + + // Clear previous sample database + qx_query dropDB("{ \"dropDatabase\" : 1 }"); + QSqlError daoError = qx::dao::call_query(dropDB); qAssert(! daoError.isValid()); + + // To optimize queries : create automatically indexes based on relationships and properties marked as 'index' + daoError = qx::dao::mongodb::QxMongoDB_Helper::autoCreateIndexes(true); qAssert(! daoError.isValid()); + + // Basic CRUD operations + basicCRUDOnAuthor(true); + basicCRUDOnAuthor(false); + + // Populate category collection + basicCRUDOnCategory(); + + // Populate blog collection + basicCRUDOnBlog(); + + // Process some complex queries on blog collection (with relationships) + complexQueriesOnBlog(); + + // Process some others operations on database + miscellaneousOperations(); + + // Test Qt properties registered via QX_REGISTER_ALL_QT_PROPERTIES() macro (https://www.qxorm.com/qxorm_en/manual.html#manual_520) + testQtProperty(); + + return 0; +} + +void basicCRUDOnAuthor(bool withDelete) +{ + // Test delete all author + QSqlError daoError = qx::dao::delete_all(); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 0); + + // Test insert one without id + author_ptr author_1 = std::make_shared(); + author_1->m_name = "author_1"; + author_1->m_sex = author::male; + author_1->m_birthdate = QDate(1998, 07, 12); + daoError = qx::dao::insert(author_1); qAssert(! daoError.isValid()); + qAssert(! author_1->m_id.isEmpty()); + qAssert(qx::dao::count() == 1); + + // Test insert one author with a custom id + author_ptr author_2 = std::make_shared(); + author_2->m_id = "my_custom_id_author_2"; + author_2->m_name = "author_2"; + author_2->m_sex = author::female; + author_2->m_birthdate = QDate(2003, 02, 28); + daoError = qx::dao::insert(author_2); qAssert(! daoError.isValid()); + qAssert(author_2->m_id == "my_custom_id_author_2"); + qAssert(qx::dao::count() == 2); + + // Test insert many author with/without ids + QList authorX; + author author_3; author_3.m_name = "author_3"; author_3.m_sex = author::female; author_3.m_birthdate = QDate(1968, 05, 01); authorX.append(author_3); + author author_4; author_4.m_id = "my_custom_id_author_4"; author_4.m_name = "author_4"; author_4.m_sex = author::male; author_4.m_birthdate = QDate(1980, 12, 19); authorX.append(author_4); + author author_5; author_5.m_name = "author_5"; author_5.m_sex = author::female; author_5.m_birthdate = QDate(1978, 03, 03); authorX.append(author_5); + daoError = qx::dao::insert(authorX); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 5); + qAssert(authorX.at(1).m_id == "my_custom_id_author_4"); + QString author_3_id = authorX.at(0).m_id; qAssert(! author_3_id.isEmpty()); + QString author_5_id = authorX.at(2).m_id; qAssert(! author_5_id.isEmpty()); + + // Test update one author + author_3 = authorX.at(0); + author_3.m_name = "author_3_modified"; + daoError = qx::dao::update(author_3); qAssert(! daoError.isValid()); + + // Test update many author + authorX.clear(); + author_3.m_name = "author_3_modified_twice"; authorX.append(author_3); + author_2->m_name = "author_2_modified"; authorX.append(* author_2); + author_1->m_name = "author_1_modified"; authorX.append(* author_1); + daoError = qx::dao::update(authorX); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 5); + + // Test fetch all author (inside QList) + authorX.clear(); + daoError = qx::dao::fetch_all(authorX); qAssert(! daoError.isValid()); + qAssert(authorX.count() == 5); + qx::dump(authorX); + + // Test fetch all author (inside QHash by id) + QHash authorXById; + daoError = qx::dao::fetch_all(authorXById); qAssert(! daoError.isValid()); + qAssert(authorXById.count() == 5); + qx::dump(authorXById); + + // Test fetch author by query (only female) + list_author list_of_female_author; + qx_query query("{ \"sex\" : " + QString::number(static_cast(author::female)) + " }"); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); qAssert(! daoError.isValid()); + qAssert(list_of_female_author.count() == 3); + qx::dump(list_of_female_author); + + // Test fetch by query using MongoDB aggregation framework (only female) + list_author list_of_female_author_other; + qx_query queryAggregate("aggregate", "[ { \"$match\" : { \"sex\" : " + QString::number(static_cast(author::female)) + " } } ]"); + daoError = qx::dao::fetch_by_query(queryAggregate, list_of_female_author_other); qAssert(! daoError.isValid()); + qAssert(list_of_female_author_other.count() == 3); + qx::dump(list_of_female_author_other); + + // Test fetch by query (only female) adding 'sort', 'limit', 'skip', etc... commands (see second query QStringList parameter) + list_of_female_author_other.clear(); + qx_query queryOpts(QStringList() << "{ \"sex\" : " + QString::number(static_cast(author::female)) + " }" + << "{ \"sort\" : { \"sex\" : -1 }, \"limit\" : 2 }"); + daoError = qx::dao::fetch_by_query(queryOpts, list_of_female_author_other); qAssert(! daoError.isValid()); + qAssert(list_of_female_author_other.count() == 2); + qx::dump(list_of_female_author_other); + + // Test update one author after fetch + author_5 = authorX.at(4); + author_5.m_name = "author_5_modified_after_fetch"; + daoError = qx::dao::update(author_5); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 5); + + // Test update many author after fetch + author_ptr pAuthor = list_of_female_author.getByIndex(0); + pAuthor->m_name = pAuthor->m_name + "_female_modified_after_fetch"; + pAuthor = list_of_female_author.getByIndex(1); + pAuthor->m_name = pAuthor->m_name + "_female_modified_after_fetch"; + pAuthor = list_of_female_author.getByIndex(2); + pAuthor->m_name = pAuthor->m_name + "_female_modified_after_fetch"; + daoError = qx::dao::update(list_of_female_author); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 5); + + // Test fetch one author by id + pAuthor.reset(new author()); + pAuthor->m_id = "my_custom_id_author_2"; + daoError = qx::dao::fetch_by_id(pAuthor); qAssert(! daoError.isValid()); + qAssert(pAuthor->m_id == "my_custom_id_author_2"); + qAssert(! pAuthor->m_birthdate.isNull()); + + // Test fetch many author by id + authorX.clear(); + QHashIterator itr(authorXById); + while (itr.hasNext()) { itr.next(); author author_tmp; author_tmp.m_id = itr.key(); authorX.append(author_tmp); } + daoError = qx::dao::fetch_by_id(authorX); qAssert(! daoError.isValid()); + qAssert(authorX.count() == 5); + qAssert(! authorX.at(2).m_birthdate.isNull()); + qx::dump(authorX); + + if (! withDelete) { return; } + + // Test delete one author by id + pAuthor.reset(new author()); + pAuthor->m_id = "my_custom_id_author_4"; + daoError = qx::dao::delete_by_id(pAuthor); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 4); + + // Test delete many author by id + authorX.clear(); + { author author_tmp; author_tmp.m_id = author_3_id; authorX.append(author_tmp); } + { author author_tmp; author_tmp.m_id = author_5_id; authorX.append(author_tmp); } + daoError = qx::dao::delete_by_id(authorX); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 2); + + // Test delete author by query (all male) +#ifdef Q_COMPILER_INITIALIZER_LISTS + int iMale = static_cast(author::male); + query = qx_query{ { "sex", iMale } }; +#else // Q_COMPILER_INITIALIZER_LISTS + query = qx_query("{ \"sex\" : " + QString::number(static_cast(author::male)) + " }"); +#endif // Q_COMPILER_INITIALIZER_LISTS + daoError = qx::dao::delete_by_query(query); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 1); + + // Now delete all author + daoError = qx::dao::delete_all(); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 0); +} + +void basicCRUDOnCategory() +{ + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + // Insert 3 categories into database, use 'db' parameter for the transaction + QSqlError daoError = qx::dao::insert(category_1); qAssert(! daoError.isValid()); + daoError = qx::dao::insert(category_2); qAssert(! daoError.isValid()); + daoError = qx::dao::insert(category_3); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 3); +} + +void basicCRUDOnBlog() +{ + // Search author_1 + author_ptr author_1 = std::make_shared(); + qx_query query("{ \"name\" : \"author_1_modified\" }"); + QSqlError daoError = qx::dao::fetch_by_query(query, (* author_1)); qAssert(! daoError.isValid()); + qAssert(author_1 && ! author_1->m_id.isEmpty()); + + // Search author_2 + author_ptr author_2 = std::make_shared(); + author_2->m_id = "my_custom_id_author_2"; + daoError = qx::dao::fetch_by_id(author_2); qAssert(! daoError.isValid()); + qAssert(author_2 && ! author_2->m_id.isEmpty()); + + // Create a blog from class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); qAssert(! daoError.isValid()); + daoError = qx::dao::insert(comment_2); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 2); + + // Add 2 categories to 'blog_1' => 'list_category' is not defined as relationship in 'blog' class => so all categories are embedded in 'blog' collection (instead of referenced for relationships) + list_category categories; + daoError = qx::dao::fetch_all(categories); qAssert(! daoError.isValid()); + qAssert(categories.count() == 3); + + category_ptr category_1 = categories.getByIndex(0); + category_ptr category_3 = categories.getByIndex(2); + blog_1->m_categoryX.insert(category_1->m_id, category_1); + blog_1->m_categoryX.insert(category_3->m_id, category_3); + daoError = qx::dao::save(blog_1); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 1); + + // Push a second blog + blog_ptr blog_2 = std::make_shared(); + blog_2->m_text = "blog_text_2"; + daoError = qx::dao::save(blog_2); qAssert(! daoError.isValid()); +} + +void complexQueriesOnBlog() +{ + // Fetch all blogs (without relation) + list_blog allBlogs; + QSqlError daoError = qx::dao::fetch_all(allBlogs); qAssert(! daoError.isValid()); + qx::dump(allBlogs); + qAssert(allBlogs.size() == 2); + + // Fetch blog into a new variable with all relations : 'author', 'comment' and 'category' (MongoDB version 3.6+ is required for relationships) + blog_ptr blog_tmp = std::make_shared(); + blog_tmp->m_id = allBlogs[0]->m_id; + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); qAssert(! daoError.isValid()); + qx::dump(blog_tmp); + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && (blog_tmp->m_author->m_id == "my_custom_id_author_2")); + + // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->m_id = allBlogs[0]->m_id; + daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp); qAssert(! daoError.isValid()); + qx::dump(blog_tmp); + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "my_custom_id_author_2"); + qAssert(blog_tmp->m_author->m_blogX[0]->m_commentX.count() > 0); + + // Fetch blog into a new variable with many relations using "*->*" (2 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->m_id = allBlogs[0]->m_id; + daoError = qx::dao::fetch_all_with_relation("*->*", blog_tmp); qAssert(! daoError.isValid()); + qx::dump(blog_tmp); + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "my_custom_id_author_2"); + qAssert(blog_tmp->m_author->m_blogX[0]->m_commentX.count() == 0); + + // 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].get() != NULL)) + { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); } + qx::dump(lst_blog_with_only_date_creation); + + // Fetch relations defining fields to fetch with syntax { col_1, col_2, etc... } + list_blog lstBlogComplexRelation; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *", lstBlogComplexRelation); qAssert(! daoError.isValid()); + qx::dump(lstBlogComplexRelation); + qAssert(lstBlogComplexRelation.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_dt_creation.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_blog); + + // Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... } + list_blog lstBlogComplexRelation2; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "- { blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *", lstBlogComplexRelation2); qAssert(! daoError.isValid()); + qx::dump(lstBlogComplexRelation2); + qAssert(lstBlogComplexRelation2.size() > 0); + qAssert(lstBlogComplexRelation2[0]->m_text == ""); // Not fetched + qAssert(! lstBlogComplexRelation2[0]->m_dt_creation.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_sex != author::unknown); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_name == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX.size() > 0); + qAssert(! lstBlogComplexRelation2[0]->m_commentX[0]->m_dt_create.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_text == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_blog); + + // Check qx::dao::save_with_relation_recursive() function + daoError = qx::dao::save_with_relation_recursive(blog_tmp); qAssert(! daoError.isValid()); + daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only); qAssert(! daoError.isValid()); + + // Fetch the second blog stored in database + blog_tmp = std::make_shared(); + blog_tmp->m_id = allBlogs[1]->m_id; + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); qAssert(! daoError.isValid()); + qx::dump(blog_tmp); + qAssert(blog_tmp->m_text == "blog_text_2"); + qAssert(blog_tmp->m_author == NULL); + qAssert(blog_tmp->m_categoryX.size() == 0); + qAssert(blog_tmp->m_commentX.size() == 0); + + // Fetch 2 blogs by id with their relationships + QList lstBlogById; + blog_tmp = std::make_shared(); blog_tmp->m_id = allBlogs[1]->m_id; lstBlogById.append(blog_tmp); + blog_tmp = std::make_shared(); blog_tmp->m_id = allBlogs[0]->m_id; lstBlogById.append(blog_tmp); + daoError = qx::dao::fetch_by_id_with_all_relation(lstBlogById); qAssert(! daoError.isValid()); + qx::dump(lstBlogById); +} + +void miscellaneousOperations() +{ + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + // Call 'age()' method with class name and method name (reflexion) + author author_1; qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); qAssert(bInvokeOk); + + // Fetch all blogs (without relation) + list_blog allBlogs; QSqlError daoError = qx::dao::fetch_all(allBlogs); qAssert(! daoError.isValid()); + qx::dump(allBlogs); qAssert(allBlogs.size() == 2); + + // Test 'isDirty()' method + qx::dao::ptr blog_isdirty = qx::dao::ptr(new blog()); + blog_isdirty->m_id = allBlogs[0]->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() == qx::dao::count())); + + 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); + + // Call a custom query and get JSON response as QVariantMap + qx_query customQuery("{ \"find\": \"author\", \"filter\": { } }"); + daoError = qx::dao::call_query(customQuery); qAssert(! daoError.isValid()); + QString responseCustomQuery = customQuery.response().toString(); + QVariantMap responseCustomQueryAsJson; + qx::serialization::json::from_string(responseCustomQueryAsJson, responseCustomQuery); + qx::dump(responseCustomQueryAsJson); + + // Call a custom query with cursor and get JSON response as QList + qx_query customQueryCursor("cursor", "{ \"find\": \"author\", \"filter\": { } }"); + daoError = qx::dao::call_query(customQueryCursor); qAssert(! daoError.isValid()); + QString responseCustomQueryCursor = customQueryCursor.response().toString(); + QList responseCustomQueryCursorAsJson; + qx::serialization::json::from_string(responseCustomQueryCursorAsJson, responseCustomQueryCursor); + qx::dump(responseCustomQueryCursorAsJson); + qAssert(responseCustomQueryCursorAsJson.count() == qx::dao::count()); + + // Test delete by query using MongoDB aggregation framework (delete all female) + qx_query queryAggregate("aggregate", "[ { \"$match\" : { \"sex\" : " + QString::number(static_cast(author::female)) + " } } ]"); + daoError = qx::dao::delete_by_query(queryAggregate); qAssert(! daoError.isValid()); + qAssert(qx::dao::count() == 2); +} + +void testQtProperty() +{ + TestQtProperty tst; + tst.setDesc("tst"); + QSqlError daoError = qx::dao::insert(tst); qAssert(! daoError.isValid()); + tst.setDesc("tst update"); + daoError = qx::dao::update(tst); qAssert(! daoError.isValid()); + daoError = qx::dao::fetch_by_id(tst); qAssert(! daoError.isValid()); + std::shared_ptr lst = qx::IxPersistable::qxFetchAll("TestQtProperty"); qAssert(lst->__count() == 1); +} diff --git a/test/qxBlogPImpl/CMakeLists.txt b/test/qxBlogPImpl/CMakeLists.txt new file mode 100644 index 0000000..b8dc627 --- /dev/null +++ b/test/qxBlogPImpl/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogPImpl LANGUAGES CXX) + +include(../../QxOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ) + +add_executable(qxBlogPImpl ${SRCS} ${HEADERS}) + +target_compile_definitions(qxBlogPImpl PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogPImpl PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogPImpl ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxBlogPImpl PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogPImpl PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxBlogPImpl/debug/.gitignore b/test/qxBlogPImpl/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogPImpl/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogPImpl/include/author.h b/test/qxBlogPImpl/include/author.h new file mode 100644 index 0000000..4da39e1 --- /dev/null +++ b/test/qxBlogPImpl/include/author.h @@ -0,0 +1,48 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class QX_BLOG_DLL_EXPORT author +{ + + QX_REGISTER_FRIEND_CLASS(author) + +private: + + struct author_impl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + +public: + + enum enum_sex { male, female, unknown }; + + author(); + virtual ~author(); + + author(const author & other); + author & operator=(const author & other); + +#ifdef Q_COMPILER_RVALUE_REFS + author(author && other) Q_DECL_NOEXCEPT; + author & operator=(author && other) Q_DECL_NOEXCEPT; +#endif // Q_COMPILER_RVALUE_REFS + + int age() const; + QString id() const; + QString name() const; + QDate birthdate() const; + enum_sex sex() const; + + void setId(const QString & s); + void setName(const QString & s); + void setBirthdate(const QDate & d); + void setSex(enum_sex e); + +}; + +QX_REGISTER_PRIMARY_KEY(author, QString) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogPImpl/include/blog.h b/test/qxBlogPImpl/include/blog.h new file mode 100644 index 0000000..331237b --- /dev/null +++ b/test/qxBlogPImpl/include/blog.h @@ -0,0 +1,50 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +class author; +class comment; +class category; + +class QX_BLOG_DLL_EXPORT blog +{ + + QX_REGISTER_FRIEND_CLASS(blog) + +private: + + struct blog_impl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + +public: + + blog(); + virtual ~blog(); + + blog(const blog & other); + blog & operator=(const blog & other); + +#ifdef Q_COMPILER_RVALUE_REFS + blog(blog && other) Q_DECL_NOEXCEPT; + blog & operator=(blog && other) Q_DECL_NOEXCEPT; +#endif // Q_COMPILER_RVALUE_REFS + + long id() const; + QString text() const; + QDateTime dateCreation() const; + + void setId(long l); + void setText(const QString & s); + void setDateCreation(const QDateTime & d); + + std::shared_ptr & getAuthor(); + QList< std::shared_ptr > & listOfComments(); + qx::QxCollection > & listOfCategories(); + +}; + +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogPImpl/include/category.h b/test/qxBlogPImpl/include/category.h new file mode 100644 index 0000000..300343c --- /dev/null +++ b/test/qxBlogPImpl/include/category.h @@ -0,0 +1,46 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category +{ + + QX_REGISTER_FRIEND_CLASS(category) + +private: + + struct category_impl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + +public: + + category(); + virtual ~category(); + + category(const category & other); + category & operator=(const category & other); + +#ifdef Q_COMPILER_RVALUE_REFS + category(category && other) Q_DECL_NOEXCEPT; + category & operator=(category && other) Q_DECL_NOEXCEPT; +#endif // Q_COMPILER_RVALUE_REFS + + long id() const; + QString name() const; + QString desc() const; + + void setId(long l); + void setName(const QString & s); + void setDesc(const QString & s); + + qx::QxCollection > & listOfBlogs(); + +}; + +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogPImpl/include/comment.h b/test/qxBlogPImpl/include/comment.h new file mode 100644 index 0000000..7cc277f --- /dev/null +++ b/test/qxBlogPImpl/include/comment.h @@ -0,0 +1,46 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment +{ + + QX_REGISTER_FRIEND_CLASS(comment) + +private: + + struct comment_impl; + std::unique_ptr m_pImpl; //!< Private implementation idiom + +public: + + comment(); + virtual ~comment(); + + comment(const comment & other); + comment & operator=(const comment & other); + +#ifdef Q_COMPILER_RVALUE_REFS + comment(comment && other) Q_DECL_NOEXCEPT; + comment & operator=(comment && other) Q_DECL_NOEXCEPT; +#endif // Q_COMPILER_RVALUE_REFS + + long id() const; + QString text() const; + QDateTime dateCreation() const; + + void setId(long l); + void setText(const QString & s); + void setDateCreation(const QDateTime & d); + + std::shared_ptr & getBlog(); + +}; + +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogPImpl/include/export.h b/test/qxBlogPImpl/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogPImpl/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogPImpl/include/precompiled.h b/test/qxBlogPImpl/include/precompiled.h new file mode 100644 index 0000000..0d8b994 --- /dev/null +++ b/test/qxBlogPImpl/include/precompiled.h @@ -0,0 +1,8 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogPImpl/qt/moc/.gitignore b/test/qxBlogPImpl/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogPImpl/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogPImpl/qxBlog.pro b/test/qxBlogPImpl/qxBlog.pro new file mode 100644 index 0000000..44ef8e8 --- /dev/null +++ b/test/qxBlogPImpl/qxBlog.pro @@ -0,0 +1,34 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogPImpld +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogPImpl +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxBlogPImpl/release/.gitignore b/test/qxBlogPImpl/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogPImpl/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogPImpl/src/author.cpp b/test/qxBlogPImpl/src/author.cpp new file mode 100644 index 0000000..ab74dbd --- /dev/null +++ b/test/qxBlogPImpl/src/author.cpp @@ -0,0 +1,75 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) + +struct Q_DECL_HIDDEN author::author_impl +{ + QString m_id; + QString m_name; + QDate m_birthdate; + author::enum_sex m_sex; + list_blog m_blogX; + + author_impl() : m_sex(author::unknown) { ; } + ~author_impl() { ; } +}; + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pImpl = t.pimpl(& author::m_pImpl); + + t.id(& author::author_impl::m_id, "author_id", 0, pImpl); + + t.data(& author::author_impl::m_name, "name", 0, true, true, pImpl); + t.data(& author::author_impl::m_birthdate, "birthdate", 0, true, true, pImpl); + t.data(& author::author_impl::m_sex, "sex", 0, true, true, pImpl); + + t.relationOneToMany(& author::author_impl::m_blogX, "list_blog", "author_id", 0, pImpl); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +author::author() : m_pImpl(new author_impl()) { ; } + +author::~author() { ; } + +author::author(const author & other) : m_pImpl(new author_impl(* other.m_pImpl)) { ; } + +author & author::operator=(const author & other) +{ + if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); } + return (* this); +} + +#ifdef Q_COMPILER_RVALUE_REFS +author::author(author && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; } +author & author::operator=(author && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); } +#endif // Q_COMPILER_RVALUE_REFS + +int author::age() const +{ + if (! m_pImpl->m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_pImpl->m_birthdate.year()); +} + +QString author::id() const { return m_pImpl->m_id; } + +QString author::name() const { return m_pImpl->m_name; } + +QDate author::birthdate() const { return m_pImpl->m_birthdate; } + +author::enum_sex author::sex() const { return m_pImpl->m_sex; } + +void author::setId(const QString & s) { m_pImpl->m_id = s; } + +void author::setName(const QString & s) { m_pImpl->m_name = s; } + +void author::setBirthdate(const QDate & d) { m_pImpl->m_birthdate = d; } + +void author::setSex(enum_sex e) { m_pImpl->m_sex = e; } diff --git a/test/qxBlogPImpl/src/blog.cpp b/test/qxBlogPImpl/src/blog.cpp new file mode 100644 index 0000000..c0ab97c --- /dev/null +++ b/test/qxBlogPImpl/src/blog.cpp @@ -0,0 +1,73 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) + +struct Q_DECL_HIDDEN blog::blog_impl +{ + long m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; + + blog_impl() : m_id(0) { ; } + ~blog_impl() { ; } +}; + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pImpl = t.pimpl(& blog::m_pImpl); + + t.id(& blog::blog_impl::m_id, "blog_id", 0, pImpl); + + t.data(& blog::blog_impl::m_text, "blog_text", 0, true, true, pImpl); + t.data(& blog::blog_impl::m_dt_creation, "date_creation", 0, true, true, pImpl); + + t.relationManyToOne(& blog::blog_impl::m_author, "author_id", 0, pImpl); + t.relationOneToMany(& blog::blog_impl::m_commentX, "list_comment", "blog_id", 0, pImpl); + t.relationManyToMany(& blog::blog_impl::m_categoryX, "list_category", "category_blog", "blog_id", "category_id", 0, pImpl); +}} + +blog::blog() : m_pImpl(new blog_impl()) { ; } + +blog::~blog() { ; } + +blog::blog(const blog & other) : m_pImpl(new blog_impl(* other.m_pImpl)) { ; } + +blog & blog::operator=(const blog & other) +{ + if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); } + return (* this); +} + +#ifdef Q_COMPILER_RVALUE_REFS +blog::blog(blog && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; } +blog & blog::operator=(blog && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); } +#endif // Q_COMPILER_RVALUE_REFS + +long blog::id() const { return m_pImpl->m_id; } + +QString blog::text() const { return m_pImpl->m_text; } + +QDateTime blog::dateCreation() const { return m_pImpl->m_dt_creation; } + +void blog::setId(long l) { m_pImpl->m_id = l; } + +void blog::setText(const QString & s) { m_pImpl->m_text = s; } + +void blog::setDateCreation(const QDateTime & d) { m_pImpl->m_dt_creation = d; } + +std::shared_ptr & blog::getAuthor() { return m_pImpl->m_author; } + +QList< std::shared_ptr > & blog::listOfComments() { return m_pImpl->m_commentX; } + +qx::QxCollection > & blog::listOfCategories() { return m_pImpl->m_categoryX; } diff --git a/test/qxBlogPImpl/src/category.cpp b/test/qxBlogPImpl/src/category.cpp new file mode 100644 index 0000000..c4bde55 --- /dev/null +++ b/test/qxBlogPImpl/src/category.cpp @@ -0,0 +1,65 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) + +struct Q_DECL_HIDDEN category::category_impl +{ + typedef qx::QxCollection list_blog; + + long m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; + + category_impl() : m_id(0) { ; } + ~category_impl() { ; } +}; + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pImpl = t.pimpl(& category::m_pImpl); + + t.id(& category::category_impl::m_id, "category_id", 0, pImpl); + + t.data(& category::category_impl::m_name, "name", 0, true, true, pImpl); + t.data(& category::category_impl::m_desc, "description", 0, true, true, pImpl); + + t.relationManyToMany(& category::category_impl::m_blogX, "list_blog", "category_blog", "category_id", "blog_id", 0, pImpl); +}} + +category::category() : m_pImpl(new category_impl()) { ; } + +category::~category() { ; } + +category::category(const category & other) : m_pImpl(new category_impl(* other.m_pImpl)) { ; } + +category & category::operator=(const category & other) +{ + if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); } + return (* this); +} + +#ifdef Q_COMPILER_RVALUE_REFS +category::category(category && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; } +category & category::operator=(category && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); } +#endif // Q_COMPILER_RVALUE_REFS + +long category::id() const { return m_pImpl->m_id; } + +QString category::name() const { return m_pImpl->m_name; } + +QString category::desc() const { return m_pImpl->m_desc; } + +void category::setId(long l) { m_pImpl->m_id = l; } + +void category::setName(const QString & s) { m_pImpl->m_name = s; } + +void category::setDesc(const QString & s) { m_pImpl->m_desc = s; } + +qx::QxCollection > & category::listOfBlogs() { return m_pImpl->m_blogX; } diff --git a/test/qxBlogPImpl/src/comment.cpp b/test/qxBlogPImpl/src/comment.cpp new file mode 100644 index 0000000..52e9995 --- /dev/null +++ b/test/qxBlogPImpl/src/comment.cpp @@ -0,0 +1,63 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) + +struct Q_DECL_HIDDEN comment::comment_impl +{ + long m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; + + comment_impl() : m_id(0) { ; } + ~comment_impl() { ; } +}; + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pImpl = t.pimpl(& comment::m_pImpl); + + t.id(& comment::comment_impl::m_id, "comment_id", 0, pImpl); + + t.data(& comment::comment_impl::m_text, "comment_text", 0, true, true, pImpl); + t.data(& comment::comment_impl::m_dt_create, "date_creation", 0, true, true, pImpl); + + t.relationManyToOne(& comment::comment_impl::m_blog, "blog_id", 0, pImpl); +}} + +comment::comment() : m_pImpl(new comment_impl()) { ; } + +comment::~comment() { ; } + +comment::comment(const comment & other) : m_pImpl(new comment_impl(* other.m_pImpl)) { ; } + +comment & comment::operator=(const comment & other) +{ + if (this != (& other)) { (* m_pImpl) = (* other.m_pImpl); } + return (* this); +} + +#ifdef Q_COMPILER_RVALUE_REFS +comment::comment(comment && other) Q_DECL_NOEXCEPT : m_pImpl(std::move(other.m_pImpl)) { ; } +comment & comment::operator=(comment && other) Q_DECL_NOEXCEPT { if (this != (& other)) { m_pImpl = std::move(other.m_pImpl); }; return (* this); } +#endif // Q_COMPILER_RVALUE_REFS + +long comment::id() const { return m_pImpl->m_id; } + +QString comment::text() const { return m_pImpl->m_text; } + +QDateTime comment::dateCreation() const { return m_pImpl->m_dt_create; } + +void comment::setId(long l) { m_pImpl->m_id = l; } + +void comment::setText(const QString & s) { m_pImpl->m_text = s; } + +void comment::setDateCreation(const QDateTime & d) { m_pImpl->m_dt_create = d; } + +std::shared_ptr & comment::getBlog() { return m_pImpl->m_blog; } diff --git a/test/qxBlogPImpl/src/main.cpp b/test/qxBlogPImpl/src/main.cpp new file mode 100644 index 0000000..c30733c --- /dev/null +++ b/test/qxBlogPImpl/src/main.cpp @@ -0,0 +1,372 @@ +#include "../include/precompiled.h" + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +int main(int argc, char * argv[]) +{ + // Qt application + QCoreApplication app(argc, argv); + QFile::remove("./qxBlogPImpl.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlogPImpl.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::QxSqlDatabase::getSingleton()->setFormatSqlQueryBeforeLogging(true); + qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->setId("author_id_1"); author_1->setName("author_1"); + author_1->setSex(author::male); author_1->setBirthdate(QDate::currentDate()); + author_2->setId("author_id_2"); author_2->setName("author_2"); + author_2->setSex(author::female); author_2->setBirthdate(QDate::currentDate()); + author_3->setId("author_id_3"); author_3->setName("author_3"); + author_3->setSex(author::female); author_3->setBirthdate(QDate::currentDate()); + + list_author authorX; + authorX.insert(author_1->id(), author_1); + authorX.insert(author_2->id(), author_2); + authorX.insert(author_3->id(), author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone(* author_2); + qAssert(author_clone->id() == "author_id_2"); + qAssert(author_clone->sex() == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author, false); + qx::dump(list_of_female_author, true); + + // Test qx::QxSqlQuery::freeText() with/without placeholders + query = qx_query(); query.freeText("WHERE author.sex = " + QString::number(static_cast(author::female))); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + query = qx_query(); query.freeText("WHERE author.sex = :sex", QVariantList() << author::female); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + query = qx_query(); query.freeText("WHERE author.sex=:sex AND author.author_id=:author_id", QVariantList() << author::female << "author_id_2"); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 1); + query = qx_query(); query.freeText("WHERE (author.sex = :sex) AND (author.author_id = :author_id)", QVariantList() << author::female << "author_id_2"); + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 1); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->setName("category_1"); category_1->setDesc("desc_1"); + category_2->setName("category_2"); category_2->setDesc("desc_2"); + category_3->setName("category_3"); category_3->setDesc("desc_3"); + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->id() != 0); + qAssert(category_2->id() != 0); + qAssert(category_3->id() != 0); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->setText("blog_text_1"); + blog_1->setDateCreation(QDateTime::currentDateTime()); + blog_1->getAuthor() = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->setText("update blog_text_1"); + blog_1->getAuthor() = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->setText("comment_1 text"); + comment_1->setDateCreation(QDateTime::currentDateTime()); + comment_1->getBlog() = blog_1; + comment_2->setText("comment_2 text"); + comment_2->setDateCreation(QDateTime::currentDateTime()); + comment_2->getBlog() = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(qx::dao::count() == 2); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->listOfCategories().insert(category_1->id(), category_1); + blog_1->listOfCategories().insert(category_3->id(), category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->setId(blog_1->id()); + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(blog_tmp->listOfComments().count() == 2); + qAssert(blog_tmp->listOfCategories().count() == 2); + qAssert(blog_tmp->text() == "update blog_text_1"); + qAssert(blog_tmp->getAuthor() && blog_tmp->getAuthor()->id() == "author_id_2"); + + // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->setId(blog_1->id()); + daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp); + + qAssert(blog_tmp->listOfComments().count() == 2); + qAssert(blog_tmp->listOfCategories().count() == 2); + qAssert(blog_tmp->text() == "update blog_text_1"); + qAssert(blog_tmp->getAuthor() && blog_tmp->getAuthor()->id() == "author_id_2"); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp, false); + qx::dump(blog_tmp, true); + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + list_blog lstBlogComplexRelation; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *", lstBlogComplexRelation); + qx::dump(lstBlogComplexRelation); + qAssert(lstBlogComplexRelation.size() > 0); + qAssert(lstBlogComplexRelation[0]->text() != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->dateCreation().isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->getAuthor()->sex() == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation[0]->getAuthor()->name() != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->listOfComments().size() > 0); + qAssert(lstBlogComplexRelation[0]->listOfComments()[0]->dateCreation().isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->listOfComments()[0]->text() != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->listOfComments()[0]->getBlog()); + + // Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... } + list_blog lstBlogComplexRelation2; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "-{ blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *", lstBlogComplexRelation2); + qx::dump(lstBlogComplexRelation2); + qAssert(lstBlogComplexRelation2.size() > 0); + qAssert(lstBlogComplexRelation2[0]->text() == ""); // Not fetched + qAssert(! lstBlogComplexRelation2[0]->dateCreation().isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->getAuthor()->sex() != author::unknown); // Fetched + qAssert(lstBlogComplexRelation2[0]->getAuthor()->name() == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->listOfComments().size() > 0); + qAssert(! lstBlogComplexRelation2[0]->listOfComments()[0]->dateCreation().isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->listOfComments()[0]->text() == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->listOfComments()[0]->getBlog()); + +#ifndef _QX_NO_JSON + // Custom JSON serialization process + QString customJsonFull = qx::serialization::json::to_string(blog_tmp, 1); + QString customJsonFiltered = qx::serialization::json::to_string(blog_tmp, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + qDebug("[QxOrm] custom JSON serialization process (full) : \n%s", qPrintable(customJsonFull)); + qDebug("[QxOrm] custom JSON serialization process (filtered) : \n%s", qPrintable(customJsonFiltered)); + + blog_ptr blogFromJsonFull; blogFromJsonFull.reset(new blog()); + blog_ptr blogFromJsonFiltered; blogFromJsonFiltered.reset(new blog()); + qx::serialization::json::from_string(blogFromJsonFull, customJsonFull, 1); + qx::serialization::json::from_string(blogFromJsonFiltered, customJsonFull, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + + qx::dump(blogFromJsonFull); + qAssert(blogFromJsonFull->listOfComments().count() == 2); + qAssert(blogFromJsonFull->listOfCategories().count() == 2); + qAssert(blogFromJsonFull->text() == "update blog_text_1"); + qAssert(blogFromJsonFull->getAuthor() && blogFromJsonFull->getAuthor()->id() == "author_id_2"); + + qx::dump(blogFromJsonFiltered); + qAssert(blogFromJsonFiltered->text() != ""); // Fetched + qAssert(blogFromJsonFiltered->dateCreation().isNull()); // Not fetched + qAssert(blogFromJsonFiltered->getAuthor()->sex() == author::unknown); // Not fetched + qAssert(blogFromJsonFiltered->getAuthor()->name() != ""); // Fetched + qAssert(blogFromJsonFiltered->listOfComments().size() > 0); + qAssert(blogFromJsonFiltered->listOfComments()[0]->dateCreation().isNull()); // Not fetched + qAssert(blogFromJsonFiltered->listOfComments()[0]->text() != ""); // Fetched + qAssert(blogFromJsonFiltered->listOfComments()[0]->getBlog()); +#endif // _QX_NO_JSON + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + custom table alias using syntax + custom table alias suffix using syntax <..._my_alias_suffix> + list_blog lstBlogComplexRelation3; + daoError = qx::dao::fetch_all_with_relation(QStringList() << " { blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> * <..._my_alias_suffix>", lstBlogComplexRelation3); + qx::dump(lstBlogComplexRelation3); + qAssert(lstBlogComplexRelation3.size() > 0); + qAssert(lstBlogComplexRelation3[0]->text() != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->dateCreation().isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->getAuthor()->sex() == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation3[0]->getAuthor()->name() != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->listOfComments().size() > 0); + qAssert(lstBlogComplexRelation3[0]->listOfComments()[0]->dateCreation().isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->listOfComments()[0]->text() != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->listOfComments()[0]->getBlog()); + + // Test to add join SQL sub-queries (inside LEFT OUTER JOIN or INNER JOIN) + list_blog lstBlogWithJoinQueries; + query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1"); + query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL"); + query.addJoinQuery("author_alias", qx_query().freeText("AND author_alias.sex = :sex", QVariantList() << author::female)); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_text }" << "author_id { name, birthdate, sex }" << "list_comment { comment_text }", query, lstBlogWithJoinQueries); + qx::dump(lstBlogWithJoinQueries); + qAssert(lstBlogWithJoinQueries.size() > 0); + qAssert(lstBlogWithJoinQueries[0]->text() == "update blog_text_1"); + qAssert(lstBlogWithJoinQueries[0]->getAuthor()->sex() == author::female); + + // When join SQL sub-queries are used, then relationships should keep user defined order (in this example : 'list_comment' before 'author') + lstBlogWithJoinQueries.clear(); + query = qx_query().where("blog_alias.blog_text").isEqualTo("update blog_text_1"); + query.addJoinQuery("list_comment_alias", "AND list_comment_alias.comment_text IS NOT NULL"); + query.addJoinQuery("author_alias", qx_query("AND author_alias.sex = :sex", QVariantList() << author::female)); + daoError = qx::dao::fetch_by_query_with_relation(QStringList() << " { blog_text }" << "list_comment { comment_text }" << "author_id { name, birthdate, sex }", query, lstBlogWithJoinQueries); + qx::dump(lstBlogWithJoinQueries); + qAssert(lstBlogWithJoinQueries.size() > 0); + qAssert(lstBlogWithJoinQueries[0]->text() == "update blog_text_1"); + qAssert(lstBlogWithJoinQueries[0]->getAuthor()->sex() == author::female); + + // Check qx::dao::save_with_relation_recursive() function + daoError = qx::dao::save_with_relation_recursive(blog_tmp); + qAssert(! daoError.isValid()); + daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only); + qAssert(! daoError.isValid()); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // Check count with relations and filter + long lBlogCountWithRelation = 0; qx_query queryBlogCountWithRelation; + daoError = qx::dao::count_with_relation(lBlogCountWithRelation, QStringList() << "author_id" << "list_comment -> blog_id -> *", queryBlogCountWithRelation); + qAssert(! daoError.isValid() && (lBlogCountWithRelation > 0)); + + // Test 'isDirty()' method + qx::dao::ptr blog_isdirty = qx::dao::ptr(new blog()); + blog_isdirty->setId(blog_1->id()); + daoError = qx::dao::fetch_by_id(blog_isdirty); + qAssert(! daoError.isValid() && ! blog_isdirty.isDirty()); + + blog_isdirty->setText("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, false); + qx::dump(blog_isdirty, true); + + // 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->setName("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->setBirthdate(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, false); + qx::dump(container_isdirty, true); + + // 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].get() != NULL)) + { qAssert(lst_blog_with_only_date_creation[0]->text().isEmpty()); } + qx::dump(lst_blog_with_only_date_creation, false); + qx::dump(lst_blog_with_only_date_creation, true); + + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + // Call a custom SQL query or a stored procedure + qx_query testStoredProc("SELECT * FROM author"); + daoError = qx::dao::call_query(testStoredProc); + qAssert(! daoError.isValid()); + testStoredProc.dumpSqlResult(); + + // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items) + qx_query testStoredProcBis("SELECT * FROM author"); + authorX.clear(); + daoError = qx::dao::execute_query(testStoredProcBis, authorX); + qAssert(! daoError.isValid()); qAssert(authorX.count() > 0); + qx::dump(authorX, false); + qx::dump(authorX, true); + + // Call a custom SQL query or a stored procedure and fetch automatically properties + qx_query testStoredProcThird("SELECT name, category_id FROM category"); + category_ptr category_tmp = category_ptr(new category()); + daoError = qx::dao::execute_query(testStoredProcThird, category_tmp); + qAssert(! daoError.isValid()); qAssert(category_tmp->id() != 0); + qx::dump(category_tmp, false); + qx::dump(category_tmp, true); + + // Test SQL DISTINCT keyword + QList listOfBlogDistinct; + qx_query queryDistinct; queryDistinct.distinct().limit(10); + daoError = qx::dao::fetch_by_query(queryDistinct, listOfBlogDistinct, NULL, QStringList() << "blog_text"); + qAssert(! daoError.isValid()); qAssert((listOfBlogDistinct.count() > 0) && (listOfBlogDistinct.at(0).id() == 0) && (! listOfBlogDistinct.at(0).text().isEmpty())); + qx::dump(listOfBlogDistinct); + + return 0; +} diff --git a/test/qxBlogRestApi/CMakeLists.txt b/test/qxBlogRestApi/CMakeLists.txt new file mode 100644 index 0000000..69e2a37 --- /dev/null +++ b/test/qxBlogRestApi/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxBlogRestApi LANGUAGES CXX) + +include(../../QxOrm.cmake) + +if(NOT _QX_NO_JSON) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Widgets Quick Qml REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/author.h + ./include/blog.h + ./include/category.h + ./include/comment.h + ) + +set(SRCS + ./src/author.cpp + ./src/blog.cpp + ./src/category.cpp + ./src/comment.cpp + ./src/main.cpp + ) + +set(QRCS + ./qt/rcc/qxBlogRestApi.qrc + ) + +if(COMMAND qt_add_resources) +qt_add_resources(QRCS_HDRS ${QRCS}) +else() # (COMMAND qt_add_resources) +qt5_add_resources(QRCS_HDRS ${QRCS}) +endif() # (COMMAND qt_add_resources) + +add_executable(qxBlogRestApi ${SRCS} ${HEADERS} ${QRCS_HDRS}) + +target_compile_definitions(qxBlogRestApi PRIVATE -D_BUILDING_QX_BLOG) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxBlogRestApi PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxBlogRestApi ${QX_LIBRARIES} QxOrm Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Qml) + +set_target_properties(qxBlogRestApi PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../_bin" + ) + +set_target_properties(qxBlogRestApi PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +else() # _QX_NO_JSON + +message(STATUS "qxBlogRestApi project not loaded because _QX_NO_JSON option is defined (QxOrm REST API requires JSON serialization)") + +endif() # _QX_NO_JSON diff --git a/test/qxBlogRestApi/debug/.gitignore b/test/qxBlogRestApi/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogRestApi/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogRestApi/include/author.h b/test/qxBlogRestApi/include/author.h new file mode 100644 index 0000000..c83ebb6 --- /dev/null +++ b/test/qxBlogRestApi/include/author.h @@ -0,0 +1,34 @@ +#ifndef _QX_BLOG_AUTHOR_H_ +#define _QX_BLOG_AUTHOR_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT author : public qx::IxPersistable +{ + QX_PERSISTABLE_HPP(author) +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef std::vector list_blog; +// -- enum + enum enum_sex { male, female, unknown }; +// -- properties + QString m_id; + QString m_name; + QDate m_birthdate; + enum_sex m_sex; + list_blog m_blogX; +// -- contructor, virtual destructor + author() : qx::IxPersistable(), m_id("0"), m_sex(unknown) { ; } + virtual ~author() { ; } +// -- methods + int age() const; +}; + +QX_REGISTER_PRIMARY_KEY(author, QString) +QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr author_ptr; +typedef qx::QxCollection list_author; + +#endif // _QX_BLOG_AUTHOR_H_ diff --git a/test/qxBlogRestApi/include/blog.h b/test/qxBlogRestApi/include/blog.h new file mode 100644 index 0000000..182d53c --- /dev/null +++ b/test/qxBlogRestApi/include/blog.h @@ -0,0 +1,37 @@ +#ifndef _QX_BLOG_BLOG_H_ +#define _QX_BLOG_BLOG_H_ + +#include "author.h" +#include "comment.h" +#include "category.h" + +class QX_BLOG_DLL_EXPORT blog : public qx::IxPersistable +{ + QX_PERSISTABLE_HPP(blog) + QX_REGISTER_FRIEND_CLASS(blog) +public: +// -- properties + long m_id; + QString m_text; + QDateTime m_dt_creation; + author_ptr m_author; + list_comment m_commentX; + list_category m_categoryX; +// -- contructor, virtual destructor + blog() : qx::IxPersistable(), m_id(0) { ; } + virtual ~blog() { ; } +#ifndef _QX_NO_JSON +// -- function callable by introspection and REST API + static QJsonValue helloWorld(const QJsonValue & request); +#endif // _QX_NO_JSON +private: +// -- function to validate a blog instance + void isValid(qx::QxInvalidValueX & invalidValues); +}; + +QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr blog_ptr; +typedef std::vector list_blog; + +#endif // _QX_BLOG_BLOG_H_ diff --git a/test/qxBlogRestApi/include/category.h b/test/qxBlogRestApi/include/category.h new file mode 100644 index 0000000..fd23b54 --- /dev/null +++ b/test/qxBlogRestApi/include/category.h @@ -0,0 +1,28 @@ +#ifndef _QX_BLOG_CATEGORY_H_ +#define _QX_BLOG_CATEGORY_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT category : public qx::IxPersistable +{ + QX_PERSISTABLE_HPP(category) +public: +// -- typedef + typedef std::shared_ptr blog_ptr; + typedef qx::QxCollection list_blog; +// -- properties + long m_id; + QString m_name; + QString m_desc; + list_blog m_blogX; +// -- contructor, virtual destructor + category() : qx::IxPersistable(), m_id(0) { ; } + virtual ~category() { ; } +}; + +QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0) + +typedef QSharedPointer category_ptr; +typedef qx::QxCollection list_category; + +#endif // _QX_BLOG_CATEGORY_H_ diff --git a/test/qxBlogRestApi/include/comment.h b/test/qxBlogRestApi/include/comment.h new file mode 100644 index 0000000..c0d1897 --- /dev/null +++ b/test/qxBlogRestApi/include/comment.h @@ -0,0 +1,27 @@ +#ifndef _QX_BLOG_COMMENT_H_ +#define _QX_BLOG_COMMENT_H_ + +class blog; + +class QX_BLOG_DLL_EXPORT comment : public qx::IxPersistable +{ + QX_PERSISTABLE_HPP(comment) +public: +// -- typedef + typedef std::shared_ptr blog_ptr; +// -- properties + long m_id; + QString m_text; + QDateTime m_dt_create; + blog_ptr m_blog; +// -- contructor, virtual destructor + comment() : qx::IxPersistable(), m_id(0) { ; } + virtual ~comment() { ; } +}; + +QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr comment_ptr; +typedef QList list_comment; + +#endif // _QX_BLOG_COMMENT_H_ diff --git a/test/qxBlogRestApi/include/export.h b/test/qxBlogRestApi/include/export.h new file mode 100644 index 0000000..b1c11df --- /dev/null +++ b/test/qxBlogRestApi/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_BLOG_EXPORT_H_ +#define _QX_BLOG_EXPORT_H_ + +#ifdef _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_BLOG +#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_BLOG + +#ifdef _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_BLOG +#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_BLOG + +#endif // _QX_BLOG_EXPORT_H_ diff --git a/test/qxBlogRestApi/include/precompiled.h b/test/qxBlogRestApi/include/precompiled.h new file mode 100644 index 0000000..0d8b994 --- /dev/null +++ b/test/qxBlogRestApi/include/precompiled.h @@ -0,0 +1,8 @@ +#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_ +#define _QX_BLOG_PRECOMPILED_HEADER_H_ + +#include + +#include "export.h" + +#endif // _QX_BLOG_PRECOMPILED_HEADER_H_ diff --git a/test/qxBlogRestApi/qt/moc/.gitignore b/test/qxBlogRestApi/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogRestApi/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_ca.pem b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_ca.pem new file mode 100644 index 0000000..e0eb24e --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_ca.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEyjCCA7KgAwIBAgIJAOwBaVFFv3nHMA0GCSqGSIb3DQEBCwUAMIGeMQswCQYD +VQQGEwJGUjEUMBIGA1UECBMLTW9udHBlbGxpZXIxFDASBgNVBAcTC0JhaWxsYXJn +dWVzMQ4wDAYDVQQKEwVReE9ybTEhMB8GA1UECxMYUXhPcm0gYW5kIFF4RW50aXR5 +RWRpdG9yMQ4wDAYDVQQDEwVReE9ybTEgMB4GCSqGSIb3DQEJARYRY29udGFjdEBx +eG9ybS5jb20wHhcNMTkwMzA5MTMxNTU2WhcNMjQwMzA3MTMxNTU2WjCBnjELMAkG +A1UEBhMCRlIxFDASBgNVBAgTC01vbnRwZWxsaWVyMRQwEgYDVQQHEwtCYWlsbGFy +Z3VlczEOMAwGA1UEChMFUXhPcm0xITAfBgNVBAsTGFF4T3JtIGFuZCBReEVudGl0 +eUVkaXRvcjEOMAwGA1UEAxMFUXhPcm0xIDAeBgkqhkiG9w0BCQEWEWNvbnRhY3RA +cXhvcm0uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4AJ2A+3Q +3CrVM7ptfaXczoHPP4Nvedr+bYRqGzvgrK83nmdtIVDZBAUFLBaVqs4ry3RPsFat +YbKcsMynKuefMngUHTpOW2EXvlouiPzFDYM6+VlggiWRUpC9Ofd7h/Gph0ShTpqH +4Be20m4+tsai6dk0UO91AGnHyg4QMeGW1EbY+YSv6eX84uKcfNikZNYGGiVc27ru +UnQz92e+upnhaFN30NW7eTsnAxDBOr9q0PHEpJbkNk+o4gMPjDt1NOddRk7Cp3f6 +Uz/+eUO+AzWpZRfSPfQy4+YY7gP3r9rZmLf2AGoRw7aYiTWvObLjPB/SA1Dwaoc2 +O2xpKJD6MuAYswIDAQABo4IBBzCCAQMwHQYDVR0OBBYEFDCJhMbpmZK21Te5Bgei +56xDxXADMIHTBgNVHSMEgcswgciAFDCJhMbpmZK21Te5Bgei56xDxXADoYGkpIGh +MIGeMQswCQYDVQQGEwJGUjEUMBIGA1UECBMLTW9udHBlbGxpZXIxFDASBgNVBAcT +C0JhaWxsYXJndWVzMQ4wDAYDVQQKEwVReE9ybTEhMB8GA1UECxMYUXhPcm0gYW5k +IFF4RW50aXR5RWRpdG9yMQ4wDAYDVQQDEwVReE9ybTEgMB4GCSqGSIb3DQEJARYR +Y29udGFjdEBxeG9ybS5jb22CCQDsAWlRRb95xzAMBgNVHRMEBTADAQH/MA0GCSqG +SIb3DQEBCwUAA4IBAQBvJCXV+eJ2oSRblCNjB2kGjt99Zx+sKLXXuzMs1a+3Dn34 +n5h4UIXM7T7VtcU0b5M/ifaaftp7JZZvI1RF5ohFUC2iM826EPbCKiVgUJupWnTr +w5cY+Ac3coN4QFHbDvBAY0duuxUar2UmzhDZa6oOPs5ND+nw0YA5GBpjsG0uzsFA +ixyPQb24K280mwjxyOvo+/z1Ou6DvGIxriGuwZiJKLInnb6KrV6YRci7aWR0weMn +kZVBavtLevzk8h/zPZCaYb9wYhX2sJ5chfQVQHrr3betC0VeOxziKZem7c+oNVB4 +xTdaOZirtHk7BqJAhEJRXSX6DTXkiFVWohL6LNCf +-----END CERTIFICATE----- diff --git a/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.crt b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.crt new file mode 100644 index 0000000..6fc082f --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEEjCCAvqgAwIBAgIJALC9lov7amDkMA0GCSqGSIb3DQEBCwUAMIGeMQswCQYD +VQQGEwJGUjEUMBIGA1UECBMLTW9udHBlbGxpZXIxFDASBgNVBAcTC0JhaWxsYXJn +dWVzMQ4wDAYDVQQKEwVReE9ybTEhMB8GA1UECxMYUXhPcm0gYW5kIFF4RW50aXR5 +RWRpdG9yMQ4wDAYDVQQDEwVReE9ybTEgMB4GCSqGSIb3DQEJARYRY29udGFjdEBx +eG9ybS5jb20wHhcNMTkwMzA5MTMyMTE4WhcNMjQwMzA3MTMyMTE4WjCBnjELMAkG +A1UEBhMCRlIxFDASBgNVBAgTC01vbnRwZWxsaWVyMRQwEgYDVQQHEwtCYWlsbGFy +Z3VlczEOMAwGA1UEChMFUXhPcm0xITAfBgNVBAsTGFF4T3JtIGFuZCBReEVudGl0 +eUVkaXRvcjEOMAwGA1UEAxMFUXhPcm0xIDAeBgkqhkiG9w0BCQEWEWNvbnRhY3RA +cXhvcm0uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5gXL5XXa +aFW0LYspMhGpZpFzhGGMbwbm/+lpV1VZH7qoPBaMaxioO62vJFGthersbcWoIq6g +XuiclP63i0iPe0J5lzXic973posoNw0yCPQiIFpwSd2fNW7tq9mDahzDiAUbI9U3 +R7wgdirAzsQmumJ4j2Dnfdal4modEjnQKtH7AF5U9fNAdBayvG4p4iPg2AXzUkhR +iyfIpIMct/5d6vjPQEewO1HYocMYp2K4P65XOtJ9AHE+0543ualvoUGmtG+x+CWg +/g8uidGHhgWL1AfsHFrXZaP5B1Y3xhcN3tJNDg6emHs5SEcbhp2W2CkdpDn/nqX3 +NbQJobkeM7d4RQIDAQABo1EwTzAfBgNVHSMEGDAWgBQwiYTG6ZmSttU3uQYHoues +Q8VwAzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAUBgNVHREEDTALgglxeG9ybS5j +b20wDQYJKoZIhvcNAQELBQADggEBAFY5aWMu2g7D63IigrtXPiFGsnkOSZn5p95z +Q2xacbGdq//NeWrkuzUkaYH6z9rdtVWe93kmU/pT6neT6ttVAjmfvzzgm6IRF4PT +xnKKGfyV+woorSuQlSxYogHtgOCHw7FSSgykqYVLQkPeAEWzwOrTpBAWsWYqKFLO +oBAo7XYdfxXg0zM5kuvDk3vKHH0Rc25o5QpD4BCEqxaSN/p3dSPGtM3AwSqDLyEI +vDQNiTR5slqxTAv1nKd1CuZSAES+ceHmt6q04ESnwRz7pCMOF6N5iAvRHkbIR2DY +vsmWZwhTmCbHWUhS0b8GMoL+MPIbB3n2jq4rbeRo0vPx+ZUHkk0= +-----END CERTIFICATE----- diff --git a/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.key b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.key new file mode 100644 index 0000000..5084923 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/cert_qxorm_server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEA5gXL5XXaaFW0LYspMhGpZpFzhGGMbwbm/+lpV1VZH7qoPBaM +axioO62vJFGthersbcWoIq6gXuiclP63i0iPe0J5lzXic973posoNw0yCPQiIFpw +Sd2fNW7tq9mDahzDiAUbI9U3R7wgdirAzsQmumJ4j2Dnfdal4modEjnQKtH7AF5U +9fNAdBayvG4p4iPg2AXzUkhRiyfIpIMct/5d6vjPQEewO1HYocMYp2K4P65XOtJ9 +AHE+0543ualvoUGmtG+x+CWg/g8uidGHhgWL1AfsHFrXZaP5B1Y3xhcN3tJNDg6e +mHs5SEcbhp2W2CkdpDn/nqX3NbQJobkeM7d4RQIDAQABAoIBABmoH9wSTzBADv7d +fNTW33xPUQE9GDryHCYDVPqmzHAbk9RP942ijHFLqDN24NIFKCX+XAiyTbUIYR7F +Ypeomkh3W7SgEAg4oIr1DqFFWYViJcRSEiBLFg0RuHToqB3X439yglp219mqhDxp +/GOTwXYcsbHcbzW8EXi1uVRlGnEMELLf5FeJS0ZfavogcC+zUqrvIemMs9ltkktM +I6ABje3WxsJgOafb1uleUr9y04Fgf9CWt76FdPJucl2dBjj+kzxs9JnQw5cYC0v4 +ISK/lbnddbLaqeZ52ebEH70LAc+4uSAYEEfoodEt1STIxCAGOH7gepcJLt0PQkO5 +x4TJJqkCgYEA/PLhwy9v1AR/zAZ/JSJe5ahgMbQZy7Yt4fYWq3+yKTWO8DcTO2oL +ik2J05xZO3J2723ZeD3VEI7U/U9e7cxrW8CyxM3N2khj6kWglrSFQXWK7AaMpcDQ +pE8+G8Vb/1mwJSIh+CdiVlx0HaKLF0tyGTcEQlM/Fi+YQdYJUTjNKVsCgYEA6Mwe +HIv4yLENtq2wdgAnhBt7j91oQfUlMjmmZ2i5is9xseOg4PU5LmsDi01hfuVPdTXg +JHIFVLmiv2vIhEg8nVr4xou437giHNUyO5dpcMVWSG00N6ChuomEGFHh1FxH4N8Q +tUqc2nPtGxOQMKfg9CN+HEmEykCEucDCP3o59t8CgYBfYxAz1M2s/E1dGQ4VaNK0 +dDxiQfKAWaEP1wdRgQQkeif++iXsf97+NqNFA2669j1XqOsbZuXUKqizJZ08u5u4 +rAA+KwX3zNiw3bTjYAvoVXUf8JBVaVLEw4U+X7yDnMTKHAcHV4LD4nV/P26ISFEs +pQycHlxp92TJXveAg5UKhQKBgFmsjwjWDj5YnXy6CVhbFN25rG4tjoShxvNC68u3 +tok3AYfRtF4TeDReOp5Fb4HvGR2AZFgFp/IMFBoCjdoO7XJ74YqxtcRP7KwIn/H+ +kDpFecgqcMvgz4vIfx7TI9emuHVx18DN/f/UWghtD8T+VhQVO/Xvh/xUwAvBqdHD +5mInAoGARe2+SN/zZiAdjCULMpAcrwKkqbniKemeg90yFsfusWe0Sm60W4y+7x+U +BFFV9cqRd/vcNo/s5K+JMgLlGngEDgeAokvXwdkQeX4Loy9eHaFriraxZEAhDNCE +CGN/Ek40PNfnk5KmD5UXg2+NAYRpsILkLJytBHajiGAoSxScTsM= +-----END RSA PRIVATE KEY----- diff --git a/test/qxBlogRestApi/qt/rcc/documents/jquery.js b/test/qxBlogRestApi/qt/rcc/documents/jquery.js new file mode 100644 index 0000000..4d9b3a2 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + +

Welcome to QxOrm HTTP Server - qxBlogRestApi example project

+ + + + + + + + + + + + + + + + + +
+ + + +
+ + + +

QxOrm, QxEntityEditor +
+ +
+

+ +
+ + + diff --git a/test/qxBlogRestApi/qt/rcc/documents/test_http_server.qml b/test/qxBlogRestApi/qt/rcc/documents/test_http_server.qml new file mode 100644 index 0000000..20e5bc1 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/test_http_server.qml @@ -0,0 +1,40 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + +Item { + width: 500 + height: 130 + Column { + anchors.fill: parent + spacing: 10 + anchors.leftMargin: 5 + anchors.rightMargin: 5 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: " " + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "!!! Test QxOrm QxRestApi module from a web page using QxHttpServer module !!!" + font.bold: true + color: "blue" + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "Please open your web browser to this URL : http://localhost:9642/files/test_http_server.html" + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "Note : closing this QML window means stopping QxOrm HTTP server too." + } + } +} diff --git a/test/qxBlogRestApi/qt/rcc/documents/test_http_server_qt6.qml b/test/qxBlogRestApi/qt/rcc/documents/test_http_server_qt6.qml new file mode 100644 index 0000000..8401bb0 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/test_http_server_qt6.qml @@ -0,0 +1,39 @@ +import QtQuick +import QtQuick.Controls + +Item { + width: 500 + height: 130 + Column { + anchors.fill: parent + spacing: 10 + anchors.leftMargin: 5 + anchors.rightMargin: 5 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: " " + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "!!! Test QxOrm QxRestApi module from a web page using QxHttpServer module !!!" + font.bold: true + color: "blue" + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "Please open your web browser to this URL : http://localhost:9642/files/test_http_server.html" + } + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "Note : closing this QML window means stopping QxOrm HTTP server too." + } + } +} diff --git a/test/qxBlogRestApi/qt/rcc/documents/test_rest_api.qml b/test/qxBlogRestApi/qt/rcc/documents/test_rest_api.qml new file mode 100644 index 0000000..79399a2 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/test_rest_api.qml @@ -0,0 +1,503 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 + +Item { + width: 1000 + height: 700 + Row { + anchors.fill: parent + spacing: 10 + anchors.leftMargin: 5 + anchors.rightMargin: 5 + Column { + width: ((parent.width - 10) * 0.5) + height: (parent.height) + spacing: 10 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "JSON Request" + font.bold: true + color: "blue" + } + TextArea { + id: txtRequest + anchors.left: parent.left + anchors.right: parent.right + height: (parent.height * 0.4) + wrapMode: TextEdit.NoWrap + text: "" + } + Button { + anchors.left: parent.left + anchors.right: parent.right + text: "Send JSON request" + height: 45 + onClicked: onSendRequest() + style: ButtonStyle { + label: Text { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + font.pointSize: 12 + font.bold: true + color: "blue" + } + } + } + Label { + anchors.left: parent.left + anchors.right: parent.right + text: "Here are some request examples :" + font.italic: true + color: "blue" + } + ScrollView { + width: parent.width + height: (parent.height * 0.4) + ListView { + id: lstRequestExample + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + boundsBehavior: Flickable.StopAtBounds + model: ListModel { + id: modelRequestExample + ListElement { key: "get_meta_data"; txt: " - get project meta-data (all classes)" } + ListElement { key: "fetch_all_blogs"; txt: " - fetch all blogs (as list)" } + ListElement { key: "fetch_all_blogs_as_collection"; txt: " - fetch all blogs (as collection key/value)" } + ListElement { key: "fetch_all_blogs_with_relationships"; txt: " - fetch all blogs with relationships (several levels)" } + ListElement { key: "fetch_all_blogs_with_relationships_output_format"; txt: " - fetch all blogs with relationships (several levels) and define output format" } + ListElement { key: "fetch_blog_by_id"; txt: " - fetch a single blog by id" } + ListElement { key: "fetch_blog_by_id_columns"; txt: " - fetch some columns of a single blog by id" } + ListElement { key: "fetch_list_of_blog_by_id"; txt: " - fetch list of blogs by id" } + ListElement { key: "fetch_list_of_blog_by_id_output_format"; txt: " - fetch list of blogs by id and define output format" } + ListElement { key: "fetch_authors_by_query"; txt: " - fetch authors using a query (only female)" } + ListElement { key: "fetch_authors_by_query_with_relationships"; txt: " - fetch authors with relationships using a query" } + ListElement { key: "fetch_authors_by_query_with_relationships_output_format"; txt: " - fetch authors with relationships using a query and define output format" } + ListElement { key: "insert_blog"; txt: " - insert a blog" } + ListElement { key: "insert_list_of_blog"; txt: " - insert list of blogs" } + ListElement { key: "insert_author"; txt: " - insert an author" } + ListElement { key: "insert_category"; txt: " - insert a category" } + ListElement { key: "update_blog"; txt: " - update a blog" } + ListElement { key: "update_blog_columns"; txt: " - update some columns of blog" } + ListElement { key: "update_author"; txt: " - update an author" } + ListElement { key: "update_list_of_author"; txt: " - update list of authors" } + ListElement { key: "update_category"; txt: " - update a category" } + ListElement { key: "save_blog"; txt: " - save (insert or update) a blog" } + ListElement { key: "save_list_of_blog"; txt: " - save (insert or update) list of blogs" } + ListElement { key: "save_blog_recursive"; txt: " - save (insert or update) a blog with relationships (recursively)" } + ListElement { key: "save_blog_recursive_insert"; txt: " - save (insert optimized) a blog with relationships (recursively)" } + ListElement { key: "exist_blog"; txt: " - check if a blog id exist" } + ListElement { key: "exist_list_of_blog"; txt: " - check if list of blogs id exist" } + ListElement { key: "exist_author"; txt: " - check if an author id exist" } + ListElement { key: "validate_blog"; txt: " - validate a blog instance" } + ListElement { key: "count_all_blog"; txt: " - count all blogs" } + ListElement { key: "count_author_with_query"; txt: " - count authors using a query" } + ListElement { key: "count_blog_with_query_and_relationships"; txt: " - count blogs using a query and relationships" } + ListElement { key: "delete_blog_by_id"; txt: " - delete a blog by id" } + ListElement { key: "delete_list_of_blog_by_id"; txt: " - delete list of blogs by id" } + ListElement { key: "delete_author_by_query"; txt: " - delete some authors using a query" } + ListElement { key: "delete_all_comment"; txt: " - delete all comments" } + ListElement { key: "call_custom_query"; txt: " - call custom database query or stored procedure" } + ListElement { key: "call_entity_function"; txt: " - call entity static function with signature : static QJsonValue myEntity::myFct(const QJsonValue & request)" } + ListElement { key: "several_requests_in_array"; txt: " - build several requests in array to send only 1 call to server (executed in a transaction commit/rollback)" } + } + delegate: Rectangle { + width: parent.width + height: 20 + color: ((index == lstRequestExample.currentIndex) ? "lightblue" : (((index % 2) == 0) ? "white" : "papayawhip")) + Column { Text { text: txt } } + MouseArea { + anchors.fill: parent + onClicked: lstRequestExample.currentIndex = index + } + } + highlight: Rectangle { color: "lightblue" } + onCurrentItemChanged: onRequestExampleSelected(modelRequestExample.get(lstRequestExample.currentIndex)) + Component.onCompleted : currentIndex = -1 + focus: true + } + } + } + Column { + width: ((parent.width - 10) * 0.5) + height: (parent.height) + spacing: 10 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "JSON Response" + font.bold: true + color: "blue" + } + TextArea { + id: txtResponse + anchors.left: parent.left + anchors.right: parent.right + height: (parent.height * 0.9) + wrapMode: TextEdit.NoWrap + text: "" + } + } + } + + function onSendRequest() { + try { + console.log("onSendRequest() called"); + qxRestApi.clearAll(); + var response = qxRestApi.processRequest(txtRequest.text); + response = JSON.parse(response); + txtResponse.text = JSON.stringify(response, null, 3); + } + catch(exc) { + txtResponse.text = "An error occurred processing request : " + exc; + } + } + + function onRequestExampleSelected(objRequestExample) { + txtResponse.text = ""; + if (! objRequestExample) { return; } + console.log("onRequestExampleSelected() : " + objRequestExample.key + " selected"); + var request = buildRequestExample(objRequestExample); + txtRequest.text = JSON.stringify(request, null, 3); + } + + function buildRequestExample(objRequestExample) { + var request = { }; + request.request_id = createGUID(); + if (objRequestExample.key == "get_meta_data") { + request.action = "get_meta_data"; + request.entity = "*"; + } + else if (objRequestExample.key == "fetch_all_blogs") { + request.action = "fetch_all"; + request.entity = "blog"; + } + else if (objRequestExample.key == "fetch_all_blogs_as_collection") { + request.action = "fetch_all"; + request.entity = "blog"; + request.data = [ { key: "", value: "" } ] + } + else if (objRequestExample.key == "fetch_all_blogs_with_relationships") { + request.action = "fetch_all"; + request.entity = "blog"; + request.relations = [ "*->*" ]; + } + else if (objRequestExample.key == "fetch_all_blogs_with_relationships_output_format") { + request.action = "fetch_all"; + request.entity = "blog"; + request.relations = [ " { blog_text }", "author_id { name, birthdate }", "list_comment { comment_text } -> blog_id -> * <..._my_alias_suffix>" ]; + request.output_format = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text } -> blog_id -> *" ]; + } + else if (objRequestExample.key == "fetch_blog_by_id") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + } + else if (objRequestExample.key == "fetch_blog_by_id_columns") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + request.columns = [ "blog_text", "date_creation" ]; + } + else if (objRequestExample.key == "fetch_list_of_blog_by_id") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 2 }, { blog_id: 3 } ]; + } + else if (objRequestExample.key == "fetch_list_of_blog_by_id_output_format") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 2 } ]; + request.relations = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text }" ]; + request.output_format = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text }" ]; + } + else if (objRequestExample.key == "fetch_authors_by_query") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + } + else if (objRequestExample.key == "fetch_authors_by_query_with_relationships") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + request.relations = [ "*" ]; + } + else if (objRequestExample.key == "fetch_authors_by_query_with_relationships_output_format") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + request.relations = [ "*" ]; + request.output_format = [ "{ birthdate, name }", "list_blog { blog_text, date_creation }" ]; + } + else if (objRequestExample.key == "insert_blog") { + request.action = "insert"; + request.entity = "blog"; + request.data = { + blog_text: "this is a new blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }; + } + else if (objRequestExample.key == "insert_list_of_blog") { + request.action = "insert"; + request.entity = "blog"; + request.data = [ + { + blog_text: "new blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }, + { + blog_text: "another blog from QxOrm REST API !", + date_creation: "2016-06-12T08:33:12", + author_id: "author_id_1" + } + ]; + } + else if (objRequestExample.key == "insert_author") { + request.action = "insert"; + request.entity = "author"; + request.data = { + author_id: "author_id_from_rest_api", + birthdate: "1978-05-11", + name: "new author created by QxOrm REST API", + sex: 1 + }; + } + else if (objRequestExample.key == "insert_category") { + request.action = "insert"; + request.entity = "category"; + request.data = { + description: "category from REST API", + name: "new_category" + }; + } + else if (objRequestExample.key == "update_blog") { + request.action = "update"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: "author_id_1" + }; + } + else if (objRequestExample.key == "update_blog_columns") { + request.action = "update"; + request.entity = "blog"; + request.data = { + blog_id: 2, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33" + }; + request.columns = [ "blog_text", "date_creation" ]; + } + else if (objRequestExample.key == "update_author") { + request.action = "update"; + request.entity = "author"; + request.data = { + author_id: "author_id_from_rest_api", + birthdate: "1992-11-03", + name: "modify author from QxOrm REST API", + sex: 0 + }; + } + else if (objRequestExample.key == "update_list_of_author") { + request.action = "update"; + request.entity = "author"; + request.data = [ + { + author_id: "author_id_from_rest_api", + birthdate: "1992-11-03", + name: "modify author from QxOrm REST API", + sex: 0 + }, + { + author_id: "author_id_1", + birthdate: "1978-12-25", + name: "modify another author from QxOrm REST API", + sex: 2 + } + ]; + } + else if (objRequestExample.key == "update_category") { + request.action = "update"; + request.entity = "category"; + request.data = { + category_id: 1, + description: "category modified by REST API", + name: "modif_category" + }; + } + else if (objRequestExample.key == "save_blog") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: "author_id_1" + }; + } + else if (objRequestExample.key == "save_list_of_blog") { + request.action = "save"; + request.entity = "blog"; + request.data = [ + { + blog_id: 1, + blog_text: "save blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }, + { + blog_text: "save another blog from QxOrm REST API !", + date_creation: "2016-06-12T08:33:12", + author_id: "author_id_1" + } + ]; + } + else if (objRequestExample.key == "save_blog_recursive") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "save recursive blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: { + author_id: "author_id_1", + birthdate: "1965-07-21", + name: "save recursive author from QxOrm REST API", + sex: 0 + } + }; + request.save_mode = "check_insert_or_update"; + } + else if (objRequestExample.key == "save_blog_recursive_insert") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_text: "save recursive - new blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: { + author_id: "author_id_save_recursive", + birthdate: "1965-07-21", + name: "save recursive (insert only) author from QxOrm REST API", + sex: 0 + } + }; + request.save_mode = "insert_only"; + } + else if (objRequestExample.key == "exist_blog") { + request.action = "exist"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + } + else if (objRequestExample.key == "exist_list_of_blog") { + request.action = "exist"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 999 }, { blog_id: 3 } ]; + } + else if (objRequestExample.key == "exist_author") { + request.action = "exist"; + request.entity = "author"; + request.data = { author_id: "author_id_2" }; + } + else if (objRequestExample.key == "validate_blog") { + request.action = "validate"; + request.entity = "blog"; + request.data = { blog_id: 9999, blog_text: "" }; + } + else if (objRequestExample.key == "count_all_blog") { + request.action = "count"; + request.entity = "blog"; + } + else if (objRequestExample.key == "count_author_with_query") { + request.action = "count"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + } + else if (objRequestExample.key == "count_blog_with_query_and_relationships") { + request.action = "count"; + request.entity = "blog"; + request.query = { + sql: "WHERE author_alias.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + request.relations = [ "author_id { sex }" ]; + } + else if (objRequestExample.key == "delete_blog_by_id") { + request.action = "delete_by_id"; + request.entity = "blog"; + request.data = { blog_id: 4 }; + } + else if (objRequestExample.key == "delete_list_of_blog_by_id") { + request.action = "delete_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 3 }, { blog_id: 2 } ]; + } + else if (objRequestExample.key == "delete_author_by_query") { + request.action = "delete_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + } + else if (objRequestExample.key == "delete_all_comment") { + request.action = "delete_all"; + request.entity = "comment"; + } + else if (objRequestExample.key == "call_custom_query") { + request.action = "call_custom_query"; + request.query = { + sql: "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)", + params: [ + { key: ":author_id", value: "author_id_custom_query" }, + { key: ":name", value: "new author inserted by custom query" }, + { key: ":birthdate", value: "20190215" }, + { key: ":sex", value: 2 } + ] + }; + } + else if (objRequestExample.key == "call_entity_function") { + request.action = "call_entity_function"; + request.entity = "blog"; + request.fct = "helloWorld"; + request.data = { param1: "test", param2: "static fct call" }; + } + else if (objRequestExample.key == "several_requests_in_array") { + request = [ buildRequestExample(modelRequestExample.get(0)), + buildRequestExample(modelRequestExample.get(1)), + buildRequestExample(modelRequestExample.get(2)), + buildRequestExample(modelRequestExample.get(3)) ]; + } + else { + request.error = ""; + } + return request; + } + + function createGUID() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + } +} diff --git a/test/qxBlogRestApi/qt/rcc/documents/test_rest_api_qt6.qml b/test/qxBlogRestApi/qt/rcc/documents/test_rest_api_qt6.qml new file mode 100644 index 0000000..7dba4df --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/documents/test_rest_api_qt6.qml @@ -0,0 +1,513 @@ +import QtQuick +import QtQuick.Controls + +Item { + width: 1000 + height: 700 + Row { + anchors.fill: parent + spacing: 10 + anchors.leftMargin: 5 + anchors.rightMargin: 5 + Column { + width: ((parent.width - 10) * 0.5) + height: (parent.height) + spacing: 10 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "JSON Request" + font.bold: true + color: "blue" + } + Flickable { + anchors.left: parent.left + anchors.right: parent.right + height: (parent.height * 0.4) + TextArea.flickable: TextArea { + id: txtRequest + wrapMode: TextEdit.NoWrap + text: "" + background: Rectangle { + border.width: 1 + } + } + ScrollBar.vertical: ScrollBar { } + ScrollBar.horizontal: ScrollBar { } + } + Button { + anchors.left: parent.left + anchors.right: parent.right + height: 45 + onClicked: onSendRequest() + contentItem: Label { + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: "Send JSON request" + font.pointSize: 12 + font.bold: true + color: "blue" + } + } + Label { + anchors.left: parent.left + anchors.right: parent.right + text: "Here are some request examples :" + font.italic: true + color: "blue" + } + ScrollView { + width: parent.width + height: (parent.height * 0.4) + ListView { + id: lstRequestExample + anchors.fill: parent + flickableDirection: Flickable.VerticalFlick + boundsBehavior: Flickable.StopAtBounds + model: ListModel { + id: modelRequestExample + ListElement { key: "get_meta_data"; txt: " - get project meta-data (all classes)" } + ListElement { key: "fetch_all_blogs"; txt: " - fetch all blogs (as list)" } + ListElement { key: "fetch_all_blogs_as_collection"; txt: " - fetch all blogs (as collection key/value)" } + ListElement { key: "fetch_all_blogs_with_relationships"; txt: " - fetch all blogs with relationships (several levels)" } + ListElement { key: "fetch_all_blogs_with_relationships_output_format"; txt: " - fetch all blogs with relationships (several levels) and define output format" } + ListElement { key: "fetch_blog_by_id"; txt: " - fetch a single blog by id" } + ListElement { key: "fetch_blog_by_id_columns"; txt: " - fetch some columns of a single blog by id" } + ListElement { key: "fetch_list_of_blog_by_id"; txt: " - fetch list of blogs by id" } + ListElement { key: "fetch_list_of_blog_by_id_output_format"; txt: " - fetch list of blogs by id and define output format" } + ListElement { key: "fetch_authors_by_query"; txt: " - fetch authors using a query (only female)" } + ListElement { key: "fetch_authors_by_query_with_relationships"; txt: " - fetch authors with relationships using a query" } + ListElement { key: "fetch_authors_by_query_with_relationships_output_format"; txt: " - fetch authors with relationships using a query and define output format" } + ListElement { key: "insert_blog"; txt: " - insert a blog" } + ListElement { key: "insert_list_of_blog"; txt: " - insert list of blogs" } + ListElement { key: "insert_author"; txt: " - insert an author" } + ListElement { key: "insert_category"; txt: " - insert a category" } + ListElement { key: "update_blog"; txt: " - update a blog" } + ListElement { key: "update_blog_columns"; txt: " - update some columns of blog" } + ListElement { key: "update_author"; txt: " - update an author" } + ListElement { key: "update_list_of_author"; txt: " - update list of authors" } + ListElement { key: "update_category"; txt: " - update a category" } + ListElement { key: "save_blog"; txt: " - save (insert or update) a blog" } + ListElement { key: "save_list_of_blog"; txt: " - save (insert or update) list of blogs" } + ListElement { key: "save_blog_recursive"; txt: " - save (insert or update) a blog with relationships (recursively)" } + ListElement { key: "save_blog_recursive_insert"; txt: " - save (insert optimized) a blog with relationships (recursively)" } + ListElement { key: "exist_blog"; txt: " - check if a blog id exist" } + ListElement { key: "exist_list_of_blog"; txt: " - check if list of blogs id exist" } + ListElement { key: "exist_author"; txt: " - check if an author id exist" } + ListElement { key: "validate_blog"; txt: " - validate a blog instance" } + ListElement { key: "count_all_blog"; txt: " - count all blogs" } + ListElement { key: "count_author_with_query"; txt: " - count authors using a query" } + ListElement { key: "count_blog_with_query_and_relationships"; txt: " - count blogs using a query and relationships" } + ListElement { key: "delete_blog_by_id"; txt: " - delete a blog by id" } + ListElement { key: "delete_list_of_blog_by_id"; txt: " - delete list of blogs by id" } + ListElement { key: "delete_author_by_query"; txt: " - delete some authors using a query" } + ListElement { key: "delete_all_comment"; txt: " - delete all comments" } + ListElement { key: "call_custom_query"; txt: " - call custom database query or stored procedure" } + ListElement { key: "call_entity_function"; txt: " - call entity static function with signature : static QJsonValue myEntity::myFct(const QJsonValue & request)" } + ListElement { key: "several_requests_in_array"; txt: " - build several requests in array to send only 1 call to server (executed in a transaction commit/rollback)" } + } + delegate: Rectangle { + width: parent.width + height: 20 + color: ((index == lstRequestExample.currentIndex) ? "lightblue" : (((index % 2) == 0) ? "white" : "papayawhip")) + Column { Text { text: txt } } + MouseArea { + anchors.fill: parent + onClicked: lstRequestExample.currentIndex = index + } + } + highlight: Rectangle { color: "lightblue" } + onCurrentItemChanged: onRequestExampleSelected(modelRequestExample.get(lstRequestExample.currentIndex)) + Component.onCompleted : currentIndex = -1 + focus: true + } + } + } + Column { + width: ((parent.width - 10) * 0.5) + height: (parent.height) + spacing: 10 + Label { + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: "JSON Response" + font.bold: true + color: "blue" + } + Flickable { + anchors.left: parent.left + anchors.right: parent.right + height: (parent.height * 0.9) + TextArea.flickable: TextArea { + id: txtResponse + wrapMode: TextEdit.NoWrap + text: "" + background: Rectangle { + border.width: 1 + } + } + ScrollBar.vertical: ScrollBar { } + ScrollBar.horizontal: ScrollBar { } + } + } + } + + function onSendRequest() { + try { + console.log("onSendRequest() called"); + qxRestApi.clearAll(); + var response = qxRestApi.processRequest(txtRequest.text); + response = JSON.parse(response); + txtResponse.text = JSON.stringify(response, null, 3); + } + catch(exc) { + txtResponse.text = "An error occurred processing request : " + exc; + } + } + + function onRequestExampleSelected(objRequestExample) { + txtResponse.text = ""; + if (! objRequestExample) { return; } + console.log("onRequestExampleSelected() : " + objRequestExample.key + " selected"); + var request = buildRequestExample(objRequestExample); + txtRequest.text = JSON.stringify(request, null, 3); + } + + function buildRequestExample(objRequestExample) { + var request = { }; + request.request_id = createGUID(); + if (objRequestExample.key == "get_meta_data") { + request.action = "get_meta_data"; + request.entity = "*"; + } + else if (objRequestExample.key == "fetch_all_blogs") { + request.action = "fetch_all"; + request.entity = "blog"; + } + else if (objRequestExample.key == "fetch_all_blogs_as_collection") { + request.action = "fetch_all"; + request.entity = "blog"; + request.data = [ { key: "", value: "" } ] + } + else if (objRequestExample.key == "fetch_all_blogs_with_relationships") { + request.action = "fetch_all"; + request.entity = "blog"; + request.relations = [ "*->*" ]; + } + else if (objRequestExample.key == "fetch_all_blogs_with_relationships_output_format") { + request.action = "fetch_all"; + request.entity = "blog"; + request.relations = [ " { blog_text }", "author_id { name, birthdate }", "list_comment { comment_text } -> blog_id -> * <..._my_alias_suffix>" ]; + request.output_format = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text } -> blog_id -> *" ]; + } + else if (objRequestExample.key == "fetch_blog_by_id") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + } + else if (objRequestExample.key == "fetch_blog_by_id_columns") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + request.columns = [ "blog_text", "date_creation" ]; + } + else if (objRequestExample.key == "fetch_list_of_blog_by_id") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 2 }, { blog_id: 3 } ]; + } + else if (objRequestExample.key == "fetch_list_of_blog_by_id_output_format") { + request.action = "fetch_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 2 } ]; + request.relations = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text }" ]; + request.output_format = [ "{ blog_text }", "author_id { name, birthdate }", "list_comment { comment_text }" ]; + } + else if (objRequestExample.key == "fetch_authors_by_query") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + } + else if (objRequestExample.key == "fetch_authors_by_query_with_relationships") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + request.relations = [ "*" ]; + } + else if (objRequestExample.key == "fetch_authors_by_query_with_relationships_output_format") { + request.action = "fetch_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1, type: "in" } ] + }; + request.relations = [ "*" ]; + request.output_format = [ "{ birthdate, name }", "list_blog { blog_text, date_creation }" ]; + } + else if (objRequestExample.key == "insert_blog") { + request.action = "insert"; + request.entity = "blog"; + request.data = { + blog_text: "this is a new blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }; + } + else if (objRequestExample.key == "insert_list_of_blog") { + request.action = "insert"; + request.entity = "blog"; + request.data = [ + { + blog_text: "new blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }, + { + blog_text: "another blog from QxOrm REST API !", + date_creation: "2016-06-12T08:33:12", + author_id: "author_id_1" + } + ]; + } + else if (objRequestExample.key == "insert_author") { + request.action = "insert"; + request.entity = "author"; + request.data = { + author_id: "author_id_from_rest_api", + birthdate: "1978-05-11", + name: "new author created by QxOrm REST API", + sex: 1 + }; + } + else if (objRequestExample.key == "insert_category") { + request.action = "insert"; + request.entity = "category"; + request.data = { + description: "category from REST API", + name: "new_category" + }; + } + else if (objRequestExample.key == "update_blog") { + request.action = "update"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: "author_id_1" + }; + } + else if (objRequestExample.key == "update_blog_columns") { + request.action = "update"; + request.entity = "blog"; + request.data = { + blog_id: 2, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33" + }; + request.columns = [ "blog_text", "date_creation" ]; + } + else if (objRequestExample.key == "update_author") { + request.action = "update"; + request.entity = "author"; + request.data = { + author_id: "author_id_from_rest_api", + birthdate: "1992-11-03", + name: "modify author from QxOrm REST API", + sex: 0 + }; + } + else if (objRequestExample.key == "update_list_of_author") { + request.action = "update"; + request.entity = "author"; + request.data = [ + { + author_id: "author_id_from_rest_api", + birthdate: "1992-11-03", + name: "modify author from QxOrm REST API", + sex: 0 + }, + { + author_id: "author_id_1", + birthdate: "1978-12-25", + name: "modify another author from QxOrm REST API", + sex: 2 + } + ]; + } + else if (objRequestExample.key == "update_category") { + request.action = "update"; + request.entity = "category"; + request.data = { + category_id: 1, + description: "category modified by REST API", + name: "modif_category" + }; + } + else if (objRequestExample.key == "save_blog") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "modify blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: "author_id_1" + }; + } + else if (objRequestExample.key == "save_list_of_blog") { + request.action = "save"; + request.entity = "blog"; + request.data = [ + { + blog_id: 1, + blog_text: "save blog from QxOrm REST API !", + date_creation: "2018-01-30T12:42:01", + author_id: "author_id_2" + }, + { + blog_text: "save another blog from QxOrm REST API !", + date_creation: "2016-06-12T08:33:12", + author_id: "author_id_1" + } + ]; + } + else if (objRequestExample.key == "save_blog_recursive") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_id: 1, + blog_text: "save recursive blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: { + author_id: "author_id_1", + birthdate: "1965-07-21", + name: "save recursive author from QxOrm REST API", + sex: 0 + } + }; + request.save_mode = "check_insert_or_update"; + } + else if (objRequestExample.key == "save_blog_recursive_insert") { + request.action = "save"; + request.entity = "blog"; + request.data = { + blog_text: "save recursive - new blog from QxOrm REST API", + date_creation: "2013-11-25T09:56:33", + author_id: { + author_id: "author_id_save_recursive", + birthdate: "1965-07-21", + name: "save recursive (insert only) author from QxOrm REST API", + sex: 0 + } + }; + request.save_mode = "insert_only"; + } + else if (objRequestExample.key == "exist_blog") { + request.action = "exist"; + request.entity = "blog"; + request.data = { blog_id: 1 }; + } + else if (objRequestExample.key == "exist_list_of_blog") { + request.action = "exist"; + request.entity = "blog"; + request.data = [ { blog_id: 1 }, { blog_id: 999 }, { blog_id: 3 } ]; + } + else if (objRequestExample.key == "exist_author") { + request.action = "exist"; + request.entity = "author"; + request.data = { author_id: "author_id_2" }; + } + else if (objRequestExample.key == "validate_blog") { + request.action = "validate"; + request.entity = "blog"; + request.data = { blog_id: 9999, blog_text: "" }; + } + else if (objRequestExample.key == "count_all_blog") { + request.action = "count"; + request.entity = "blog"; + } + else if (objRequestExample.key == "count_author_with_query") { + request.action = "count"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + } + else if (objRequestExample.key == "count_blog_with_query_and_relationships") { + request.action = "count"; + request.entity = "blog"; + request.query = { + sql: "WHERE author_alias.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + request.relations = [ "author_id { sex }" ]; + } + else if (objRequestExample.key == "delete_blog_by_id") { + request.action = "delete_by_id"; + request.entity = "blog"; + request.data = { blog_id: 4 }; + } + else if (objRequestExample.key == "delete_list_of_blog_by_id") { + request.action = "delete_by_id"; + request.entity = "blog"; + request.data = [ { blog_id: 3 }, { blog_id: 2 } ]; + } + else if (objRequestExample.key == "delete_author_by_query") { + request.action = "delete_by_query"; + request.entity = "author"; + request.query = { + sql: "WHERE author.sex = :sex", + params: [ { key: ":sex", value: 1 } ] + }; + } + else if (objRequestExample.key == "delete_all_comment") { + request.action = "delete_all"; + request.entity = "comment"; + } + else if (objRequestExample.key == "call_custom_query") { + request.action = "call_custom_query"; + request.query = { + sql: "INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex)", + params: [ + { key: ":author_id", value: "author_id_custom_query" }, + { key: ":name", value: "new author inserted by custom query" }, + { key: ":birthdate", value: "20190215" }, + { key: ":sex", value: 2 } + ] + }; + } + else if (objRequestExample.key == "call_entity_function") { + request.action = "call_entity_function"; + request.entity = "blog"; + request.fct = "helloWorld"; + request.data = { param1: "test", param2: "static fct call" }; + } + else if (objRequestExample.key == "several_requests_in_array") { + request = [ buildRequestExample(modelRequestExample.get(0)), + buildRequestExample(modelRequestExample.get(1)), + buildRequestExample(modelRequestExample.get(2)), + buildRequestExample(modelRequestExample.get(3)) ]; + } + else { + request.error = ""; + } + return request; + } + + function createGUID() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { + var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8); + return v.toString(16); + }); + } +} diff --git a/test/qxBlogRestApi/qt/rcc/images/.gitignore b/test/qxBlogRestApi/qt/rcc/images/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/images/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogRestApi/qt/rcc/qxBlogRestApi.qrc b/test/qxBlogRestApi/qt/rcc/qxBlogRestApi.qrc new file mode 100644 index 0000000..96735df --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/qxBlogRestApi.qrc @@ -0,0 +1,14 @@ + + + documents/test_rest_api.qml + documents/test_http_server.qml + documents/test_rest_api_qt6.qml + documents/test_http_server_qt6.qml + documents/test_http_server.html + documents/logo_qxorm_and_qxee.png + documents/jquery.js + documents/cert_qxorm_ca.pem + documents/cert_qxorm_server.crt + documents/cert_qxorm_server.key + + diff --git a/test/qxBlogRestApi/qt/rcc/src/.gitignore b/test/qxBlogRestApi/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogRestApi/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogRestApi/qxBlog.pro b/test/qxBlogRestApi/qxBlog.pro new file mode 100644 index 0000000..b435b9d --- /dev/null +++ b/test/qxBlogRestApi/qxBlog.pro @@ -0,0 +1,44 @@ +include(../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _BUILDING_QX_BLOG +INCLUDEPATH += ../../../QxOrm/include/ +DESTDIR = ../../../QxOrm/test/_bin/ +LIBS += -L"../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +greaterThan(QT_MAJOR_VERSION, 4) { +QT += widgets +QT += quick +QT += qml +} else { +QT += declarative +} + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = qxBlogRestApid +LIBS += -l"QxOrmd" +} else { +TARGET = qxBlogRestApi +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/author.h +HEADERS += ./include/blog.h +HEADERS += ./include/category.h +HEADERS += ./include/comment.h + +SOURCES += ./src/author.cpp +SOURCES += ./src/blog.cpp +SOURCES += ./src/category.cpp +SOURCES += ./src/comment.cpp +SOURCES += ./src/main.cpp + +RESOURCES += ./qt/rcc/qxBlogRestApi.qrc diff --git a/test/qxBlogRestApi/release/.gitignore b/test/qxBlogRestApi/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxBlogRestApi/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxBlogRestApi/src/author.cpp b/test/qxBlogRestApi/src/author.cpp new file mode 100644 index 0000000..868ed1d --- /dev/null +++ b/test/qxBlogRestApi/src/author.cpp @@ -0,0 +1,29 @@ +#include "../include/precompiled.h" + +#include "../include/author.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(author) +QX_PERSISTABLE_CPP(author) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& author::m_id, "author_id"); + + t.data(& author::m_name, "name"); + t.data(& author::m_birthdate, "birthdate"); + t.data(& author::m_sex, "sex"); + + t.relationOneToMany(& author::m_blogX, "list_blog", "author_id"); + + t.fct_0(std::mem_fn(& author::age), "age"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +int author::age() const +{ + if (! m_birthdate.isValid()) { return -1; } + return (QDate::currentDate().year() - m_birthdate.year()); +} diff --git a/test/qxBlogRestApi/src/blog.cpp b/test/qxBlogRestApi/src/blog.cpp new file mode 100644 index 0000000..6af3c13 --- /dev/null +++ b/test/qxBlogRestApi/src/blog.cpp @@ -0,0 +1,43 @@ +#include "../include/precompiled.h" + +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(blog) +QX_PERSISTABLE_CPP(blog) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& blog::m_id, "blog_id"); + + t.data(& blog::m_text, "blog_text"); + t.data(& blog::m_dt_creation, "date_creation"); + + t.relationManyToOne(& blog::m_author, "author_id"); + t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id"); + t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", "blog_id", "category_id"); + +#ifndef _QX_NO_JSON + t.fctStatic_1(& blog::helloWorld, "helloWorld"); +#endif // _QX_NO_JSON + + QxValidatorX * pAllValidator = t.getAllValidator(); + pAllValidator->add_CustomValidator(std::mem_fn(& blog::isValid)); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) +}} + +#ifndef _QX_NO_JSON +QJsonValue blog::helloWorld(const QJsonValue & request) +{ + QJsonObject response; + response.insert("request", request); + response.insert("response", QString("Hello World !")); + return response; +} +#endif // _QX_NO_JSON + +void blog::isValid(qx::QxInvalidValueX & invalidValues) +{ + if (m_text.isEmpty()) { invalidValues.insert("'blog_text' property cannot be empty"); } +} diff --git a/test/qxBlogRestApi/src/category.cpp b/test/qxBlogRestApi/src/category.cpp new file mode 100644 index 0000000..0396cf2 --- /dev/null +++ b/test/qxBlogRestApi/src/category.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/category.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(category) +QX_PERSISTABLE_CPP(category) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& category::m_id, "category_id"); + + t.data(& category::m_name, "name"); + t.data(& category::m_desc, "description"); + + t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id"); +}} diff --git a/test/qxBlogRestApi/src/comment.cpp b/test/qxBlogRestApi/src/comment.cpp new file mode 100644 index 0000000..2357579 --- /dev/null +++ b/test/qxBlogRestApi/src/comment.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/comment.h" +#include "../include/blog.h" + +#include + +QX_REGISTER_CPP_QX_BLOG(comment) +QX_PERSISTABLE_CPP(comment) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& comment::m_id, "comment_id"); + + t.data(& comment::m_text, "comment_text"); + t.data(& comment::m_dt_create, "date_creation"); + + t.relationManyToOne(& comment::m_blog, "blog_id"); +}} diff --git a/test/qxBlogRestApi/src/main.cpp b/test/qxBlogRestApi/src/main.cpp new file mode 100644 index 0000000..d938bf7 --- /dev/null +++ b/test/qxBlogRestApi/src/main.cpp @@ -0,0 +1,490 @@ +#include "../include/precompiled.h" + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#include +#include +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#include +#include +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include + +#include "../include/blog.h" +#include "../include/author.h" +#include "../include/comment.h" +#include "../include/category.h" + +#include + +int main(int argc, char * argv[]) +{ + // Qt application + QApplication app(argc, argv); + QFile::remove("./qxBlogRestApi.sqlite"); + + // Parameters to connect to database + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlogRestApi.sqlite"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::QxSqlDatabase::getSingleton()->setFormatSqlQueryBeforeLogging(true); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + // Create all tables in database + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + // Create a list of 3 author + author_ptr author_1; author_1.reset(new author()); + author_ptr author_2; author_2.reset(new author()); + author_ptr author_3; author_3.reset(new author()); + + author_1->m_id = "author_id_1"; author_1->m_name = "author_1"; + author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate(); + author_2->m_id = "author_id_2"; author_2->m_name = "author_2"; + author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate(); + author_3->m_id = "author_id_3"; author_3->m_name = "author_3"; + author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate(); + + list_author authorX; + authorX.insert(author_1->m_id, author_1); + authorX.insert(author_2->m_id, author_2); + authorX.insert(author_3->m_id, author_3); + + // Insert list of 3 author into database + daoError = qx::dao::insert(authorX); + qAssert(qx::dao::count() == 3); + + // Clone author 2 : 'author_id_2' + author_ptr author_clone = qx::clone(* author_2); + qAssert(author_clone->m_id == "author_id_2"); + qAssert(author_clone->m_sex == author::female); + + // Create a query to fetch only female author : 'author_id_2' and 'author_id_3' + qx::QxSqlQuery query("WHERE author.sex = :sex"); + query.bind(":sex", author::female); + + list_author list_of_female_author; + daoError = qx::dao::fetch_by_query(query, list_of_female_author); + qAssert(list_of_female_author.count() == 2); + + // Dump list of female author (xml serialization) + qx::dump(list_of_female_author, false); + qx::dump(list_of_female_author, true); + + // Create 3 categories + category_ptr category_1 = category_ptr(new category()); + category_ptr category_2 = category_ptr(new category()); + category_ptr category_3 = category_ptr(new category()); + + category_1->m_name = "category_1"; category_1->m_desc = "desc_1"; + category_2->m_name = "category_2"; category_2->m_desc = "desc_2"; + category_3->m_name = "category_3"; category_3->m_desc = "desc_3"; + + { // Create a scope to destroy temporary connexion to database + + // Open a transaction to database + QSqlDatabase db = qx::QxSqlDatabase::getDatabase(); + bool bCommit = db.transaction(); + + // Insert 3 categories into database, use 'db' parameter for the transaction + daoError = qx::dao::insert(category_1, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_2, (& db)); bCommit = (bCommit && ! daoError.isValid()); + daoError = qx::dao::insert(category_3, (& db)); bCommit = (bCommit && ! daoError.isValid()); + + qAssert(bCommit); + qAssert(category_1->m_id != 0); + qAssert(category_2->m_id != 0); + qAssert(category_3->m_id != 0); + + // Terminate transaction => commit or rollback if there is error + if (bCommit) { db.commit(); } + else { db.rollback(); } + + } // End of scope : 'db' is destroyed + + // Create a blog with the class name (factory) + qx::any blog_any = qx::create("blog"); + blog_ptr blog_1; + try { blog_1 = qx::any_cast(blog_any); } + catch (...) { blog_1.reset(new blog()); } + blog_1->m_text = "blog_text_1"; + blog_1->m_dt_creation = QDateTime::currentDateTime(); + blog_1->m_author = author_1; + + // Insert 'blog_1' into database with 'save()' method + daoError = qx::dao::save(blog_1); + + // Modify 'blog_1' properties and save into database + blog_1->m_text = "update blog_text_1"; + blog_1->m_author = author_2; + daoError = qx::dao::save(blog_1); + + // Add 2 comments to 'blog_1' + comment_ptr comment_1; comment_1.reset(new comment()); + comment_ptr comment_2; comment_2.reset(new comment()); + + comment_1->m_text = "comment_1 text"; + comment_1->m_dt_create = QDateTime::currentDateTime(); + comment_1->m_blog = blog_1; + comment_2->m_text = "comment_2 text"; + comment_2->m_dt_create = QDateTime::currentDateTime(); + comment_2->m_blog = blog_1; + + daoError = qx::dao::insert(comment_1); + daoError = qx::dao::insert(comment_2); + qAssert(qx::dao::count() == 2); + + // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog' + blog_1->m_categoryX.insert(category_1->m_id, category_1); + blog_1->m_categoryX.insert(category_3->m_id, category_3); + daoError = qx::dao::save_with_relation("list_category", blog_1); + + // Fetch blog into a new variable with all relation : 'author', 'comment' and 'category' + blog_ptr blog_tmp; blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Fetch blog into a new variable with many relations using "*->*->*->*" (4 levels of relationships) + blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_relation("*->*->*->*", blog_tmp); + + qAssert(blog_tmp->m_commentX.count() == 2); + qAssert(blog_tmp->m_categoryX.count() == 2); + qAssert(blog_tmp->m_text == "update blog_text_1"); + qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2"); + + // Dump 'blog_tmp' result from database (xml serialization) + qx::dump(blog_tmp, false); + qx::dump(blog_tmp, true); + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + list_blog lstBlogComplexRelation; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "{ blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> *", lstBlogComplexRelation); + qx::dump(lstBlogComplexRelation); + qAssert(lstBlogComplexRelation.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_dt_creation.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation[0]->m_commentX[0]->m_blog); + + // Fetch relations defining columns to remove before fetching with syntax -{ col_1, col_2, etc... } + list_blog lstBlogComplexRelation2; + daoError = qx::dao::fetch_all_with_relation(QStringList() << "-{ blog_text }" << "author_id -{ name, birthdate }" << "list_comment -{ comment_text } -> blog_id -> *", lstBlogComplexRelation2); + qx::dump(lstBlogComplexRelation2); + qAssert(lstBlogComplexRelation2.size() > 0); + qAssert(lstBlogComplexRelation2[0]->m_text == ""); // Not fetched + qAssert(! lstBlogComplexRelation2[0]->m_dt_creation.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_sex != author::unknown); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_author->m_name == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX.size() > 0); + qAssert(! lstBlogComplexRelation2[0]->m_commentX[0]->m_dt_create.isNull()); // Fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_text == ""); // Not fetched + qAssert(lstBlogComplexRelation2[0]->m_commentX[0]->m_blog); + +#ifndef _QX_NO_JSON + // Custom JSON serialization process + QString customJsonFull = qx::serialization::json::to_string(blog_tmp, 1); + QString customJsonFiltered = qx::serialization::json::to_string(blog_tmp, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + qDebug("[QxOrm] custom JSON serialization process (full) : \n%s", qPrintable(customJsonFull)); + qDebug("[QxOrm] custom JSON serialization process (filtered) : \n%s", qPrintable(customJsonFiltered)); + + blog_ptr blogFromJsonFull; blogFromJsonFull.reset(new blog()); + blog_ptr blogFromJsonFiltered; blogFromJsonFiltered.reset(new blog()); + qx::serialization::json::from_string(blogFromJsonFull, customJsonFull, 1); + qx::serialization::json::from_string(blogFromJsonFiltered, customJsonFull, 1, "filter: { blog_text } | author_id { name, birthdate } | list_comment { comment_text } -> blog_id -> *"); + + qx::dump(blogFromJsonFull); + qAssert(blogFromJsonFull->m_commentX.count() == 2); + qAssert(blogFromJsonFull->m_categoryX.count() == 2); + qAssert(blogFromJsonFull->m_text == "update blog_text_1"); + qAssert(blogFromJsonFull->m_author && blogFromJsonFull->m_author->m_id == "author_id_2"); + + qx::dump(blogFromJsonFiltered); + qAssert(blogFromJsonFiltered->m_text != ""); // Fetched + qAssert(blogFromJsonFiltered->m_dt_creation.isNull()); // Not fetched + qAssert(blogFromJsonFiltered->m_author->m_sex == author::unknown); // Not fetched + qAssert(blogFromJsonFiltered->m_author->m_name != ""); // Fetched + qAssert(blogFromJsonFiltered->m_commentX.size() > 0); + qAssert(blogFromJsonFiltered->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(blogFromJsonFiltered->m_commentX[0]->m_text != ""); // Fetched + qAssert(blogFromJsonFiltered->m_commentX[0]->m_blog); +#endif // _QX_NO_JSON + + // Fetch relations defining columns to fetch with syntax { col_1, col_2, etc... } + custom table alias using syntax + custom table alias suffix using syntax <..._my_alias_suffix> + list_blog lstBlogComplexRelation3; + daoError = qx::dao::fetch_all_with_relation(QStringList() << " { blog_text }" << "author_id { name, birthdate }" << "list_comment { comment_text } -> blog_id -> * <..._my_alias_suffix>", lstBlogComplexRelation3); + qx::dump(lstBlogComplexRelation3); + qAssert(lstBlogComplexRelation3.size() > 0); + qAssert(lstBlogComplexRelation3[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_dt_creation.isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_author->m_sex == author::unknown); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_author->m_name != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX.size() > 0); + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_dt_create.isNull()); // Not fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_text != ""); // Fetched + qAssert(lstBlogComplexRelation3[0]->m_commentX[0]->m_blog); + + // Check qx::dao::save_with_relation_recursive() function + daoError = qx::dao::save_with_relation_recursive(blog_tmp); + qAssert(! daoError.isValid()); + daoError = qx::dao::save_with_relation_recursive(blog_tmp, qx::dao::save_mode::e_update_only); + qAssert(! daoError.isValid()); + + // Call 'age()' method with class name and method name (reflexion) + qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1); + qAssert(bInvokeOk); + + // Check count with relations and filter + long lBlogCountWithRelation = 0; qx_query queryBlogCountWithRelation; + daoError = qx::dao::count_with_relation(lBlogCountWithRelation, QStringList() << "author_id" << "list_comment -> blog_id -> *", queryBlogCountWithRelation); + qAssert(! daoError.isValid() && (lBlogCountWithRelation > 0)); + + // 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, false); + qx::dump(blog_isdirty, true); + + // 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, false); + qx::dump(container_isdirty, true); + + // 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].get() != NULL)) + { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); } + qx::dump(lst_blog_with_only_date_creation, false); + qx::dump(lst_blog_with_only_date_creation, true); + + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + // Call a custom SQL query or a stored procedure + qx_query testStoredProc("SELECT * FROM author"); + daoError = qx::dao::call_query(testStoredProc); + qAssert(! daoError.isValid()); + testStoredProc.dumpSqlResult(); + + // Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items) + qx_query testStoredProcBis("SELECT * FROM author"); + authorX.clear(); + daoError = qx::dao::execute_query(testStoredProcBis, authorX); + qAssert(! daoError.isValid()); qAssert(authorX.count() > 0); + qx::dump(authorX, false); + qx::dump(authorX, true); + + // Call a custom SQL query or a stored procedure and fetch automatically properties + qx_query testStoredProcThird("SELECT name, category_id FROM category"); + category_ptr category_tmp = category_ptr(new category()); + daoError = qx::dao::execute_query(testStoredProcThird, category_tmp); + qAssert(! daoError.isValid()); qAssert(category_tmp->m_id != 0); + qx::dump(category_tmp, false); + qx::dump(category_tmp, true); + + // Create several blogs + blog_tmp.reset(new blog()); + blog_tmp->m_id = blog_1->m_id; + daoError = qx::dao::fetch_by_id_with_relation("*", blog_tmp); + blog_ptr blog_cloned = qx::clone(* blog_tmp); + daoError = qx::dao::save_with_relation_recursive(blog_cloned, qx::dao::save_mode::e_insert_only); qAssert(! daoError.isValid()); + blog_cloned = qx::clone(* blog_tmp); + daoError = qx::dao::save_with_relation_recursive(blog_cloned, qx::dao::save_mode::e_insert_only); qAssert(! daoError.isValid()); + blog_cloned = qx::clone(* blog_tmp); + daoError = qx::dao::save_with_relation_recursive(blog_cloned, qx::dao::save_mode::e_insert_only); qAssert(! daoError.isValid()); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + { + qx::QxRestApi api; + + QQuickView qmlView; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/test_rest_api_qt6.qml"; +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/test_rest_api.qml"; +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + + qmlView.rootContext()->setContextProperty("qxRestApi", (& api)); + qmlView.setResizeMode(QQuickView::SizeRootObjectToView); + qmlView.setSource(QUrl(sQmlFile)); + qmlView.show(); + qApp->exec(); + } + +#ifdef _QX_ENABLE_QT_NETWORK + + { + // Just to be sure to have static files on the system + QDir appPath(QDir::currentPath()); appPath.mkdir("files"); + QFile::copy(":/documents/test_http_server.html", appPath.filePath("files/test_http_server.html")); + QFile::copy(":/documents/logo_qxorm_and_qxee.png", appPath.filePath("files/logo_qxorm_and_qxee.png")); + QFile::copy(":/documents/jquery.js", appPath.filePath("files/jquery.js")); + + // HTTP server settings + qx::service::QxConnect * serverSettings = qx::service::QxConnect::getSingleton(); + serverSettings->setKeepAlive(5000); + serverSettings->setCompressData(true); + serverSettings->setThreadCount(50); + serverSettings->setPort(9642); + +#ifndef QT_NO_SSL + if (false) // If you want to test SSL/TLS secured connection, just force this condition to 'true' + { + // Certificates created with this tutorial : https://deliciousbrains.com/ssl-certificate-authority-for-local-https-development/ + QFile::copy(":/documents/cert_qxorm_ca.pem", appPath.filePath("files/cert_qxorm_ca.pem")); + QFile::copy(":/documents/cert_qxorm_server.crt", appPath.filePath("files/cert_qxorm_server.crt")); + QFile::copy(":/documents/cert_qxorm_server.key", appPath.filePath("files/cert_qxorm_server.key")); + + QFile fileCertCA(appPath.filePath("files/cert_qxorm_ca.pem")); + fileCertCA.open(QIODevice::ReadOnly); + QList certCA; certCA << QSslCertificate(fileCertCA.readAll()); + + QFile fileCertServerPublic(appPath.filePath("files/cert_qxorm_server.crt")); + fileCertServerPublic.open(QIODevice::ReadOnly); + QSslCertificate certServerPublic(fileCertServerPublic.readAll()); + + QFile fileCertServerPrivate(appPath.filePath("files/cert_qxorm_server.key")); + fileCertServerPrivate.open(QIODevice::ReadOnly); + QSslKey certServerPrivate(fileCertServerPrivate.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "qxorm"); + + serverSettings->setSSLEnabled(true); + serverSettings->setSSLCACertificates(certCA); + serverSettings->setSSLLocalCertificate(certServerPublic); + serverSettings->setSSLPrivateKey(certServerPrivate); + } +#endif // QT_NO_SSL + + // Create a QxOrm HTTP server instance + qx::QxHttpServer httpServer; + + // Define all HTTP server routes (dispatcher) to handle requests + // Each callback is executed in a dedicated thread, so QxOrm HTTP server can handle several requests in parallel + httpServer.dispatch("GET", "/files/*", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) { + qx::QxHttpServer::buildResponseStaticFile(request, response, QDir::currentPath(), 5000); + }); + httpServer.dispatch("POST", "/qx", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) { + qx::QxHttpServer::buildResponseQxRestApi(request, response); + + // Not useful here but this is how to get a server session per user + // If this is the first time to access to session, then a cookie is created automatically and attached to the response + // Then each request sent by web browser will contain a cookie with the session id + // The session expires on server side after qx::service::QxConnect::setSessionTimeOut() milliseconds + qx::QxHttpSession_ptr session = qx::QxHttpSessionManager::getSession(request, response); + if (session) { session->set("last_request_per_user", QDateTime::currentDateTime()); } + }); + httpServer.dispatch("GET", "/params//", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) { + response.data() = "Test URL dispatch parameters :\r\n"; + response.data() += " - var1 = " + request.dispatchParams().value("var1").toByteArray() + "\r\n"; + response.data() += " - var2 = " + request.dispatchParams().value("var2").toByteArray() + "\r\n"; + }); + httpServer.dispatch("GET", "/test_big_json", [](qx::QxHttpRequest & request, qx::QxHttpResponse & response) { + // To compare with this benchmark : https://blog.binaryspaceship.com/2017/cpp-rest-api-frameworks-benchmark/ + // This is more a JSON benchmark than HTTP server benchmark (RapidJSON is faster than Qt QJson engine) + QJsonArray arr; Q_UNUSED(request); + for (int i = 0; i < 10000; ++i) + { + QJsonObject item; + item.insert("id", QString::number(i)); + item.insert("name", QString("Hello World")); + item.insert("type", QString("application")); + arr.append(item); + } + QJsonDocument doc(arr); + response.headers().insert("Content-Type", "application/json; charset=utf-8"); + response.data() = doc.toJson(QJsonDocument::Compact); + }); + + // Start HTTP server + httpServer.startServer(); + + // Open default web browser to connect to QxOrm HTTP server instance +#ifndef QT_NO_SSL + if (serverSettings->getSSLEnabled()) { QDesktopServices::openUrl(QUrl("https://localhost:9642/files/test_http_server.html")); } + else { QDesktopServices::openUrl(QUrl("http://localhost:9642/files/test_http_server.html")); } +#else // QT_NO_SSL + QDesktopServices::openUrl(QUrl("http://localhost:9642/files/test_http_server.html")); +#endif // QT_NO_SSL + + QQuickView qmlView; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/test_http_server_qt6.qml"; +#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString sQmlFile = "qrc:/documents/test_http_server.qml"; +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + + qmlView.rootContext()->setContextProperty("qxHttpServer", (& httpServer)); + qmlView.setResizeMode(QQuickView::SizeRootObjectToView); + qmlView.setSource(QUrl(sQmlFile)); + qmlView.show(); + qApp->exec(); + } + +#else // _QX_ENABLE_QT_NETWORK + + qDebug("[QxOrm] qxBlogRestApi example project : %s", "cannot start QxOrm HTTP server because _QX_ENABLE_QT_NETWORK compilation option is not defined"); + +#endif // _QX_ENABLE_QT_NETWORK + +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + qDebug("[QxOrm] %s", "qxBlogRestApi example project only works with Qt5 or +"); + +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + + return 0; +} diff --git a/test/qxClientServer/CMakeLists.txt b/test/qxClientServer/CMakeLists.txt new file mode 100644 index 0000000..5a7c01e --- /dev/null +++ b/test/qxClientServer/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxClientServer LANGUAGES CXX) + +include(../../QxOrm.cmake) + +if(_QX_ENABLE_QT_NETWORK) + +add_subdirectory(qxService/qxServiceClient) +add_subdirectory(qxService/qxServiceServer) +add_subdirectory(qxClient) +add_subdirectory(qxServer) + +else() # _QX_ENABLE_QT_NETWORK + +message(STATUS "qxClientServer project not loaded because _QX_ENABLE_QT_NETWORK option not enabled (QxOrm QxService module is disabled)") + +endif() # _QX_ENABLE_QT_NETWORK diff --git a/test/qxClientServer/qxClient/CMakeLists.txt b/test/qxClientServer/qxClient/CMakeLists.txt new file mode 100644 index 0000000..ea95b71 --- /dev/null +++ b/test/qxClientServer/qxClient/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxClient LANGUAGES CXX) + +include(../../../QxOrm.cmake) + +if(_QX_ENABLE_QT_NETWORK) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Widgets REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/main_dlg.h + ) + +set(SRCS + ./src/main_dlg.cpp + ./src/main.cpp + ) + +set(UIS + ./qt/ui/qxClient.ui + ) + +if(COMMAND qt_wrap_ui) +qt_wrap_ui(UIS_HDRS ${UIS}) +else() # (COMMAND qt_wrap_ui) +qt5_wrap_ui(UIS_HDRS ${UIS}) +endif() # (COMMAND qt_wrap_ui) + +add_executable(qxClient ${SRCS} ${HEADERS} ${UIS_HDRS}) + +target_compile_definitions(qxClient PRIVATE -D_BUILDING_QX_CLIENT) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxClient PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxClient ${QX_LIBRARIES} Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets QxOrm qxServiceClient) + +set_target_properties(qxClient PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ) + +set_target_properties(qxClient PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +else() # _QX_ENABLE_QT_NETWORK + +message(STATUS "qxClient project not loaded because _QX_ENABLE_QT_NETWORK option not enabled (QxOrm QxService module is disabled)") + +endif() # _QX_ENABLE_QT_NETWORK diff --git a/test/qxClientServer/qxClient/debug/.gitignore b/test/qxClientServer/qxClient/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxClient/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxClient/include/export.h b/test/qxClientServer/qxClient/include/export.h new file mode 100644 index 0000000..9dfb9c5 --- /dev/null +++ b/test/qxClientServer/qxClient/include/export.h @@ -0,0 +1,20 @@ +#ifndef _QX_CLIENT_EXPORT_H_ +#define _QX_CLIENT_EXPORT_H_ + +#include "../../qxService/include/export.h" + +#ifdef _BUILDING_QX_CLIENT +#define QX_CLIENT_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_CLIENT +#define QX_CLIENT_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_CLIENT + +#ifdef _BUILDING_QX_CLIENT +#define QX_REGISTER_HPP_QX_CLIENT QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_CLIENT QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_CLIENT +#define QX_REGISTER_HPP_QX_CLIENT QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_CLIENT QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_CLIENT + +#endif // _QX_CLIENT_EXPORT_H_ diff --git a/test/qxClientServer/qxClient/include/main_dlg.h b/test/qxClientServer/qxClient/include/main_dlg.h new file mode 100644 index 0000000..cab3f05 --- /dev/null +++ b/test/qxClientServer/qxClient/include/main_dlg.h @@ -0,0 +1,56 @@ +#ifndef _QX_CLIENT_MAIN_DLG_H_ +#define _QX_CLIENT_MAIN_DLG_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../qt/ui/include/ui_qxClient.h" + +#include "../../qxService/include/business_object/user.h" +#include "../../qxService/include/business_object/user_search.h" + +class main_dlg : public QWidget, private Ui::dlgClient +{ + + Q_OBJECT + +private: + + qx::service::QxClientAsync_ptr m_pDateTimeAsync; // To retrieve current server date-time without blocking GUI (async transaction) + +public: + + main_dlg(QWidget * parent = NULL) : QWidget(parent), Ui::dlgClient() { main_dlg::init(); } + virtual ~main_dlg() { ; } + +private: + + void init(); + void updateLastTransactionLog(qx::service::QxTransaction_ptr transaction); + void fillUser(user_ptr user); + user_ptr fileUser(); + +private Q_SLOTS: + + void onClickBtnDateTime(); + void onClickBtnDateTimeAsync(); + void onClickBtnAddUser(); + void onClickBtnUpdateUser(); + void onClickBtnRemoveUser(); + void onClickBtnRemoveAllUsers(); + void onClickBtnFetchUser(); + void onClickBtnGetAllUsers(); + void onClickBtnSearchUsers(); + void onDateTimeAsyncFinished(); + void onUpdateServerConnection(); + +}; + +#endif // _QX_CLIENT_MAIN_DLG_H_ diff --git a/test/qxClientServer/qxClient/include/precompiled.h b/test/qxClientServer/qxClient/include/precompiled.h new file mode 100644 index 0000000..27be75a --- /dev/null +++ b/test/qxClientServer/qxClient/include/precompiled.h @@ -0,0 +1,9 @@ +#ifndef _QX_CLIENT_PRECOMPILED_HEADER_H_ +#define _QX_CLIENT_PRECOMPILED_HEADER_H_ + +#include +#include + +#include "export.h" + +#endif // _QX_CLIENT_PRECOMPILED_HEADER_H_ diff --git a/test/qxClientServer/qxClient/qt/moc/.gitignore b/test/qxClientServer/qxClient/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxClient/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxClient/qt/rcc/src/.gitignore b/test/qxClientServer/qxClient/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxClient/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxClient/qt/ui/qxClient.ui b/test/qxClientServer/qxClient/qt/ui/qxClient.ui new file mode 100644 index 0000000..bab3b3b --- /dev/null +++ b/test/qxClientServer/qxClient/qt/ui/qxClient.ui @@ -0,0 +1,448 @@ + + + dlgClient + + + + 0 + 0 + 541 + 371 + + + + + 541 + 371 + + + + + 541 + 371 + + + + qxClient + + + + + 230 + 10 + 301 + 51 + + + + Server infos transaction + + + + + 10 + 20 + 121 + 23 + + + + Get Server DateTime + + + Get Server DateTime + + + + + + 140 + 20 + 151 + 23 + + + + Get Server DateTime Async + + + Get Server DateTime Async + + + + + + + 10 + 170 + 521 + 191 + + + + Log last client-server reply-request transaction + + + + + 10 + 20 + 501 + 161 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + QPlainTextEdit::NoWrap + + + true + + + + + + + 10 + 70 + 521 + 91 + + + + User transaction + + + + + 380 + 20 + 61 + 23 + + + + Get All Users + + + Get All + + + + + + 10 + 20 + 51 + 23 + + + + Add User + + + Add + + + + + + 70 + 20 + 61 + 23 + + + + Update User + + + Update + + + + + + 140 + 20 + 61 + 23 + + + + Remove User + + + Remove + + + + + + 210 + 20 + 81 + 23 + + + + Remove All Users + + + Remove All + + + + + + 300 + 20 + 71 + 23 + + + + Fetch User + + + Fetch + + + + + + 10 + 40 + 501 + 20 + + + + Qt::Horizontal + + + + + + 10 + 60 + 21 + 16 + + + + ID + + + ID : + + + + + + 100 + 60 + 61 + 16 + + + + First Name + + + First Name : + + + + + + 240 + 60 + 61 + 16 + + + + Last Name + + + Last Name : + + + + + + 380 + 60 + 51 + 16 + + + + Birthdate + + + Birthdate : + + + + + + 30 + 60 + 61 + 20 + + + + ID + + + + + + 160 + 60 + 71 + 20 + + + + First Name + + + + + + 300 + 60 + 71 + 20 + + + + Last Name + + + + + + 440 + 60 + 71 + 20 + + + + Birthdate + + + + + + 450 + 20 + 61 + 23 + + + + Search Users + + + Search + + + + + + + 10 + 10 + 211 + 51 + + + + Server connection + + + + + 10 + 20 + 21 + 16 + + + + Ip + + + Ip : + + + + + + 120 + 20 + 31 + 16 + + + + Port + + + Port : + + + + + + 150 + 20 + 51 + 22 + + + + Port + + + 1 + + + 32000 + + + + + + 30 + 20 + 81 + 20 + + + + Ip + + + 127.0.0.1 + + + Qt::AlignCenter + + + + + + + diff --git a/test/qxClientServer/qxClient/qt/ui/src/.gitignore b/test/qxClientServer/qxClient/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxClient/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxClient/qxClient.pro b/test/qxClientServer/qxClient/qxClient.pro new file mode 100644 index 0000000..7d3c986 --- /dev/null +++ b/test/qxClientServer/qxClient/qxClient.pro @@ -0,0 +1,39 @@ +include(../../../QxOrm.pri) + +!contains(DEFINES, _QX_ENABLE_QT_NETWORK) { +error(unable to use QxOrm QxService module : please define _QX_ENABLE_QT_NETWORK compilation option in QxOrm.pri configuration file) +} # !contains(DEFINES, _QX_ENABLE_QT_NETWORK) + +TEMPLATE = app +DEFINES += _BUILDING_QX_CLIENT +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ + +QT += gui +greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets } + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +LIBS += -L"../../../../QxOrm/lib" +LIBS += -L"../../../../QxOrm/test/_bin" + +CONFIG(debug, debug|release) { +TARGET = qxClientd +LIBS += -l"QxOrmd" +LIBS += -l"qxServiceClientd" +} else { +TARGET = qxClient +LIBS += -l"QxOrm" +LIBS += -l"qxServiceClient" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/main_dlg.h + +SOURCES += ./src/main_dlg.cpp +SOURCES += ./src/main.cpp + +FORMS += ./qt/ui/qxClient.ui diff --git a/test/qxClientServer/qxClient/release/.gitignore b/test/qxClientServer/qxClient/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxClient/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxClient/src/main.cpp b/test/qxClientServer/qxClient/src/main.cpp new file mode 100644 index 0000000..54655c9 --- /dev/null +++ b/test/qxClientServer/qxClient/src/main.cpp @@ -0,0 +1,22 @@ +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include "../include/precompiled.h" +#include "../include/main_dlg.h" + +#include + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); + + main_dlg dlg; + dlg.show(); + + return app.exec(); +} diff --git a/test/qxClientServer/qxClient/src/main_dlg.cpp b/test/qxClientServer/qxClient/src/main_dlg.cpp new file mode 100644 index 0000000..bd984c8 --- /dev/null +++ b/test/qxClientServer/qxClient/src/main_dlg.cpp @@ -0,0 +1,223 @@ +#include "../include/precompiled.h" + +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include "../include/main_dlg.h" + +#include "../../qxService/include/service/server_infos.h" +#include "../../qxService/include/service/user_service.h" + +#include + +#define QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT "dd/MM/yyyy" + +void main_dlg::init() +{ + setupUi(this); + + QObject::connect(btnDateTime, SIGNAL(clicked()), this, SLOT(onClickBtnDateTime())); + QObject::connect(btnDateTime_Async, SIGNAL(clicked()), this, SLOT(onClickBtnDateTimeAsync())); + QObject::connect(btnAddUser, SIGNAL(clicked()), this, SLOT(onClickBtnAddUser())); + QObject::connect(btnUpdateUser, SIGNAL(clicked()), this, SLOT(onClickBtnUpdateUser())); + QObject::connect(btnRemoveUser, SIGNAL(clicked()), this, SLOT(onClickBtnRemoveUser())); + QObject::connect(btnRemoveAllUser, SIGNAL(clicked()), this, SLOT(onClickBtnRemoveAllUsers())); + QObject::connect(btnFetchUser, SIGNAL(clicked()), this, SLOT(onClickBtnFetchUser())); + QObject::connect(btnGetAllUser, SIGNAL(clicked()), this, SLOT(onClickBtnGetAllUsers())); + QObject::connect(btnSearchUser, SIGNAL(clicked()), this, SLOT(onClickBtnSearchUsers())); + QObject::connect(txtIp, SIGNAL(editingFinished()), this, SLOT(onUpdateServerConnection())); + QObject::connect(spinPort, SIGNAL(editingFinished()), this, SLOT(onUpdateServerConnection())); + + txtBirthDate->setText(QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT); + txtBirthDate->setToolTip(QString("Birthdate : ") + QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT); + txtIp->setText("127.0.0.1"); + spinPort->setValue(7694); + onUpdateServerConnection(); +} + +void main_dlg::updateLastTransactionLog(qx::service::QxTransaction_ptr transaction) +{ + if (! transaction) { txtTransaction->setPlainText(""); return; } +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_XML + QString text = qx::serialization::xml::to_string(* transaction); +#else // _QX_ENABLE_BOOST_SERIALIZATION_XML + QString text = transaction->getInfos(); +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML + txtTransaction->setPlainText(text.replace("\t", " ")); + qx_bool bMsgReturn = transaction->getMessageReturn(); + if (! bMsgReturn.getValue() && ! bMsgReturn.getDesc().isEmpty()) + { QMessageBox::warning(this, "qxClient - transaction error", bMsgReturn.getDesc()); } +} + +void main_dlg::fillUser(user_ptr user) +{ + if (! user) { return; } + txtId->setText(QString::number(user->id)); + txtFirstName->setText(user->first_name); + txtLastName->setText(user->last_name); + txtBirthDate->setText(user->birth_date.toString(QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT)); +} + +user_ptr main_dlg::fileUser() +{ + user_ptr user_to_file = user_ptr(new user()); + user_to_file->id = txtId->text().toLong(); + user_to_file->first_name = txtFirstName->text(); + user_to_file->last_name = txtLastName->text(); + user_to_file->birth_date = QDateTime::fromString(txtBirthDate->text(), QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT); + return user_to_file; +} + +void main_dlg::onUpdateServerConnection() +{ + qx::service::QxConnect::getSingleton()->setIp(txtIp->text()); + qx::service::QxConnect::getSingleton()->setPort(spinPort->value()); +} + +void main_dlg::onClickBtnDateTime() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create service and call method to retrieve current server date-time + server_infos service; + service.get_current_date_time(); + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnDateTimeAsync() +{ + if (m_pDateTimeAsync) { qDebug("[QxOrm] '%s' transaction is already running", "server_infos::get_current_date_time"); return; } + // Create service and call method to retrieve current server date-time (async mode) + server_infos_ptr service = server_infos_ptr(new server_infos()); + m_pDateTimeAsync.reset(new qx::service::QxClientAsync()); + QObject::connect(m_pDateTimeAsync.get(), SIGNAL(finished()), this, SLOT(onDateTimeAsyncFinished())); + m_pDateTimeAsync->setService(service, "get_current_date_time"); + m_pDateTimeAsync->start(); +} + +void main_dlg::onDateTimeAsyncFinished() +{ + if (! m_pDateTimeAsync || ! m_pDateTimeAsync->getService()) { return; } + updateLastTransactionLog(m_pDateTimeAsync->getService()->getTransaction()); + m_pDateTimeAsync.reset(); +} + +void main_dlg::onClickBtnAddUser() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create input parameters with user to add + user_service_input_ptr input = user_service_input_ptr(new user_service_input()); + input->user = fileUser(); + // Create service to call and set input parameters + user_service service; + service.setInputParameter(input); + service.insert(); + // If transaction is ok => display user with new id added to database + user_ptr output = (service.isValidWithOutput() ? service.getOutputParameter()->user : user_ptr()); + if (output) { fillUser(output); } + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnUpdateUser() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create input parameters with user to update + user_service_input_ptr input = user_service_input_ptr(new user_service_input()); + input->user = fileUser(); + // Create service to call and set input parameters + user_service service; + service.setInputParameter(input); + service.update(); + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnRemoveUser() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create input parameters with user id to remove + user_service_input_ptr input = user_service_input_ptr(new user_service_input()); + input->id = txtId->text().toLong(); + // Create service to call and set input parameters + user_service service; + service.setInputParameter(input); + service.remove(); + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnRemoveAllUsers() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create service to call + user_service service; + service.remove_all(); + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnFetchUser() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create input parameters with user id to fetch + user_service_input_ptr input = user_service_input_ptr(new user_service_input()); + input->id = txtId->text().toLong(); + // Create service to call and set input parameters + user_service service; + service.setInputParameter(input); + service.fetch_by_id(); + // If transaction is ok => display user fetched on GUI + user_ptr output = (service.isValidWithOutput() ? service.getOutputParameter()->user : user_ptr()); + if (output) { fillUser(output); } + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnGetAllUsers() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create service to call + user_service service; + service.fetch_all(); + // If transaction is ok => display in a message box the number of users fetched from database + list_of_users_ptr output = (service.isValidWithOutput() ? service.getOutputParameter()->list_of_users : list_of_users_ptr()); + if (output) { QMessageBox::information(this, "qxClient - get all users", "database contains '" + QString::number(output->size()) + "' user(s)."); } + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onClickBtnSearchUsers() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + // Create criteria to search users + user_search_ptr criteria = user_search_ptr(new user_search()); + criteria->first_name = txtFirstName->text(); + criteria->last_name = txtLastName->text(); + criteria->birth_date = QDateTime::fromString(txtBirthDate->text(), QX_CLIENT_BIRTHDATE_QDATETIME_FORMAT); + // Create input parameters with criteria to search users + user_service_input_ptr input = user_service_input_ptr(new user_service_input()); + input->criteria = criteria; + // Create service to call and set input parameters + user_service service; + service.setInputParameter(input); + service.get_by_criteria(); + // If transaction is ok => display in a message box the number of users fetched from database + list_of_users_ptr output = (service.isValidWithOutput() ? service.getOutputParameter()->list_of_users : list_of_users_ptr()); + if (output) { QMessageBox::information(this, "qxClient - search users", "database contains '" + QString::number(output->size()) + "' user(s) with input criteria."); } + // Update transaction log + updateLastTransactionLog(service.getTransaction()); + QApplication::restoreOverrideCursor(); +} diff --git a/test/qxClientServer/qxServer/CMakeLists.txt b/test/qxClientServer/qxServer/CMakeLists.txt new file mode 100644 index 0000000..b54c86f --- /dev/null +++ b/test/qxClientServer/qxServer/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxServer LANGUAGES CXX) + +include(../../../QxOrm.cmake) + +if(_QX_ENABLE_QT_NETWORK) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Widgets REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/main_dlg.h + ) + +set(SRCS + ./src/main_dlg.cpp + ./src/main.cpp + ) + +set(UIS + ./qt/ui/qxServer.ui + ) + +set(QRCS + ./qt/rcc/_qxServer.qrc + ) + +if(COMMAND qt_wrap_ui) +qt_wrap_ui(UIS_HDRS ${UIS}) +qt_add_resources(QRCS_HDRS ${QRCS}) +else() # (COMMAND qt_wrap_ui) +qt5_wrap_ui(UIS_HDRS ${UIS}) +qt5_add_resources(QRCS_HDRS ${QRCS}) +endif() # (COMMAND qt_wrap_ui) + +add_executable(qxServer ${SRCS} ${HEADERS} ${UIS_HDRS} ${QRCS_HDRS}) + +target_compile_definitions(qxServer PRIVATE -D_BUILDING_QX_SERVER) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxServer PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxServer ${QX_LIBRARIES} Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets QxOrm qxServiceServer) + +set_target_properties(qxServer PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ) + +set_target_properties(qxServer PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) + +else() # _QX_ENABLE_QT_NETWORK + +message(STATUS "qxServer project not loaded because _QX_ENABLE_QT_NETWORK option not enabled (QxOrm QxService module is disabled)") + +endif() # _QX_ENABLE_QT_NETWORK diff --git a/test/qxClientServer/qxServer/debug/.gitignore b/test/qxClientServer/qxServer/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxServer/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxServer/include/export.h b/test/qxClientServer/qxServer/include/export.h new file mode 100644 index 0000000..1635cc1 --- /dev/null +++ b/test/qxClientServer/qxServer/include/export.h @@ -0,0 +1,20 @@ +#ifndef _QX_SERVER_EXPORT_H_ +#define _QX_SERVER_EXPORT_H_ + +#include "../../qxService/include/export.h" + +#ifdef _BUILDING_QX_SERVER +#define QX_SERVER_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_SERVER +#define QX_SERVER_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_SERVER + +#ifdef _BUILDING_QX_SERVER +#define QX_REGISTER_HPP_QX_SERVER QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_SERVER QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_SERVER +#define QX_REGISTER_HPP_QX_SERVER QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_SERVER QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_SERVER + +#endif // _QX_SERVER_EXPORT_H_ diff --git a/test/qxClientServer/qxServer/include/main_dlg.h b/test/qxClientServer/qxServer/include/main_dlg.h new file mode 100644 index 0000000..cbcc63e --- /dev/null +++ b/test/qxClientServer/qxServer/include/main_dlg.h @@ -0,0 +1,47 @@ +#ifndef _QX_SERVER_MAIN_DLG_H_ +#define _QX_SERVER_MAIN_DLG_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../qt/ui/include/ui_qxServer.h" + +class main_dlg : public QWidget, private Ui::dlgServer +{ + + Q_OBJECT + +private: + + qx::service::QxThreadPool_ptr m_pThreadPool; // Server thread pool to receive all requests + qx::QxDaoAsync m_daoAsync; // To test to run queries in a different thread + +public: + + main_dlg(QWidget * parent = NULL) : QWidget(parent), Ui::dlgServer() { main_dlg::init(); } + virtual ~main_dlg() { ; } + +private: + + void init(); + void loadServices(); + +private Q_SLOTS: + + void onClickStartStop(); + void onCboIndexChanged(int index); + void onError(const QString & err, qx::service::QxTransaction_ptr transaction); + void onServerIsRunning(bool bIsRunning, qx::service::QxServer * pServer); + void onTransactionFinished(qx::service::QxTransaction_ptr transaction); + void onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams); + +}; + +#endif // _QX_SERVER_MAIN_DLG_H_ diff --git a/test/qxClientServer/qxServer/include/precompiled.h b/test/qxClientServer/qxServer/include/precompiled.h new file mode 100644 index 0000000..4520c67 --- /dev/null +++ b/test/qxClientServer/qxServer/include/precompiled.h @@ -0,0 +1,9 @@ +#ifndef _QX_SERVER_PRECOMPILED_HEADER_H_ +#define _QX_SERVER_PRECOMPILED_HEADER_H_ + +#include +#include + +#include "export.h" + +#endif // _QX_SERVER_PRECOMPILED_HEADER_H_ diff --git a/test/qxClientServer/qxServer/qt/moc/.gitignore b/test/qxClientServer/qxServer/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxServer/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxServer/qt/rcc/_qxServer.qrc b/test/qxClientServer/qxServer/qt/rcc/_qxServer.qrc new file mode 100644 index 0000000..1a3433a --- /dev/null +++ b/test/qxClientServer/qxServer/qt/rcc/_qxServer.qrc @@ -0,0 +1 @@ + ./stop.png ./run.png \ No newline at end of file diff --git a/test/qxClientServer/qxServer/qt/rcc/run.png b/test/qxClientServer/qxServer/qt/rcc/run.png new file mode 100644 index 0000000..49a7838 Binary files /dev/null and b/test/qxClientServer/qxServer/qt/rcc/run.png differ diff --git a/test/qxClientServer/qxServer/qt/rcc/stop.png b/test/qxClientServer/qxServer/qt/rcc/stop.png new file mode 100644 index 0000000..646acf9 Binary files /dev/null and b/test/qxClientServer/qxServer/qt/rcc/stop.png differ diff --git a/test/qxClientServer/qxServer/qt/ui/qxServer.ui b/test/qxClientServer/qxServer/qt/ui/qxServer.ui new file mode 100644 index 0000000..10afa1a --- /dev/null +++ b/test/qxClientServer/qxServer/qt/ui/qxServer.ui @@ -0,0 +1,325 @@ + + + dlgServer + + + + 0 + 0 + 552 + 392 + + + + + 552 + 392 + + + + + 552 + 392 + + + + qxServer + + + + + 10 + 310 + 531 + 71 + + + + Log last server error + + + + + 10 + 20 + 511 + 41 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 170 + 0 + 0 + + + + + + + + + 112 + 111 + 113 + + + + + + + + Qt::ScrollBarAlwaysOn + + + true + + + + + + + 10 + 10 + 531 + 81 + + + + Server parameters + + + + + 180 + 15 + 81 + 16 + + + + Thread Count + + + Thread Count : + + + + + + 10 + 50 + 91 + 16 + + + + Serialization Type + + + Serialization Type : + + + + + + 110 + 50 + 51 + 20 + + + + Serialization Type + + + + + + 10 + 20 + 81 + 16 + + + + Port Number + + + Port Number : + + + + + + 110 + 20 + 51 + 22 + + + + Port Number + + + 1 + + + 32000 + + + + + + 180 + 40 + 101 + 17 + + + + Compress Data + + + Compress Data + + + + + + 330 + 20 + 111 + 51 + + + + + 75 + true + + + + Start Server / +Stop Server + + + + + + 320 + 10 + 3 + 61 + + + + Qt::Vertical + + + + + + 450 + 20 + 71 + 51 + + + + [ is running ? ] + + + Qt::AlignCenter + + + + + + 260 + 15 + 51 + 22 + + + + Thread Count + + + 1 + + + 999 + + + + + + 180 + 55 + 101 + 17 + + + + Encrypt Data + + + Encrypt Data + + + + + + + 10 + 100 + 531 + 201 + + + + Log last client-server reply-request transaction + + + + + 10 + 20 + 511 + 171 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOn + + + QPlainTextEdit::NoWrap + + + true + + + + + + + diff --git a/test/qxClientServer/qxServer/qt/ui/src/.gitignore b/test/qxClientServer/qxServer/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxServer/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxServer/qxServer.pro b/test/qxClientServer/qxServer/qxServer.pro new file mode 100644 index 0000000..43ee5f9 --- /dev/null +++ b/test/qxClientServer/qxServer/qxServer.pro @@ -0,0 +1,41 @@ +include(../../../QxOrm.pri) + +!contains(DEFINES, _QX_ENABLE_QT_NETWORK) { +error(unable to use QxOrm QxService module : please define _QX_ENABLE_QT_NETWORK compilation option in QxOrm.pri configuration file) +} # !contains(DEFINES, _QX_ENABLE_QT_NETWORK) + +TEMPLATE = app +DEFINES += _BUILDING_QX_SERVER +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ + +QT += gui +greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets } + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +LIBS += -L"../../../../QxOrm/lib" +LIBS += -L"../../../../QxOrm/test/_bin" + +CONFIG(debug, debug|release) { +TARGET = qxServerd +LIBS += -l"QxOrmd" +LIBS += -l"qxServiceServerd" +} else { +TARGET = qxServer +LIBS += -l"QxOrm" +LIBS += -l"qxServiceServer" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/main_dlg.h + +SOURCES += ./src/main_dlg.cpp +SOURCES += ./src/main.cpp + +FORMS += ./qt/ui/qxServer.ui + +RESOURCES += ./qt/rcc/_qxServer.qrc diff --git a/test/qxClientServer/qxServer/release/.gitignore b/test/qxClientServer/qxServer/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxServer/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxServer/src/main.cpp b/test/qxClientServer/qxServer/src/main.cpp new file mode 100644 index 0000000..54655c9 --- /dev/null +++ b/test/qxClientServer/qxServer/src/main.cpp @@ -0,0 +1,22 @@ +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include "../include/precompiled.h" +#include "../include/main_dlg.h" + +#include + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); + + main_dlg dlg; + dlg.show(); + + return app.exec(); +} diff --git a/test/qxClientServer/qxServer/src/main_dlg.cpp b/test/qxClientServer/qxServer/src/main_dlg.cpp new file mode 100644 index 0000000..2eb6fdc --- /dev/null +++ b/test/qxClientServer/qxServer/src/main_dlg.cpp @@ -0,0 +1,132 @@ +#include "../include/precompiled.h" + +#include "../include/main_dlg.h" + +#include "../../qxService/include/service/server_infos.h" +#include "../../qxService/include/dao/user_manager.h" + +#include + +void main_dlg::init() +{ + setupUi(this); + + QObject::connect(btnStartStop, SIGNAL(clicked()), this, SLOT(onClickStartStop())); + QObject::connect(cboSerializationType, SIGNAL(currentIndexChanged(int)), this, SLOT(onCboIndexChanged(int))); + QObject::connect((& m_daoAsync), SIGNAL(queryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr)), this, SLOT(onQueryFinished(const QSqlError &, qx::dao::detail::QxDaoAsyncParams_ptr))); + + cboSerializationType->addItem("0- serialization_binary", QVariant((int)qx::service::QxConnect::serialization_binary)); + cboSerializationType->addItem("1- serialization_xml", QVariant((int)qx::service::QxConnect::serialization_xml)); + cboSerializationType->addItem("2- serialization_text", QVariant((int)qx::service::QxConnect::serialization_text)); + cboSerializationType->addItem("3- serialization_portable_binary", QVariant((int)qx::service::QxConnect::serialization_portable_binary)); + cboSerializationType->addItem("4- serialization_wide_binary", QVariant((int)qx::service::QxConnect::serialization_wide_binary)); + cboSerializationType->addItem("5- serialization_wide_xml", QVariant((int)qx::service::QxConnect::serialization_wide_xml)); + cboSerializationType->addItem("6- serialization_wide_text", QVariant((int)qx::service::QxConnect::serialization_wide_text)); + cboSerializationType->addItem("7- serialization_polymorphic_binary", QVariant((int)qx::service::QxConnect::serialization_polymorphic_binary)); + cboSerializationType->addItem("8- serialization_polymorphic_xml", QVariant((int)qx::service::QxConnect::serialization_polymorphic_xml)); + cboSerializationType->addItem("9- serialization_polymorphic_text", QVariant((int)qx::service::QxConnect::serialization_polymorphic_text)); + cboSerializationType->addItem("10- serialization_qt", QVariant((int)qx::service::QxConnect::serialization_qt)); + cboSerializationType->addItem("11- serialization_json", QVariant((int)qx::service::QxConnect::serialization_json)); + cboSerializationType->setCurrentIndex(cboSerializationType->findData(QVariant((int)qx::service::QxConnect::getSingleton()->getSerializationType()))); + + spinPortNumber->setValue(7694); + spinThreadCount->setValue(qx::service::QxConnect::getSingleton()->getThreadCount()); + onServerIsRunning(false, NULL); + onClickStartStop(); +} + +void main_dlg::loadServices() +{ + // Required to be sure to load all services dll : create a dummy service for each dll + // It is also possible to create a 'plugin system' to load services + server_infos dummy_01; Q_UNUSED(dummy_01); +} + +void main_dlg::onClickStartStop() +{ + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + if (m_pThreadPool) + { + m_pThreadPool.reset(); + txtError->setPlainText(""); + txtTransaction->setPlainText(""); + onServerIsRunning(false, NULL); + } + else + { + qx::service::QxConnect::getSingleton()->setPort(spinPortNumber->value()); + qx::service::QxConnect::getSingleton()->setThreadCount(spinThreadCount->value()); + qx::service::QxConnect::getSingleton()->setSerializationType((qx::service::QxConnect::serialization_type)(cboSerializationType->itemData(cboSerializationType->currentIndex()).toInt())); + qx::service::QxConnect::getSingleton()->setCompressData(chkCompressData->isChecked()); + qx::service::QxConnect::getSingleton()->setEncryptData(chkEncryptData->isChecked()); + + m_pThreadPool.reset(new qx::service::QxThreadPool()); + QObject::connect(m_pThreadPool.get(), SIGNAL(error(const QString &, qx::service::QxTransaction_ptr)), this, SLOT(onError(const QString &, qx::service::QxTransaction_ptr))); + QObject::connect(m_pThreadPool.get(), SIGNAL(serverIsRunning(bool, qx::service::QxServer *)), this, SLOT(onServerIsRunning(bool, qx::service::QxServer *))); + QObject::connect(m_pThreadPool.get(), SIGNAL(transactionFinished(qx::service::QxTransaction_ptr)), this, SLOT(onTransactionFinished(qx::service::QxTransaction_ptr))); + m_pThreadPool->start(); + } + QApplication::restoreOverrideCursor(); +} + +void main_dlg::onCboIndexChanged(int index) +{ + if (index < 0) { cboSerializationType->setToolTip(""); } + else { cboSerializationType->setToolTip(cboSerializationType->itemText(cboSerializationType->currentIndex())); } + + // To test to run queries in a different thread : see 'onQueryFinished()' method to see the result + if (cboSerializationType->count() <= 1) { return; } + user_manager dummy; Q_UNUSED(dummy); // To init database parameters + qx_query query = "SELECT * FROM user"; + m_daoAsync.asyncCallQuery(query); +} + +void main_dlg::onServerIsRunning(bool bIsRunning, qx::service::QxServer * pServer) +{ + Q_UNUSED(pServer); + imgIsRunning->setText(""); + imgIsRunning->setPixmap(bIsRunning ? QPixmap(":/run") : QPixmap(":/stop")); + btnStartStop->setText(bIsRunning ? "Stop Server" : "Start Server"); + + spinPortNumber->setEnabled(! bIsRunning); + spinThreadCount->setEnabled(! bIsRunning); + cboSerializationType->setEnabled(! bIsRunning); + chkCompressData->setEnabled(! bIsRunning); + chkEncryptData->setEnabled(! bIsRunning); +} + +void main_dlg::onError(const QString & err, qx::service::QxTransaction_ptr transaction) +{ + if (err.isEmpty()) { txtError->setPlainText(""); return; } + QString errText = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm") + " : " + err; +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_XML + if (transaction) { errText += QString("\r\n\r\n") + qx::serialization::xml::to_string(* transaction); } +#else // _QX_ENABLE_BOOST_SERIALIZATION_XML + if (transaction) { errText += QString("\r\n\r\n") + transaction->getInfos(); } +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML + txtError->setPlainText(errText.replace("\t", " ")); +} + +void main_dlg::onTransactionFinished(qx::service::QxTransaction_ptr transaction) +{ + if (! transaction) { txtTransaction->setPlainText(""); return; } +#ifdef _QX_ENABLE_BOOST_SERIALIZATION_XML + QString text = qx::serialization::xml::to_string(* transaction); +#else // _QX_ENABLE_BOOST_SERIALIZATION_XML + QString text = transaction->getInfos(); +#endif // _QX_ENABLE_BOOST_SERIALIZATION_XML + txtTransaction->setPlainText(text.replace("\t", " ")); +} + +void main_dlg::onQueryFinished(const QSqlError & daoError, qx::dao::detail::QxDaoAsyncParams_ptr pDaoParams) +{ + if (! pDaoParams) { return; } + qx::QxSqlQuery query = pDaoParams->query; + if (! daoError.isValid()) { /* ... */ } + // If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method + qx::IxPersistable_ptr ptr = pDaoParams->pInstance; + // If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method + qx::IxPersistableCollection_ptr lst = pDaoParams->pListOfInstances; + // etc... + Q_UNUSED(query); Q_UNUSED(ptr); Q_UNUSED(lst); +} diff --git a/test/qxClientServer/qxService/debug/debug_client/.gitignore b/test/qxClientServer/qxService/debug/debug_client/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/debug/debug_client/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/debug/debug_server/.gitignore b/test/qxClientServer/qxService/debug/debug_server/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/debug/debug_server/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/include/business_object/user.h b/test/qxClientServer/qxService/include/business_object/user.h new file mode 100644 index 0000000..0e4b7ab --- /dev/null +++ b/test/qxClientServer/qxService/include/business_object/user.h @@ -0,0 +1,23 @@ +#ifndef _QX_SERVICE_BO_USER_H_ +#define _QX_SERVICE_BO_USER_H_ + +class QX_SERVICE_DLL_EXPORT user +{ +public: +// -- contructor, virtual destructor + user() : id(0) { ; } + virtual ~user() { ; } +// -- properties + long id; + QString first_name; + QString last_name; + QDateTime birth_date; +}; + +QX_REGISTER_HPP_QX_SERVICE(user, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr user_ptr; +typedef qx::QxCollection list_of_users; +typedef std::shared_ptr list_of_users_ptr; + +#endif // _QX_SERVICE_BO_USER_H_ diff --git a/test/qxClientServer/qxService/include/business_object/user_search.h b/test/qxClientServer/qxService/include/business_object/user_search.h new file mode 100644 index 0000000..fa98602 --- /dev/null +++ b/test/qxClientServer/qxService/include/business_object/user_search.h @@ -0,0 +1,23 @@ +#ifndef _QX_SERVICE_BO_USER_SEARCH_H_ +#define _QX_SERVICE_BO_USER_SEARCH_H_ + +class QX_SERVICE_DLL_EXPORT user_search +{ +public: +// -- contructor, virtual destructor + user_search() { ; } + virtual ~user_search() { ; } +// -- properties + QString first_name; + QString last_name; + QDateTime birth_date; +// -- methods + bool empty() const + { return (first_name.isEmpty() && last_name.isEmpty() && ! birth_date.isValid()); } +}; + +QX_REGISTER_HPP_QX_SERVICE(user_search, qx::trait::no_base_class_defined, 0) + +typedef std::shared_ptr user_search_ptr; + +#endif // _QX_SERVICE_BO_USER_SEARCH_H_ diff --git a/test/qxClientServer/qxService/include/dao/user_manager.h b/test/qxClientServer/qxService/include/dao/user_manager.h new file mode 100644 index 0000000..0997e06 --- /dev/null +++ b/test/qxClientServer/qxService/include/dao/user_manager.h @@ -0,0 +1,25 @@ +#ifndef _QX_SERVICE_MODE_CLIENT +#ifndef _QX_SERVICE_USER_MANAGER_H_ +#define _QX_SERVICE_USER_MANAGER_H_ + +#include "../../include/business_object/user.h" +#include "../../include/business_object/user_search.h" + +class QX_SERVICE_DLL_EXPORT user_manager +{ +public: + user_manager() { user_manager::init_database(); } + ~user_manager() { ; } + QSqlError insert(user_ptr p); + QSqlError update(user_ptr p); + QSqlError remove(user_ptr p); + QSqlError remove_all(); + QSqlError fetch_by_id(user_ptr p); + QSqlError fetch_all(list_of_users_ptr lst); + QSqlError get_by_criteria(user_search_ptr criteria, list_of_users_ptr lst); +private: + static void init_database(); +}; + +#endif // _QX_SERVICE_USER_MANAGER_H_ +#endif // _QX_SERVICE_MODE_CLIENT diff --git a/test/qxClientServer/qxService/include/export.h b/test/qxClientServer/qxService/include/export.h new file mode 100644 index 0000000..75930e0 --- /dev/null +++ b/test/qxClientServer/qxService/include/export.h @@ -0,0 +1,18 @@ +#ifndef _QX_SERVICE_EXPORT_H_ +#define _QX_SERVICE_EXPORT_H_ + +#ifdef _BUILDING_QX_SERVICE +#define QX_SERVICE_DLL_EXPORT QX_DLL_EXPORT_HELPER +#else // _BUILDING_QX_SERVICE +#define QX_SERVICE_DLL_EXPORT QX_DLL_IMPORT_HELPER +#endif // _BUILDING_QX_SERVICE + +#ifdef _BUILDING_QX_SERVICE +#define QX_REGISTER_HPP_QX_SERVICE QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_SERVICE QX_REGISTER_CPP_EXPORT_DLL +#else // _BUILDING_QX_SERVICE +#define QX_REGISTER_HPP_QX_SERVICE QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_SERVICE QX_REGISTER_CPP_IMPORT_DLL +#endif // _BUILDING_QX_SERVICE + +#endif // _QX_SERVICE_EXPORT_H_ diff --git a/test/qxClientServer/qxService/include/precompiled.h b/test/qxClientServer/qxService/include/precompiled.h new file mode 100644 index 0000000..d030c41 --- /dev/null +++ b/test/qxClientServer/qxService/include/precompiled.h @@ -0,0 +1,9 @@ +#ifndef _QX_SERVICE_PRECOMPILED_HEADER_H_ +#define _QX_SERVICE_PRECOMPILED_HEADER_H_ + +#include +#include + +#include "export.h" + +#endif // _QX_SERVICE_PRECOMPILED_HEADER_H_ diff --git a/test/qxClientServer/qxService/include/service/server_infos.h b/test/qxClientServer/qxService/include/service/server_infos.h new file mode 100644 index 0000000..b05ed33 --- /dev/null +++ b/test/qxClientServer/qxService/include/service/server_infos.h @@ -0,0 +1,34 @@ +#ifndef _QX_SERVICE_SERVER_INFOS_H_ +#define _QX_SERVICE_SERVER_INFOS_H_ + +/* -- Service Input Parameters -- */ + +class QX_SERVICE_DLL_EXPORT server_infos_input : public qx::service::IxParameter +{ QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP(server_infos_input); }; + +QX_REGISTER_HPP_QX_SERVICE(server_infos_input, qx::service::IxParameter, 0) +typedef std::shared_ptr server_infos_input_ptr; + +/* -- Service Output Parameters -- */ + +class QX_SERVICE_DLL_EXPORT server_infos_output : public qx::service::IxParameter +{ public: QDateTime current_date_time; QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP(server_infos_output); }; + +QX_REGISTER_HPP_QX_SERVICE(server_infos_output, qx::service::IxParameter, 0) +typedef std::shared_ptr server_infos_output_ptr; + +/* -- Service Definition -- */ + +typedef qx::service::QxService server_infos_base_class; +class QX_SERVICE_DLL_EXPORT server_infos : public server_infos_base_class +{ +public: + server_infos() : server_infos_base_class("server_infos") { ; } + virtual ~server_infos() { ; } + void get_current_date_time(); +}; + +QX_REGISTER_HPP_QX_SERVICE(server_infos, qx::service::IxService, 0) +typedef std::shared_ptr server_infos_ptr; + +#endif // _QX_SERVICE_SERVER_INFOS_H_ diff --git a/test/qxClientServer/qxService/include/service/user_service.h b/test/qxClientServer/qxService/include/service/user_service.h new file mode 100644 index 0000000..2bf2b7f --- /dev/null +++ b/test/qxClientServer/qxService/include/service/user_service.h @@ -0,0 +1,56 @@ +#ifndef _QX_SERVICE_USER_SERVICE_H_ +#define _QX_SERVICE_USER_SERVICE_H_ + +#include "../../include/business_object/user.h" +#include "../../include/business_object/user_search.h" + +/* -- Service Input Parameters -- */ + +class QX_SERVICE_DLL_EXPORT user_service_input : public qx::service::IxParameter +{ + QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP(user_service_input); +public: + user_service_input() : id(0) { ; } + virtual ~user_service_input() { ; } + long id; + user_ptr user; + user_search_ptr criteria; +}; + +QX_REGISTER_HPP_QX_SERVICE(user_service_input, qx::service::IxParameter, 0) +typedef std::shared_ptr user_service_input_ptr; + +/* -- Service Output Parameters -- */ + +class QX_SERVICE_DLL_EXPORT user_service_output : public qx::service::IxParameter +{ + QX_SERVICE_IX_PARAMETER_SERIALIZATION_HPP(user_service_output); +public: + user_ptr user; + list_of_users_ptr list_of_users; +}; + +QX_REGISTER_HPP_QX_SERVICE(user_service_output, qx::service::IxParameter, 0) +typedef std::shared_ptr user_service_output_ptr; + +/* -- Service Definition -- */ + +typedef qx::service::QxService user_service_base_class; +class QX_SERVICE_DLL_EXPORT user_service : public user_service_base_class +{ +public: + user_service() : user_service_base_class("user_service") { ; } + virtual ~user_service() { ; } + void insert(); + void update(); + void remove(); + void remove_all(); + void fetch_by_id(); + void fetch_all(); + void get_by_criteria(); +}; + +QX_REGISTER_HPP_QX_SERVICE(user_service, qx::service::IxService, 0) +typedef std::shared_ptr user_service_ptr; + +#endif // _QX_SERVICE_USER_SERVICE_H_ diff --git a/test/qxClientServer/qxService/qt/moc/.gitignore b/test/qxClientServer/qxService/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/qt/rcc/src/.gitignore b/test/qxClientServer/qxService/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/qt/ui/include/.gitignore b/test/qxClientServer/qxService/qt/ui/include/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/qt/ui/include/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/qt/ui/src/.gitignore b/test/qxClientServer/qxService/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/qxService.pri b/test/qxClientServer/qxService/qxService.pri new file mode 100644 index 0000000..6cbb6ed --- /dev/null +++ b/test/qxClientServer/qxService/qxService.pri @@ -0,0 +1,37 @@ +include(../../../QxOrm.pri) + +!contains(DEFINES, _QX_ENABLE_QT_NETWORK) { +error(unable to use QxOrm QxService module : please define _QX_ENABLE_QT_NETWORK compilation option in QxOrm.pri configuration file) +} # !contains(DEFINES, _QX_ENABLE_QT_NETWORK) + +TEMPLATE = lib +CONFIG += dll +DEFINES += _BUILDING_QX_SERVICE +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ +LIBS += -L"../../../../QxOrm/lib" + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +CONFIG(debug, debug|release) { +LIBS += -l"QxOrmd" +} else { +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/service/server_infos.h +HEADERS += ./include/service/user_service.h +HEADERS += ./include/business_object/user.h +HEADERS += ./include/business_object/user_search.h +HEADERS += ./include/dao/user_manager.h + +SOURCES += ./src/service/server_infos.cpp +SOURCES += ./src/service/user_service.cpp +SOURCES += ./src/business_object/user.cpp +SOURCES += ./src/business_object/user_search.cpp +SOURCES += ./src/dao/user_manager.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxClientServer/qxService/qxServiceClient.pro b/test/qxClientServer/qxService/qxServiceClient.pro new file mode 100644 index 0000000..6a93543 --- /dev/null +++ b/test/qxClientServer/qxService/qxServiceClient.pro @@ -0,0 +1,11 @@ +include(./qxService.pri) + +DEFINES += _QX_SERVICE_MODE_CLIENT + +CONFIG(debug, debug|release) { +OBJECTS_DIR = ./debug/debug_client/ +TARGET = qxServiceClientd +} else { +OBJECTS_DIR = ./release/release_client/ +TARGET = qxServiceClient +} # CONFIG(debug, debug|release) diff --git a/test/qxClientServer/qxService/qxServiceClient/CMakeLists.txt b/test/qxClientServer/qxService/qxServiceClient/CMakeLists.txt new file mode 100644 index 0000000..27de8b4 --- /dev/null +++ b/test/qxClientServer/qxService/qxServiceClient/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxServiceClient LANGUAGES CXX) + +include(../../../../QxOrm.cmake) + +if(_QX_ENABLE_QT_NETWORK) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ../include/precompiled.h + ../include/export.h + ../include/service/server_infos.h + ../include/service/user_service.h + ../include/business_object/user.h + ../include/business_object/user_search.h + ../include/dao/user_manager.h + ) + +set(SRCS + ../src/service/server_infos.cpp + ../src/service/user_service.cpp + ../src/business_object/user.cpp + ../src/business_object/user_search.cpp + ../src/dao/user_manager.cpp + ../src/main.cpp + ) + +add_library(qxServiceClient SHARED ${SRCS} ${HEADERS}) + +target_compile_definitions(qxServiceClient PRIVATE -D_BUILDING_QX_SERVICE -D_QX_SERVICE_MODE_CLIENT) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxServiceClient PRIVATE ../include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxServiceClient ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxServiceClient PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ) + +else() # _QX_ENABLE_QT_NETWORK + +message(STATUS "qxServiceClient project not loaded because _QX_ENABLE_QT_NETWORK option not enabled (QxOrm QxService module is disabled)") + +endif() # _QX_ENABLE_QT_NETWORK diff --git a/test/qxClientServer/qxService/qxServiceServer.pro b/test/qxClientServer/qxService/qxServiceServer.pro new file mode 100644 index 0000000..6465cfc --- /dev/null +++ b/test/qxClientServer/qxService/qxServiceServer.pro @@ -0,0 +1,9 @@ +include(./qxService.pri) + +CONFIG(debug, debug|release) { +OBJECTS_DIR = ./debug/debug_server/ +TARGET = qxServiceServerd +} else { +OBJECTS_DIR = ./release/release_server/ +TARGET = qxServiceServer +} # CONFIG(debug, debug|release) diff --git a/test/qxClientServer/qxService/qxServiceServer/CMakeLists.txt b/test/qxClientServer/qxService/qxServiceServer/CMakeLists.txt new file mode 100644 index 0000000..9a6de6e --- /dev/null +++ b/test/qxClientServer/qxService/qxServiceServer/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxServiceServer LANGUAGES CXX) + +include(../../../../QxOrm.cmake) + +if(_QX_ENABLE_QT_NETWORK) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ../include/precompiled.h + ../include/export.h + ../include/service/server_infos.h + ../include/service/user_service.h + ../include/business_object/user.h + ../include/business_object/user_search.h + ../include/dao/user_manager.h + ) + +set(SRCS + ../src/service/server_infos.cpp + ../src/service/user_service.cpp + ../src/business_object/user.cpp + ../src/business_object/user_search.cpp + ../src/dao/user_manager.cpp + ../src/main.cpp + ) + +add_library(qxServiceServer SHARED ${SRCS} ${HEADERS}) + +target_compile_definitions(qxServiceServer PRIVATE -D_BUILDING_QX_SERVICE) + +if(COMMAND target_precompile_headers) + target_precompile_headers(qxServiceServer PRIVATE ../include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(qxServiceServer ${QX_LIBRARIES} QxOrm) + +set_target_properties(qxServiceServer PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../../_bin" + ) + +else() # _QX_ENABLE_QT_NETWORK + +message(STATUS "qxServiceServer project not loaded because _QX_ENABLE_QT_NETWORK option not enabled (QxOrm QxService module is disabled)") + +endif() # _QX_ENABLE_QT_NETWORK diff --git a/test/qxClientServer/qxService/release/release_client/.gitignore b/test/qxClientServer/qxService/release/release_client/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/release/release_client/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/release/release_server/.gitignore b/test/qxClientServer/qxService/release/release_server/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxClientServer/qxService/release/release_server/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxClientServer/qxService/src/business_object/user.cpp b/test/qxClientServer/qxService/src/business_object/user.cpp new file mode 100644 index 0000000..3c312ed --- /dev/null +++ b/test/qxClientServer/qxService/src/business_object/user.cpp @@ -0,0 +1,17 @@ +#include "../../include/precompiled.h" + +#include "../../include/business_object/user.h" + +#include + +QX_REGISTER_CPP_QX_SERVICE(user) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.id(& user::id, "id"); + + t.data(& user::first_name, "first_name"); + t.data(& user::last_name, "last_name"); + t.data(& user::birth_date, "birth_date"); +}} diff --git a/test/qxClientServer/qxService/src/business_object/user_search.cpp b/test/qxClientServer/qxService/src/business_object/user_search.cpp new file mode 100644 index 0000000..eb639f6 --- /dev/null +++ b/test/qxClientServer/qxService/src/business_object/user_search.cpp @@ -0,0 +1,15 @@ +#include "../../include/precompiled.h" + +#include "../../include/business_object/user_search.h" + +#include + +QX_REGISTER_CPP_QX_SERVICE(user_search) + +namespace qx { +template <> void register_class(QxClass & t) +{ + t.data(& user_search::first_name, "first_name"); + t.data(& user_search::last_name, "last_name"); + t.data(& user_search::birth_date, "birth_date"); +}} diff --git a/test/qxClientServer/qxService/src/dao/user_manager.cpp b/test/qxClientServer/qxService/src/dao/user_manager.cpp new file mode 100644 index 0000000..2845879 --- /dev/null +++ b/test/qxClientServer/qxService/src/dao/user_manager.cpp @@ -0,0 +1,90 @@ +#ifndef _QX_SERVICE_MODE_CLIENT + +#include "../../include/precompiled.h" + +#include "../../include/dao/user_manager.h" + +#include + +void user_manager::init_database() +{ + static QMutex mutex; + static bool bInitDone = false; + if (bInitDone) { return; } + QMutexLocker locker(& mutex); + if (bInitDone) { return; } + bInitDone = true; + + QFile::remove("./user.db"); + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("user.db"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::dao::create_table(); +} + +QSqlError user_manager::insert(user_ptr p) +{ + if (! p) { return QSqlError("cannot insert user : invalid user (null pointer)", "", QSqlError::UnknownError); } + if (p->first_name.trimmed().isEmpty()) { return QSqlError("cannot insert user : 'first_name' is required", "", QSqlError::UnknownError); } + if (p->last_name.trimmed().isEmpty()) { return QSqlError("cannot insert user : 'last_name' is required", "", QSqlError::UnknownError); } + return qx::dao::insert(p); +} + +QSqlError user_manager::update(user_ptr p) +{ + if (! p) { return QSqlError("cannot update user : invalid user (null pointer)", "", QSqlError::UnknownError); } + if (p->id == 0) { return QSqlError("cannot update user : 'id' is required", "", QSqlError::UnknownError); } + if (p->first_name.trimmed().isEmpty()) { return QSqlError("cannot update user : 'first_name' is required", "", QSqlError::UnknownError); } + if (p->last_name.trimmed().isEmpty()) { return QSqlError("cannot update user : 'last_name' is required", "", QSqlError::UnknownError); } + if (! qx::dao::exist(p)) { return QSqlError("cannot update user : user doesn't exist in database", "", QSqlError::UnknownError); } + return qx::dao::update(p); +} + +QSqlError user_manager::remove(user_ptr p) +{ + if (! p) { return QSqlError("cannot remove user : invalid user (null pointer)", "", QSqlError::UnknownError); } + if (p->id == 0) { return QSqlError("cannot remove user : 'id' is required", "", QSqlError::UnknownError); } + if (! qx::dao::exist(p)) { return QSqlError("cannot remove user : user doesn't exist in database", "", QSqlError::UnknownError); } + return qx::dao::delete_by_id(p); +} + +QSqlError user_manager::remove_all() +{ + return qx::dao::delete_all(); +} + +QSqlError user_manager::fetch_by_id(user_ptr p) +{ + if (! p) { return QSqlError("cannot fetch user : invalid user (null pointer)", "", QSqlError::UnknownError); } + if (p->id == 0) { return QSqlError("cannot fetch user : 'id' is required", "", QSqlError::UnknownError); } + if (! qx::dao::exist(p)) { return QSqlError("cannot fetch user : user doesn't exist in database", "", QSqlError::UnknownError); } + return qx::dao::fetch_by_id(p); +} + +QSqlError user_manager::fetch_all(list_of_users_ptr lst) +{ + return qx::dao::fetch_all(lst); +} + +QSqlError user_manager::get_by_criteria(user_search_ptr criteria, list_of_users_ptr lst) +{ + if (! criteria) { return QSqlError("cannot search users : invalid criteria (null pointer)", "", QSqlError::UnknownError); } + if (criteria->empty()) { return fetch_all(lst); } + + QString sql = "WHERE "; + if (! criteria->first_name.isEmpty()) { sql += "user.first_name LIKE :first_name AND "; } + if (! criteria->last_name.isEmpty()) { sql += "user.last_name LIKE :last_name AND "; } + if (criteria->birth_date.isValid()) { sql += "user.birth_date = :birth_date AND "; } + sql = sql.left(sql.count() - 5); // Remove last " AND " + + qx::QxSqlQuery query(sql); + if (! criteria->first_name.isEmpty()) { query.bind(":first_name", criteria->first_name); } + if (! criteria->last_name.isEmpty()) { query.bind(":last_name", criteria->last_name); } + if (criteria->birth_date.isValid()) { query.bind(":birth_date", criteria->birth_date); } + + return qx::dao::fetch_by_query(query, lst); +} + +#endif // _QX_SERVICE_MODE_CLIENT diff --git a/test/qxClientServer/qxService/src/main.cpp b/test/qxClientServer/qxService/src/main.cpp new file mode 100644 index 0000000..3420dba --- /dev/null +++ b/test/qxClientServer/qxService/src/main.cpp @@ -0,0 +1,20 @@ +#ifdef _MSC_VER + +#include + +extern "C" +int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReservedt */) +{ + (void)hInstance; + switch (dwReason) + { + case DLL_PROCESS_ATTACH: ::OutputDebugStringA("qxService.DllMain() ---> DLL_PROCESS_ATTACH\n"); break; + case DLL_PROCESS_DETACH: ::OutputDebugStringA("qxService.DllMain() ---> DLL_PROCESS_DETACH\n"); break; + case DLL_THREAD_ATTACH: ::OutputDebugStringA("qxService.DllMain() ---> DLL_THREAD_ATTACH\n"); break; + case DLL_THREAD_DETACH: ::OutputDebugStringA("qxService.DllMain() ---> DLL_THREAD_DETACH\n"); break; + } + + return 1; +} + +#endif // _MSC_VER diff --git a/test/qxClientServer/qxService/src/service/server_infos.cpp b/test/qxClientServer/qxService/src/service/server_infos.cpp new file mode 100644 index 0000000..51588bc --- /dev/null +++ b/test/qxClientServer/qxService/src/service/server_infos.cpp @@ -0,0 +1,42 @@ +#include "../../include/precompiled.h" + +#include "../../include/service/server_infos.h" + +#include + +QX_REGISTER_CPP_QX_SERVICE(server_infos_input) +QX_REGISTER_CPP_QX_SERVICE(server_infos_output) +QX_REGISTER_CPP_QX_SERVICE(server_infos) + +QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP(server_infos_input) +QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP(server_infos_output) + +namespace qx { + +template <> void register_class(QxClass & t) +{ Q_UNUSED(t); } + +template <> void register_class(QxClass & t) +{ t.data(& server_infos_output::current_date_time, "current_date_time"); } + +template <> void register_class(QxClass & t) +{ t.fct_0(std::mem_fn(& server_infos::get_current_date_time), "get_current_date_time"); } // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + +} // namespace qx + +#ifdef _QX_SERVICE_MODE_CLIENT + +void server_infos::get_current_date_time() +{ qx::service::execute_client(this, "get_current_date_time"); } + +#else // _QX_SERVICE_MODE_CLIENT + +void server_infos::get_current_date_time() +{ + server_infos_output_ptr output = server_infos_output_ptr(new server_infos_output()); + output->current_date_time = QDateTime::currentDateTime(); + setOutputParameter(output); + setMessageReturn(true); +} + +#endif // _QX_SERVICE_MODE_CLIENT diff --git a/test/qxClientServer/qxService/src/service/user_service.cpp b/test/qxClientServer/qxService/src/service/user_service.cpp new file mode 100644 index 0000000..1ed5e71 --- /dev/null +++ b/test/qxClientServer/qxService/src/service/user_service.cpp @@ -0,0 +1,133 @@ +#include "../../include/precompiled.h" + +#include "../../include/service/user_service.h" + +#include "../../include/dao/user_manager.h" + +#include + +QX_REGISTER_CPP_QX_SERVICE(user_service_input) +QX_REGISTER_CPP_QX_SERVICE(user_service_output) +QX_REGISTER_CPP_QX_SERVICE(user_service) + +QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP(user_service_input) +QX_SERVICE_IX_PARAMETER_SERIALIZATION_CPP(user_service_output) + +namespace qx { + +template <> void register_class(QxClass & t) +{ + t.data(& user_service_input::id, "id"); + t.data(& user_service_input::user, "user"); + t.data(& user_service_input::criteria, "criteria"); +} + +template <> void register_class(QxClass & t) +{ + t.data(& user_service_output::user, "user"); + t.data(& user_service_output::list_of_users, "list_of_users"); +} + +template <> void register_class(QxClass & t) +{ + t.fct_0(std::mem_fn(& user_service::insert), "insert"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + t.fct_0(std::mem_fn(& user_service::update), "update"); + t.fct_0(std::mem_fn(& user_service::remove), "remove"); + t.fct_0(std::mem_fn(& user_service::remove_all), "remove_all"); + t.fct_0(std::mem_fn(& user_service::fetch_by_id), "fetch_by_id"); + t.fct_0(std::mem_fn(& user_service::fetch_all), "fetch_all"); + t.fct_0(std::mem_fn(& user_service::get_by_criteria), "get_by_criteria"); +} + +} // namespace qx + +#ifdef _QX_SERVICE_MODE_CLIENT + +void user_service::insert() { qx::service::execute_client(this, "insert"); } +void user_service::update() { qx::service::execute_client(this, "update"); } +void user_service::remove() { qx::service::execute_client(this, "remove"); } +void user_service::remove_all() { qx::service::execute_client(this, "remove_all"); } +void user_service::fetch_by_id() { qx::service::execute_client(this, "fetch_by_id"); } +void user_service::fetch_all() { qx::service::execute_client(this, "fetch_all"); } +void user_service::get_by_criteria() { qx::service::execute_client(this, "get_by_criteria"); } + +#else // _QX_SERVICE_MODE_CLIENT + +void user_service::insert() +{ + user_service_input_ptr input = getInputParameter(); + if (! input) { setMessageReturn(0, "invalid input parameter to call service 'user_service::insert()'"); return; } + QSqlError err = user_manager().insert(input->user); + if (err.isValid()) { setMessageReturn(0, err.text()); return; } + user_service_output_ptr output = user_service_output_ptr(new user_service_output()); + output->user = input->user; + setOutputParameter(output); + setMessageReturn(true); +} + +void user_service::update() +{ + user_service_input_ptr input = getInputParameter(); + if (! input) { setMessageReturn(0, "invalid input parameter to call service 'user_service::update()'"); return; } + QSqlError err = user_manager().update(input->user); + if (err.isValid()) { setMessageReturn(0, err.text()); } + else { setMessageReturn(true); } +} + +void user_service::remove() +{ + user_service_input_ptr input = getInputParameter(); + if (! input) { setMessageReturn(0, "invalid input parameter to call service 'user_service::remove()'"); return; } + user_ptr user_tmp = user_ptr(new user()); + user_tmp->id = input->id; + QSqlError err = user_manager().remove(user_tmp); + if (err.isValid()) { setMessageReturn(0, err.text()); } + else { setMessageReturn(true); } +} + +void user_service::remove_all() +{ + QSqlError err = user_manager().remove_all(); + if (err.isValid()) { setMessageReturn(0, err.text()); } + else { setMessageReturn(true); } +} + +void user_service::fetch_by_id() +{ + user_service_input_ptr input = getInputParameter(); + if (! input) { setMessageReturn(0, "invalid input parameter to call service 'user_service::fetch_by_id()'"); return; } + user_ptr user_output = user_ptr(new user()); + user_output->id = input->id; + QSqlError err = user_manager().fetch_by_id(user_output); + if (err.isValid()) { setMessageReturn(0, err.text()); return; } + user_service_output_ptr output = user_service_output_ptr(new user_service_output()); + output->user = user_output; + setOutputParameter(output); + setMessageReturn(true); +} + +void user_service::fetch_all() +{ + list_of_users_ptr list_of_users_output = list_of_users_ptr(new list_of_users()); + QSqlError err = user_manager().fetch_all(list_of_users_output); + if (err.isValid()) { setMessageReturn(0, err.text()); return; } + user_service_output_ptr output = user_service_output_ptr(new user_service_output()); + output->list_of_users = list_of_users_output; + setOutputParameter(output); + setMessageReturn(true); +} + +void user_service::get_by_criteria() +{ + user_service_input_ptr input = getInputParameter(); + if (! input) { setMessageReturn(0, "invalid input parameter to call service 'user_service::get_by_criteria()'"); return; } + list_of_users_ptr list_of_users_output = list_of_users_ptr(new list_of_users()); + QSqlError err = user_manager().get_by_criteria(input->criteria, list_of_users_output); + if (err.isValid()) { setMessageReturn(0, err.text()); return; } + user_service_output_ptr output = user_service_output_ptr(new user_service_output()); + output->list_of_users = list_of_users_output; + setOutputParameter(output); + setMessageReturn(true); +} + +#endif // _QX_SERVICE_MODE_CLIENT diff --git a/test/qxClientServer/qxService/tools/build_debug.bat b/test/qxClientServer/qxService/tools/build_debug.bat new file mode 100644 index 0000000..12466c4 --- /dev/null +++ b/test/qxClientServer/qxService/tools/build_debug.bat @@ -0,0 +1,4 @@ +qmake %QXORM_QMAKE_PARAMS% "./qxServiceClient.pro" +nmake debug +qmake %QXORM_QMAKE_PARAMS% "./qxServiceServer.pro" +nmake debug diff --git a/test/qxClientServer/qxService/tools/build_release.bat b/test/qxClientServer/qxService/tools/build_release.bat new file mode 100644 index 0000000..9339ef4 --- /dev/null +++ b/test/qxClientServer/qxService/tools/build_release.bat @@ -0,0 +1,4 @@ +qmake %QXORM_QMAKE_PARAMS% "./qxServiceClient.pro" +nmake release +qmake %QXORM_QMAKE_PARAMS% "./qxServiceServer.pro" +nmake release diff --git a/test/qxClientServer/qxService/tools/clean_debug.bat b/test/qxClientServer/qxService/tools/clean_debug.bat new file mode 100644 index 0000000..e2007d2 --- /dev/null +++ b/test/qxClientServer/qxService/tools/clean_debug.bat @@ -0,0 +1,4 @@ +cd "./debug/" +del /F /S /Q "./*.*" +cd "../" +del /F /S /Q "./vc90.pdb" diff --git a/test/qxClientServer/qxService/tools/clean_release.bat b/test/qxClientServer/qxService/tools/clean_release.bat new file mode 100644 index 0000000..e85cbe4 --- /dev/null +++ b/test/qxClientServer/qxService/tools/clean_release.bat @@ -0,0 +1,2 @@ +cd "./release/" +del /F /S /Q "./*.*" diff --git a/test/qxDllSample/CMakeLists.txt b/test/qxDllSample/CMakeLists.txt new file mode 100644 index 0000000..aafcf2d --- /dev/null +++ b/test/qxDllSample/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.1) + +project(qxDllSample LANGUAGES CXX) + +add_subdirectory(dll1) +add_subdirectory(dll2) +add_subdirectory(exe) diff --git a/test/qxDllSample/dll1/CMakeLists.txt b/test/qxDllSample/dll1/CMakeLists.txt new file mode 100644 index 0000000..bda5a27 --- /dev/null +++ b/test/qxDllSample/dll1/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 3.1) + +project(dll1 LANGUAGES CXX) + +include(../../../QxOrm.cmake) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/CPerson.h + ./include/TestQtProperty.h + ./include/QxPersistable.h + ) + +set(SRCS + ./qx/CPerson.qx.cpp + ./src/CPerson.cpp + ./src/TestQtProperty.cpp + ./src/QxPersistable.cpp + ./src/main.cpp + ) + +add_library(dll1 SHARED ${SRCS} ${HEADERS}) + +target_compile_definitions(dll1 PRIVATE -D_QX_BUILDING_DLL1) + +if(COMMAND target_precompile_headers) + target_precompile_headers(dll1 PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(dll1 ${QX_LIBRARIES} QxOrm) + +set_target_properties(dll1 PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ) diff --git a/test/qxDllSample/dll1/debug/.gitignore b/test/qxDllSample/dll1/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/dll1.pro b/test/qxDllSample/dll1/dll1.pro new file mode 100644 index 0000000..1430d54 --- /dev/null +++ b/test/qxDllSample/dll1/dll1.pro @@ -0,0 +1,38 @@ +include(../../../QxOrm.pri) + +TEMPLATE = lib +CONFIG += dll +DEFINES += _QX_BUILDING_DLL1 +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +CONFIG(debug, debug|release) { +TARGET = dll1d +} else { +TARGET = dll1 +} # CONFIG(debug, debug|release) + +LIBS += -L"../../../../QxOrm/lib" + +CONFIG(debug, debug|release) { +LIBS += -l"QxOrmd" +} else { +LIBS += -l"QxOrm" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/CPerson.h +HEADERS += ./include/TestQtProperty.h +HEADERS += ./include/QxPersistable.h + +SOURCES += ./qx/CPerson.qx.cpp + +SOURCES += ./src/CPerson.cpp +SOURCES += ./src/TestQtProperty.cpp +SOURCES += ./src/QxPersistable.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxDllSample/dll1/include/CPerson.h b/test/qxDllSample/dll1/include/CPerson.h new file mode 100644 index 0000000..b30c549 --- /dev/null +++ b/test/qxDllSample/dll1/include/CPerson.h @@ -0,0 +1,66 @@ +#ifndef _QX_CLASS_PERSON_H_ +#define _QX_CLASS_PERSON_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +namespace qx { +namespace test { + +class QX_DLL1_EXPORT CPerson : public QObject +{ + + Q_OBJECT + QX_REGISTER_FRIEND_CLASS(qx::test::CPerson) + +public: + + enum sex { male, female, unknown }; + +protected: + + long m_lPersonId; + QString m_sFirstName; + QString m_sLastName; + double m_dDouble; + sex m_eSex; + +public: + + CPerson() : QObject(), m_lPersonId(0), m_sFirstName("toto"), m_dDouble(4.5678), m_eSex(unknown) { ; } + CPerson(long lId) : QObject(), m_lPersonId(lId), m_sFirstName("toto"), m_dDouble(4.5678), m_eSex(unknown) { ; } + virtual ~CPerson() { ; } + + long getPersonId() const { return m_lPersonId; } + QString getFirstName() const { return m_sFirstName; } + QString getLastName() const { return m_sLastName; } + double getDouble() const { return m_dDouble; } + sex getSex() const { return m_eSex; } + + void setPersonId(long l) { m_lPersonId = l; } + void setFirstName(const QString & s) { m_sFirstName = s; } + void setLastName(const QString & s) { m_sLastName = s; } + void setDouble(double d) { m_dDouble = d; } + void setSex(sex e) { m_eSex = e; } + + static int testStaticFct(const QString & s); + +private: + + void isValid(qx::QxInvalidValueX & invalidValues); + +}; + +} // namespace test +} // namespace qx + +QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0, qx_test_CPerson) + +#endif // _QX_CLASS_PERSON_H_ diff --git a/test/qxDllSample/dll1/include/QxPersistable.h b/test/qxDllSample/dll1/include/QxPersistable.h new file mode 100644 index 0000000..736abdd --- /dev/null +++ b/test/qxDllSample/dll1/include/QxPersistable.h @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** 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_PERSISTABLE_H_ +#define _QX_PERSISTABLE_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +namespace qx +{ + + class QxPersistable; + + namespace dao + { + namespace detail + { + + template <> + struct QxDao_Trigger; + + } // namespace detail + } // namespace dao + + /*! + * \brief qx::QxPersistable : super base class for persistent classes with many features and methods to override (be careful, don't forget to use QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros for each derived class) + */ + class QX_DLL1_EXPORT QxPersistable : public QObject, public qx::IxPersistable + { + + Q_OBJECT + QX_REGISTER_FRIEND_CLASS(qx::QxPersistable) + QX_PERSISTABLE_HPP(qx::QxPersistable) + + Q_PROPERTY(long qxId READ qxGetId WRITE qxSetId) + Q_PROPERTY(QDateTime qxDateCreation READ qxGetDateCreation WRITE qxSetDateCreation) + Q_PROPERTY(QDateTime qxDateModification READ qxGetDateModification WRITE qxSetDateModification) + + friend struct qx::dao::detail::QxDao_Trigger; + + protected: + long m_qxId; //!< Id of current instance stored into database + qx::QxDateTimeNeutral m_qxDateCreation; //!< Creation date-time automatically calculated before INSERT query + qx::QxDateTimeNeutral m_qxDateModification; //!< Modification date-time automatically calculated before INSERT and UPDATE queries + + public: + QxPersistable(); + virtual ~QxPersistable(); + + long qxGetId() const; + QDateTime qxGetDateCreation() const; + QDateTime qxGetDateModification() const; + + void qxSetId(long l); + void qxSetDateCreation(const QDateTime &dt); + void qxSetDateModification(const QDateTime &dt); + + protected: + // -- List of useful protected methods to override into derived class -- // + + virtual void qxIsValid(qx::QxInvalidValueX &invalidValues); + + virtual void qxOnBeforeInsert(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnBeforeUpdate(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnBeforeDelete(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnBeforeFetch(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnAfterInsert(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnAfterUpdate(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnAfterDelete(qx::dao::detail::IxDao_Helper *dao); + virtual void qxOnAfterFetch(qx::dao::detail::IxDao_Helper *dao); + + private: + void qxIsValidInternal(qx::QxInvalidValueX &invalidValues); + + Q_SIGNALS: + + void qxOnBeforeInsert(qx::QxPersistable *p); + void qxOnBeforeUpdate(qx::QxPersistable *p); + void qxOnBeforeDelete(qx::QxPersistable *p); + void qxOnBeforeFetch(qx::QxPersistable *p); + void qxOnAfterInsert(qx::QxPersistable *p); + void qxOnAfterUpdate(qx::QxPersistable *p); + void qxOnAfterDelete(qx::QxPersistable *p); + void qxOnAfterFetch(qx::QxPersistable *p); + + public: + // -- List of useful public methods available from 'qx::IxPersistable' interface (using QX_PERSISTABLE_HPP() and QX_PERSISTABLE_CPP() macros) -- // + + /* + virtual long qxCount(const qx::QxSqlQuery & query = qx::QxSqlQuery(), QSqlDatabase * pDatabase = NULL, const QStringList & relation = QStringList()); + virtual QSqlError qxFetchById(const QVariant & id = QVariant(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxFetchAll(qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxFetchByQuery(const qx::QxSqlQuery & query, qx::IxCollection & list, const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxInsert(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false); + virtual QSqlError qxUpdate(const qx::QxSqlQuery & query = qx::QxSqlQuery(), const QStringList & columns = QStringList(), const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false); + virtual QSqlError qxSave(const QStringList & relation = QStringList(), QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxDeleteById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false); + virtual QSqlError qxDeleteAll(QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxDeleteByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxDestroyById(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL, bool bUseExecBatch = false); + virtual QSqlError qxDestroyAll(QSqlDatabase * pDatabase = NULL); + virtual QSqlError qxDestroyByQuery(const qx::QxSqlQuery & query, QSqlDatabase * pDatabase = NULL); + virtual qx_bool qxExist(const QVariant & id = QVariant(), QSqlDatabase * pDatabase = NULL); + virtual qx::QxInvalidValueX qxValidate(const QStringList & groups = QStringList()); + virtual qx::IxPersistableCollection_ptr qxNewPersistableCollection(bool bAsList = false) const; + virtual qx::IxClass * qxClass() const; + */ + }; + + typedef std::shared_ptr QxPersistable_ptr; + +} // namespace qx + +QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::QxPersistable, QObject, 0, qx_QxPersistable) + +namespace qx +{ + namespace dao + { + namespace detail + { + + template <> + struct QxDao_Trigger + { + + static inline void onBeforeInsert(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnBeforeInsert(dao); + } + } + static inline void onBeforeUpdate(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnBeforeUpdate(dao); + } + } + static inline void onBeforeDelete(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnBeforeDelete(dao); + } + } + static inline void onBeforeFetch(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnBeforeFetch(dao); + } + } + static inline void onAfterInsert(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnAfterInsert(dao); + } + } + static inline void onAfterUpdate(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnAfterUpdate(dao); + } + } + static inline void onAfterDelete(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnAfterDelete(dao); + } + } + static inline void onAfterFetch(qx::QxPersistable *t, qx::dao::detail::IxDao_Helper *dao) + { + if (t) + { + t->qxOnAfterFetch(dao); + } + } + }; + + } // namespace detail + } // namespace dao +} // namespace qx + +#endif // _QX_PERSISTABLE_H_ diff --git a/test/qxDllSample/dll1/include/TestQtProperty.h b/test/qxDllSample/dll1/include/TestQtProperty.h new file mode 100644 index 0000000..61134e9 --- /dev/null +++ b/test/qxDllSample/dll1/include/TestQtProperty.h @@ -0,0 +1,53 @@ +#ifndef _QX_TEST_QT_META_PROPERTY_H_ +#define _QX_TEST_QT_META_PROPERTY_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +class QX_DLL1_EXPORT TestQtProperty : public QObject +{ + + Q_OBJECT + Q_PROPERTY(int id READ id WRITE setId) + Q_PROPERTY(long number READ number WRITE setNumber) + Q_PROPERTY(QString desc READ desc WRITE setDesc) + Q_PROPERTY(QDateTime birthDate READ birthDate WRITE setBirthDate) + Q_PROPERTY(QVariant photo READ photo WRITE setPhoto) + +protected: + + int m_id; + long m_number; + QString m_desc; + QDateTime m_birthDate; + QVariant m_photo; + +public: + + TestQtProperty() : QObject(), m_id(0), m_number(0) { ; } + virtual ~TestQtProperty() { ; } + + int id() const { return m_id; } + long number() const { return m_number; } + QString desc() const { return m_desc; } + QDateTime birthDate() const { return m_birthDate; } + QVariant photo() const { return m_photo; } + + void setId(int i) { m_id = i; } + void setNumber(long l) { m_number = l; } + void setDesc(const QString & s) { m_desc = s; } + void setBirthDate(const QDateTime & dt) { m_birthDate = dt; } + void setPhoto(const QVariant & v) { m_photo = v; } + +}; + +QX_REGISTER_HPP_QX_DLL1(TestQtProperty, QObject, 0) + +#endif // _QX_TEST_QT_META_PROPERTY_H_ diff --git a/test/qxDllSample/dll1/include/export.h b/test/qxDllSample/dll1/include/export.h new file mode 100644 index 0000000..f5ac083 --- /dev/null +++ b/test/qxDllSample/dll1/include/export.h @@ -0,0 +1,26 @@ +#ifndef _QX_DLL1_EXPORT_H_ +#define _QX_DLL1_EXPORT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_BUILDING_DLL1 +#define QX_DLL1_EXPORT QX_DLL_EXPORT_HELPER +#else // _QX_BUILDING_DLL1 +#define QX_DLL1_EXPORT QX_DLL_IMPORT_HELPER +#endif // _QX_BUILDING_DLL1 + +#ifdef _QX_BUILDING_DLL1 +#define QX_REGISTER_HPP_QX_DLL1 QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_DLL1 QX_REGISTER_CPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1 QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL1 QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL +#else // _QX_BUILDING_DLL1 +#define QX_REGISTER_HPP_QX_DLL1 QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_DLL1 QX_REGISTER_CPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1 QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL1 QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL +#endif // _QX_BUILDING_DLL1 + +#endif // _QX_DLL1_EXPORT_H_ diff --git a/test/qxDllSample/dll1/include/precompiled.h b/test/qxDllSample/dll1/include/precompiled.h new file mode 100644 index 0000000..0ac20db --- /dev/null +++ b/test/qxDllSample/dll1/include/precompiled.h @@ -0,0 +1,12 @@ +#ifndef _QX_DLL1_PRECOMPILED_HEADER_H_ +#define _QX_DLL1_PRECOMPILED_HEADER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include "../include/export.h" + +#endif // _QX_DLL1_PRECOMPILED_HEADER_H_ diff --git a/test/qxDllSample/dll1/qt/moc/.gitignore b/test/qxDllSample/dll1/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/qt/rcc/src/.gitignore b/test/qxDllSample/dll1/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/qt/ui/include/.gitignore b/test/qxDllSample/dll1/qt/ui/include/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/qt/ui/include/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/qt/ui/src/.gitignore b/test/qxDllSample/dll1/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/qx/CPerson.qx.cpp b/test/qxDllSample/dll1/qx/CPerson.qx.cpp new file mode 100644 index 0000000..eda0a8d --- /dev/null +++ b/test/qxDllSample/dll1/qx/CPerson.qx.cpp @@ -0,0 +1,70 @@ +#include "../include/precompiled.h" + +#include "../include/CPerson.h" + +#include + +void myGlobalValidator_1(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues); +void myGlobalValidator_2(const QString & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues); + +QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL1(qx::test::CPerson, qx_test_CPerson) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + IxFunction * pFct = NULL; + IxValidator * pValidator = NULL; + + t.setName("CPerson"); + + pData = t.id(& qx::test::CPerson::m_lPersonId, "idPerson", 0); + + pData = t.data(& qx::test::CPerson::m_sFirstName, "firstName", 0); + pData = t.data(& qx::test::CPerson::m_sLastName, "lastName", 0); + pData = t.data(& qx::test::CPerson::m_dDouble, "double", 0); + pData = t.data(& qx::test::CPerson::m_eSex, "sex", 0); + + pFct = t.fct_0(std::mem_fn(& qx::test::CPerson::getPersonId), "fct_getPersonId"); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + pFct = t.fct_0(std::mem_fn(& qx::test::CPerson::getFirstName), "fct_getFirstName"); + pFct = t.fct_1(std::mem_fn(& qx::test::CPerson::setPersonId), "fct_setPersonId"); + + pFct = t.fctStatic_1(& qx::test::CPerson::testStaticFct, "fct_testStaticFct"); + + QxValidatorX * pAllValidator = t.getAllValidator(); + if (! pAllValidator) { qAssert(false); return; } + pValidator = pAllValidator->add_NotEmpty("firstName", "a person must have a firstname"); + pValidator = pAllValidator->add_NotEmpty("lastName"); + pValidator = pAllValidator->add_MinDecimal("double", 0.5, "'double' field must be greater than or equal to '0.5'"); + pValidator = pAllValidator->add_MaxDecimal("double", 103.19); + pValidator = pAllValidator->add_CustomValidator(std::mem_fn(& qx::test::CPerson::isValid)); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + pValidator = pAllValidator->add_CustomValidator_QVariant(& myGlobalValidator_1, "firstName"); + pValidator = pAllValidator->add_CustomValidator_DataType(& myGlobalValidator_2, "lastName"); +}} + +// ******************************************************************************************************** +// ******************************************************************************************************** + +// Example of global functions 'myGlobalValidator_1' and 'myGlobalValidator_2' used by 'QxValidator' module +// Those functions will be called automatically by validator engine of QxOrm library : +// - when you try to insert or update using 'qx::dao::xxx' functions +// - when you call 'qx::validate()' function + +void myGlobalValidator_1(const QVariant & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues) +{ + // Here you can test the value (converted to QVariant type) + // If an invalid value is detected, just add a message into 'invalidValues' collection + + Q_UNUSED(value); Q_UNUSED(validator); Q_UNUSED(invalidValues); +} + +void myGlobalValidator_2(const QString & value, const qx::IxValidator * validator, qx::QxInvalidValueX & invalidValues) +{ + // Here you can test the value (with its real type, in this example, the data-member is a 'QString' type) + // If an invalid value is detected, just add a message into 'invalidValues' collection + + Q_UNUSED(value); Q_UNUSED(validator); Q_UNUSED(invalidValues); +} + +// ******************************************************************************************************** +// ******************************************************************************************************** diff --git a/test/qxDllSample/dll1/release/.gitignore b/test/qxDllSample/dll1/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll1/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll1/src/CPerson.cpp b/test/qxDllSample/dll1/src/CPerson.cpp new file mode 100644 index 0000000..f74ceb4 --- /dev/null +++ b/test/qxDllSample/dll1/src/CPerson.cpp @@ -0,0 +1,31 @@ +#include "../include/precompiled.h" + +#include "../include/CPerson.h" + +#include + +namespace qx { +namespace test { + +void CPerson::isValid(qx::QxInvalidValueX & invalidValues) +{ + // This method is called automatically by 'QxValidator' module (validator engine of QxOrm library) : + // - when you try to insert or update using 'qx::dao::xxx' functions + // - when you call 'qx::validate()' function + + // For registration, see 'pAllValidator->add_CustomValidator(& qx::test::CPerson::isValid);' into 'qx::register_class()' function + + // Here, you can verify some values of your instance + // If a value is not valid, you must add an invalid value into the collection 'invalidValues' + + if ((m_sFirstName == "admin") || (m_sLastName == "admin")) + { invalidValues.insert("you cannot set 'admin' for the name of a person"); } +} + +int CPerson::testStaticFct(const QString & s) +{ + return s.toInt(); +} + +} // namespace test +} // namespace qx diff --git a/test/qxDllSample/dll1/src/QxPersistable.cpp b/test/qxDllSample/dll1/src/QxPersistable.cpp new file mode 100644 index 0000000..d4a5dd7 --- /dev/null +++ b/test/qxDllSample/dll1/src/QxPersistable.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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 +** +****************************************************************************/ + +#include "../include/precompiled.h" + +#include "../include/QxPersistable.h" + +#include + +QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL1(qx::QxPersistable, qx_QxPersistable) + +namespace qx +{ + + template <> + void register_class(QxClass &t) + { + t.setPropertyBag("QX_NOT_PERSISTABLE", "1"); + + t.setSoftDelete(qx::QxSoftDelete("qx_deleted_at")); + + t.id(&qx::QxPersistable::m_qxId, "qx_id"); + + t.data(&qx::QxPersistable::m_qxDateCreation, "qx_date_creation"); + t.data(&qx::QxPersistable::m_qxDateModification, "qx_date_modification"); + + QxValidatorX *pAllValidator = t.getAllValidator(); + pAllValidator->add_CustomValidator(std::mem_fn(&qx::QxPersistable::qxIsValidInternal)); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + } + + QX_PERSISTABLE_CPP(QxPersistable) + + QxPersistable::QxPersistable() : QObject(), qx::IxPersistable(), m_qxId(0) { ; } + + QxPersistable::~QxPersistable() { ; } + + long QxPersistable::qxGetId() const { return m_qxId; } + + QDateTime QxPersistable::qxGetDateCreation() const { return m_qxDateCreation.toDateTime(); } + + QDateTime QxPersistable::qxGetDateModification() const { return m_qxDateModification.toDateTime(); } + + void QxPersistable::qxSetId(long l) { m_qxId = l; } + + void QxPersistable::qxSetDateCreation(const QDateTime &dt) { m_qxDateCreation.fromDateTime(dt); } + + void QxPersistable::qxSetDateModification(const QDateTime &dt) { m_qxDateModification.fromDateTime(dt); } + + void QxPersistable::qxIsValidInternal(qx::QxInvalidValueX &invalidValues) { this->qxIsValid(invalidValues); } + + void QxPersistable::qxIsValid(qx::QxInvalidValueX &invalidValues) { Q_UNUSED(invalidValues); } + + void QxPersistable::qxOnBeforeInsert(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + m_qxDateCreation.fromDateTime(QDateTime::currentDateTime()); + m_qxDateModification = m_qxDateCreation; + Q_EMIT qxOnBeforeInsert(this); + } + + void QxPersistable::qxOnBeforeUpdate(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + m_qxDateModification.fromDateTime(QDateTime::currentDateTime()); + Q_EMIT qxOnBeforeUpdate(this); + } + + void QxPersistable::qxOnBeforeDelete(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnBeforeDelete(this); + } + + void QxPersistable::qxOnBeforeFetch(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnBeforeFetch(this); + } + + void QxPersistable::qxOnAfterInsert(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnAfterInsert(this); + } + + void QxPersistable::qxOnAfterUpdate(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnAfterUpdate(this); + } + + void QxPersistable::qxOnAfterDelete(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnAfterDelete(this); + } + + void QxPersistable::qxOnAfterFetch(qx::dao::detail::IxDao_Helper *dao) + { + Q_UNUSED(dao); + Q_EMIT qxOnAfterFetch(this); + } + +} // namespace qx diff --git a/test/qxDllSample/dll1/src/TestQtProperty.cpp b/test/qxDllSample/dll1/src/TestQtProperty.cpp new file mode 100644 index 0000000..fc7d184 --- /dev/null +++ b/test/qxDllSample/dll1/src/TestQtProperty.cpp @@ -0,0 +1,24 @@ +#include "../include/precompiled.h" + +#include "../include/TestQtProperty.h" + +#include + +QX_REGISTER_CPP_QX_DLL1(TestQtProperty) +QX_REGISTER_ALL_QT_PROPERTIES(TestQtProperty, "id") + +/* + Instead of using 'QX_REGISTER_ALL_QT_PROPERTIES(...)' macro, it's also + possible to write classic 'void qx::register_class(...)' function, like this : + + namespace qx { + template <> void register_class(QxClass & t) + { qx::register_all_qt_properties(t, "my_id"); } + } // namespace qx + + So, you can mix Qt meta-properties and classic registration data-member. + All is stored using the same interface : 'qx::IxDataMember *'. + To more details about advantages and disadvantages of using Qt meta-property, + go to the FAQ of QxOrm library : + - How to register automatically Qt meta-properties to QxOrm context ? +*/ diff --git a/test/qxDllSample/dll1/src/main.cpp b/test/qxDllSample/dll1/src/main.cpp new file mode 100644 index 0000000..19c39b1 --- /dev/null +++ b/test/qxDllSample/dll1/src/main.cpp @@ -0,0 +1,20 @@ +#ifdef _MSC_VER + +#include + +extern "C" +int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReservedt */) +{ + (void)hInstance; + switch (dwReason) + { + case DLL_PROCESS_ATTACH: ::OutputDebugStringA("dll1.DllMain() ---> DLL_PROCESS_ATTACH\n"); break; + case DLL_PROCESS_DETACH: ::OutputDebugStringA("dll1.DllMain() ---> DLL_PROCESS_DETACH\n"); break; + case DLL_THREAD_ATTACH: ::OutputDebugStringA("dll1.DllMain() ---> DLL_THREAD_ATTACH\n"); break; + case DLL_THREAD_DETACH: ::OutputDebugStringA("dll1.DllMain() ---> DLL_THREAD_DETACH\n"); break; + } + + return 1; +} + +#endif // _MSC_VER diff --git a/test/qxDllSample/dll2/CMakeLists.txt b/test/qxDllSample/dll2/CMakeLists.txt new file mode 100644 index 0000000..50f6ea4 --- /dev/null +++ b/test/qxDllSample/dll2/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.1) + +project(dll2 LANGUAGES CXX) + +include(../../../QxOrm.cmake) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ./include/CUser.h + ./include/CTestAll.h + ./include/Bar.h + ./include/Foo.h + ./include/BaseClassTrigger.h + ) + +set(SRCS + ./qx/CUser.qx.cpp + ./qx/CTestAll.qx.cpp + ./qx/Bar.qx.cpp + ./qx/Foo.qx.cpp + ./qx/BaseClassTrigger.qx.cpp + ./src/CUser.cpp + ./src/CTestAll.cpp + ./src/Bar.cpp + ./src/Foo.cpp + ./src/BaseClassTrigger.cpp + ./src/main.cpp + ) + +add_library(dll2 SHARED ${SRCS} ${HEADERS}) + +target_compile_definitions(dll2 PRIVATE -D_QX_BUILDING_DLL2) + +if(COMMAND target_precompile_headers) + target_precompile_headers(dll2 PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(dll2 ${QX_LIBRARIES} Qt${QT_VERSION_MAJOR}::Gui QxOrm dll1) + +set_target_properties(dll2 PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ) diff --git a/test/qxDllSample/dll2/debug/.gitignore b/test/qxDllSample/dll2/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/dll2.pro b/test/qxDllSample/dll2/dll2.pro new file mode 100644 index 0000000..d52e7db --- /dev/null +++ b/test/qxDllSample/dll2/dll2.pro @@ -0,0 +1,50 @@ +include(../../../QxOrm.pri) + +TEMPLATE = lib +CONFIG += dll +DEFINES += _QX_BUILDING_DLL2 +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ +QT += gui + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +CONFIG(debug, debug|release) { +TARGET = dll2d +} else { +TARGET = dll2 +} # CONFIG(debug, debug|release) + +LIBS += -L"../../../../QxOrm/lib" +LIBS += -L"../../../../QxOrm/test/_bin" + +CONFIG(debug, debug|release) { +LIBS += -l"QxOrmd" +LIBS += -l"dll1d" +} else { +LIBS += -l"QxOrm" +LIBS += -l"dll1" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h +HEADERS += ./include/CUser.h +HEADERS += ./include/CTestAll.h +HEADERS += ./include/Bar.h +HEADERS += ./include/Foo.h +HEADERS += ./include/BaseClassTrigger.h + +SOURCES += ./qx/CUser.qx.cpp +SOURCES += ./qx/CTestAll.qx.cpp +SOURCES += ./qx/Bar.qx.cpp +SOURCES += ./qx/Foo.qx.cpp +SOURCES += ./qx/BaseClassTrigger.qx.cpp + +SOURCES += ./src/CUser.cpp +SOURCES += ./src/CTestAll.cpp +SOURCES += ./src/Bar.cpp +SOURCES += ./src/Foo.cpp +SOURCES += ./src/BaseClassTrigger.cpp +SOURCES += ./src/main.cpp diff --git a/test/qxDllSample/dll2/include/Bar.h b/test/qxDllSample/dll2/include/Bar.h new file mode 100644 index 0000000..36500e9 --- /dev/null +++ b/test/qxDllSample/dll2/include/Bar.h @@ -0,0 +1,48 @@ +#ifndef _QX_BAR_H_ +#define _QX_BAR_H_ + +#include "../include/BaseClassTrigger.h" + +class Foo; + +class QX_DLL2_EXPORT Bar : public BaseClassTrigger +{ + + QX_REGISTER_FRIEND_CLASS(Bar) + QX_PERSISTABLE_HPP(Bar) + +public: + + typedef std::shared_ptr Foo_ptr; + +protected: + + QString m_sCode; + QString m_sValue; + Foo_ptr m_pFoo; + +public: + + Bar() : BaseClassTrigger() { ; } + virtual ~Bar() { ; } + + virtual void makeAbstractClass() { ; } + + QString getCode() const { return m_sCode; } + QString getValue() const { return m_sValue; } + Foo_ptr getFoo() const { return m_pFoo; } + + void setCode(const QString & s) { m_sCode = s; } + void setValue(const QString & s) { m_sValue = s; } + void setFoo(Foo_ptr p) { m_pFoo = p; } + void setFoo(long l); + +}; + +QX_REGISTER_HPP_QX_DLL2(Bar, BaseClassTrigger, 0) + +typedef std::shared_ptr Bar_ptr; +typedef std::vector BarX; +typedef std::shared_ptr BarX_ptr; + +#endif // _QX_BAR_H_ diff --git a/test/qxDllSample/dll2/include/BaseClassTrigger.h b/test/qxDllSample/dll2/include/BaseClassTrigger.h new file mode 100644 index 0000000..4d9ae41 --- /dev/null +++ b/test/qxDllSample/dll2/include/BaseClassTrigger.h @@ -0,0 +1,67 @@ +#ifndef _QX_BASE_CLASS_TRIGGER_H_ +#define _QX_BASE_CLASS_TRIGGER_H_ + +class QX_DLL2_EXPORT BaseClassTrigger : public qx::IxPersistable +{ + + QX_REGISTER_FRIEND_CLASS(BaseClassTrigger) + +protected: + + long m_id; + QDateTime m_dateCreation; + QDateTime m_dateModification; + QString m_userCreation; + QString m_userModification; + +public: + + BaseClassTrigger() : m_id(0) { ; } + virtual ~BaseClassTrigger() { ; } + + virtual void makeAbstractClass() = 0; + + long getId() const { return m_id; } + QDateTime getDateCreation() const { return m_dateCreation; } + QDateTime getDateModification() const { return m_dateModification; } + QString getUserCreation() const { return m_userCreation; } + QString getUserModification() const { return m_userModification; } + + void setId(long l) { m_id = l; } + void setDateCreation(const QDateTime & dt) { m_dateCreation = dt; } + void setDateModification(const QDateTime & dt) { m_dateModification = dt; } + void setUserCreation(const QString & s) { m_userCreation = s; } + void setUserModification(const QString & s) { m_userModification = s; } + + void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao); + void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao); + +}; + +QX_REGISTER_ABSTRACT_CLASS(BaseClassTrigger) +QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0) + +namespace qx { +namespace dao { +namespace detail { + +template <> +struct QxDao_Trigger +{ + + static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeInsert(dao); } } + static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { if (t) { t->onBeforeUpdate(dao); } } + static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + static inline void onBeforeFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + static inline void onAfterFetch(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao) { Q_UNUSED(t); Q_UNUSED(dao); } + +}; + +} // namespace detail +} // namespace dao +} // namespace qx + +#endif // _QX_BASE_CLASS_TRIGGER_H_ diff --git a/test/qxDllSample/dll2/include/CTestAll.h b/test/qxDllSample/dll2/include/CTestAll.h new file mode 100644 index 0000000..b87b156 --- /dev/null +++ b/test/qxDllSample/dll2/include/CTestAll.h @@ -0,0 +1,105 @@ +#ifndef _QX_CLASS_TEST_ALL_H_ +#define _QX_CLASS_TEST_ALL_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#include +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#include "../../dll1/include/CPerson.h" +#include "../../dll2/include/CUser.h" + +class QX_DLL2_EXPORT CTestAll +{ + + QX_REGISTER_FRIEND_CLASS(CTestAll) + +protected: + + long m_lId; + qx_bool m_oQxBool; + + std::string m_oStdString; + std::pair m_oStdPair; + std::vector< QSharedPointer > m_oStdVector; + std::list m_oStdList; + std::map > m_oStdMap; + std::shared_ptr m_oBoostSharedPtr; + +#ifdef _QX_ENABLE_BOOST + boost::tuple m_oBoostTuple; + boost::scoped_ptr m_oBoostScopedPtr; + boost::weak_ptr m_oBoostWeakPtr; + boost::unordered_map m_oBoostUnorderedMap; +#endif // _QX_ENABLE_BOOST + + QString m_oQString; + QObject m_oQObject; + QBrush m_oQBrush; + QByteArray m_oQByteArray; + QColor m_oQColor; + QDate m_oQDate; + QDateTime m_oQDateTime; + QTime m_oQTime; + QFont m_oQFont; + QImage m_oQImage; + QPicture m_oQPicture; + QPoint m_oQPoint; + QRect m_oQRect; + QSize m_oQSize; + QRegion m_oQRegion; + QUrl m_oQUrl; + QVariant m_oQVariant; + QStringList m_oQStringList; + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + QMatrix m_oQMatrix; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + QRegExp m_oQRegExp; +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + QHash m_oQHash; + QMultiHash > m_oQMultiHash; + QMap m_oQMap; + QMultiMap > m_oQMultiMap; + qx::QxCollection > m_oQxCollection; + + QList m_oQList; + QVector m_oQVector; + QSharedPointer > > m_oQSharedPointer; + QPair m_oQPair; + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + QLinkedList m_oQLinkedList; +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +public: + + CTestAll() { init(); } + virtual ~CTestAll() { terminate(); } + + static void test(); + +private: + + void init(); + void terminate(); + +}; + +QX_REGISTER_HPP_QX_DLL2(CTestAll, qx::trait::no_base_class_defined, 1) + +#endif // _QX_CLASS_TEST_ALL_H_ diff --git a/test/qxDllSample/dll2/include/CUser.h b/test/qxDllSample/dll2/include/CUser.h new file mode 100644 index 0000000..47abc64 --- /dev/null +++ b/test/qxDllSample/dll2/include/CUser.h @@ -0,0 +1,54 @@ +#ifndef _QX_CLASS_USER_H_ +#define _QX_CLASS_USER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#ifdef _QX_NO_PRECOMPILED_HEADER +#ifndef Q_MOC_RUN +#include "../include/precompiled.h" // Need to include precompiled header for the generated moc file +#endif // Q_MOC_RUN +#endif // _QX_NO_PRECOMPILED_HEADER + +#include "../../dll1/include/CPerson.h" + +class QX_DLL2_EXPORT CUser : public qx::test::CPerson +{ + + Q_OBJECT + QX_REGISTER_FRIEND_CLASS(CUser) + +protected: + + long m_lUserId; + QString m_sProfil; + qx_bool m_bIsAdmin; + QDateTime m_dtModif; + qx::test::CPerson * m_pBrother; + +public: + + CUser() : qx::test::CPerson(), m_lUserId(0), m_pBrother(NULL) { ; } + CUser(long lId) : qx::test::CPerson(), m_lUserId(lId), m_pBrother(NULL) { ; } + virtual ~CUser() { if (m_pBrother) { delete m_pBrother; m_pBrother = NULL; } } + + void test(); + + long getUserId() const { return m_lUserId; } + QString getProfil() const { return m_sProfil; } + qx_bool getIsAdmin() const { return m_bIsAdmin; } + QDateTime getDateModif() const { return m_dtModif; } + qx::test::CPerson * getBrother() const { return m_pBrother; } + + void setUserId(long l) { m_lUserId = l; } + void setProfil(const QString & s) { m_sProfil = s; } + void setIsAdmin(qx_bool b) { m_bIsAdmin = b; } + void setDateModif(const QDateTime & dt) { m_dtModif = dt; } + void setBrother(qx::test::CPerson * p) { if (m_pBrother) { delete m_pBrother; } m_pBrother = p; } + +}; + +QX_REGISTER_HPP_QX_DLL2(CUser, qx::test::CPerson, 2) + +#endif // _QX_CLASS_USER_H_ diff --git a/test/qxDllSample/dll2/include/Foo.h b/test/qxDllSample/dll2/include/Foo.h new file mode 100644 index 0000000..2a35caf --- /dev/null +++ b/test/qxDllSample/dll2/include/Foo.h @@ -0,0 +1,67 @@ +#ifndef _QX_FOO_H_ +#define _QX_FOO_H_ + +#include "../include/BaseClassTrigger.h" +#include "../include/Bar.h" + +class QX_DLL2_EXPORT Foo : public BaseClassTrigger +{ + + QX_REGISTER_FRIEND_CLASS(Foo) + QX_PERSISTABLE_HPP(Foo) + +protected: + + QString m_sName; + QVariant m_sDesc; + BarX_ptr m_pBarX; + + qx::QxDateNeutral m_oDateNeutral; + qx::QxTimeNeutral m_oTimeNeutral; + qx::QxDateTimeNeutral m_oDateTimeNeutral; + +#ifdef _QX_ENABLE_BOOST + boost::optional m_optInt; + boost::optional m_optString; +#endif // _QX_ENABLE_BOOST + +public: + + Foo() : BaseClassTrigger() { ; } + virtual ~Foo() { ; } + + virtual void makeAbstractClass() { ; } + + QString getName() const { return m_sName; } + QVariant getDesc() const { return m_sDesc; } + BarX * getBarX() const { return m_pBarX.get(); } + QDate getDate() const { return m_oDateNeutral.toDate(); } + QTime getTime() const { return m_oTimeNeutral.toTime(); } + QDateTime getDateTime() const { return m_oDateTimeNeutral.toDateTime(); } + +#ifdef _QX_ENABLE_BOOST + boost::optional getOptInt() const { return m_optInt; } + boost::optional getOptString() const { return m_optString; } +#endif // _QX_ENABLE_BOOST + + void setName(const QString & s) { m_sName = s; } + void setDesc(const QVariant & s) { m_sDesc = s; } + void setBarX(BarX_ptr p) { m_pBarX = p; } + void setDate(const QDate & d) { m_oDateNeutral.setDate(d); } + void setTime(const QTime & t) { m_oTimeNeutral.setTime(t); } + void setDateTime(const QDateTime & dt) { m_oDateTimeNeutral.setDateTime(dt); } + +#ifdef _QX_ENABLE_BOOST + void setOptInt(const boost::optional & opt) { m_optInt = opt; } + void setOptString(const boost::optional & opt) { m_optString = opt; } +#endif // _QX_ENABLE_BOOST + +}; + +QX_REGISTER_HPP_QX_DLL2(Foo, BaseClassTrigger, 0) + +typedef std::shared_ptr Foo_ptr; +typedef qx::QxCollection FooX; +typedef std::shared_ptr FooX_ptr; + +#endif // _QX_FOO_H_ diff --git a/test/qxDllSample/dll2/include/export.h b/test/qxDllSample/dll2/include/export.h new file mode 100644 index 0000000..e5bbb4c --- /dev/null +++ b/test/qxDllSample/dll2/include/export.h @@ -0,0 +1,28 @@ +#ifndef _QX_DLL2_EXPORT_H_ +#define _QX_DLL2_EXPORT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include "../../dll1/include/export.h" + +#ifdef _QX_BUILDING_DLL2 +#define QX_DLL2_EXPORT QX_DLL_EXPORT_HELPER +#else // _QX_BUILDING_DLL2 +#define QX_DLL2_EXPORT QX_DLL_IMPORT_HELPER +#endif // _QX_BUILDING_DLL2 + +#ifdef _QX_BUILDING_DLL2 +#define QX_REGISTER_HPP_QX_DLL2 QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_DLL2 QX_REGISTER_CPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL2 QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL2 QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL +#else // _QX_BUILDING_DLL2 +#define QX_REGISTER_HPP_QX_DLL2 QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_DLL2 QX_REGISTER_CPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL2 QX_REGISTER_COMPLEX_CLASS_NAME_HPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_DLL2 QX_REGISTER_COMPLEX_CLASS_NAME_CPP_IMPORT_DLL +#endif // _QX_BUILDING_DLL2 + +#endif // _QX_DLL2_EXPORT_H_ diff --git a/test/qxDllSample/dll2/include/precompiled.h b/test/qxDllSample/dll2/include/precompiled.h new file mode 100644 index 0000000..54b6852 --- /dev/null +++ b/test/qxDllSample/dll2/include/precompiled.h @@ -0,0 +1,12 @@ +#ifndef _QX_DLL2_PRECOMPILED_HEADER_H_ +#define _QX_DLL2_PRECOMPILED_HEADER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#include "../include/export.h" + +#endif // _QX_DLL2_PRECOMPILED_HEADER_H_ diff --git a/test/qxDllSample/dll2/qt/moc/.gitignore b/test/qxDllSample/dll2/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/qt/rcc/src/.gitignore b/test/qxDllSample/dll2/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/qt/ui/include/.gitignore b/test/qxDllSample/dll2/qt/ui/include/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/qt/ui/include/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/qt/ui/src/.gitignore b/test/qxDllSample/dll2/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/qx/Bar.qx.cpp b/test/qxDllSample/dll2/qx/Bar.qx.cpp new file mode 100644 index 0000000..315beca --- /dev/null +++ b/test/qxDllSample/dll2/qx/Bar.qx.cpp @@ -0,0 +1,23 @@ +#include "../include/precompiled.h" + +#include "../include/Bar.h" +#include "../include/Foo.h" + +#include + +QX_REGISTER_CPP_QX_DLL2(Bar) +QX_PERSISTABLE_CPP(Bar) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + IxSqlRelation * pRelation = NULL; + + t.setSoftDelete(qx::QxSoftDelete("deleted_at")); + + pData = t.data(& Bar::m_sCode, "code"); + pData = t.data(& Bar::m_sValue, "value"); + + pRelation = t.relationManyToOne(& Bar::m_pFoo, "foo_id"); +}} diff --git a/test/qxDllSample/dll2/qx/BaseClassTrigger.qx.cpp b/test/qxDllSample/dll2/qx/BaseClassTrigger.qx.cpp new file mode 100644 index 0000000..857d809 --- /dev/null +++ b/test/qxDllSample/dll2/qx/BaseClassTrigger.qx.cpp @@ -0,0 +1,20 @@ +#include "../include/precompiled.h" + +#include "../include/BaseClassTrigger.h" + +#include + +QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + + pData = t.id(& BaseClassTrigger::m_id, "id"); + + pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation"); + pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification"); + pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation"); + pData = t.data(& BaseClassTrigger::m_userModification, "user_modification"); +}} diff --git a/test/qxDllSample/dll2/qx/CTestAll.qx.cpp b/test/qxDllSample/dll2/qx/CTestAll.qx.cpp new file mode 100644 index 0000000..21a7de9 --- /dev/null +++ b/test/qxDllSample/dll2/qx/CTestAll.qx.cpp @@ -0,0 +1,75 @@ +#include "../include/precompiled.h" + +#include "../include/CTestAll.h" + +#include + +QX_REGISTER_CPP_QX_DLL2(CTestAll) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + + pData = t.id(& CTestAll::m_lId, "m_lId"); + + pData = t.data(& CTestAll::m_oQxBool, "m_oQxBool"); + pData = t.data(& CTestAll::m_oStdString, "m_oStdString"); + pData = t.data(& CTestAll::m_oStdPair, "m_oStdPair"); + pData = t.data(& CTestAll::m_oStdVector, "m_oStdVector"); + pData = t.data(& CTestAll::m_oStdList, "m_oStdList"); + pData = t.data(& CTestAll::m_oStdMap, "m_oStdMap"); + pData = t.data(& CTestAll::m_oQString, "m_oQString"); + pData = t.data(& CTestAll::m_oQObject, "m_oQObject"); + pData = t.data(& CTestAll::m_oQByteArray, "m_oQByteArray"); + pData = t.data(& CTestAll::m_oQDate, "m_oQDate"); + pData = t.data(& CTestAll::m_oQDateTime, "m_oQDateTime"); + pData = t.data(& CTestAll::m_oQTime, "m_oQTime"); + +#ifdef _QX_ENABLE_BOOST + pData = t.data(& CTestAll::m_oBoostTuple, "m_oBoostTuple"); + pData = t.data(& CTestAll::m_oBoostScopedPtr, "m_oBoostScopedPtr", 1); + pData = t.data(& CTestAll::m_oBoostUnorderedMap, "m_oBoostUnorderedMap", 1); +#endif // _QX_ENABLE_BOOST + +#ifdef _QX_ENABLE_QT_GUI + pData = t.data(& CTestAll::m_oQBrush, "m_oQBrush"); + pData = t.data(& CTestAll::m_oQColor, "m_oQColor"); + pData = t.data(& CTestAll::m_oQFont, "m_oQFont", 0); + pData = t.data(& CTestAll::m_oQImage, "m_oQImage", 0); + pData = t.data(& CTestAll::m_oQPicture, "m_oQPicture", 0); + pData = t.data(& CTestAll::m_oQRegion, "m_oQRegion", 0); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + pData = t.data(& CTestAll::m_oQMatrix, "m_oQMatrix", 1); +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) +#endif // _QX_ENABLE_QT_GUI + +#if (0) /* ((! defined(Q_OS_WIN)) || (! defined(__GNUC__))) // MinGW memory bug ? */ + pData = t.data(& CTestAll::m_oQPoint, "m_oQPoint", 0); + pData = t.data(& CTestAll::m_oQRect, "m_oQRect", 0); + pData = t.data(& CTestAll::m_oQUrl, "m_oQUrl", 0); + pData = t.data(& CTestAll::m_oQVariant, "m_oQVariant", 0); + pData = t.data(& CTestAll::m_oQStringList, "m_oQStringList", 0); + pData = t.data(& CTestAll::m_oQHash, "m_oQHash", 0); + pData = t.data(& CTestAll::m_oQMultiHash, "m_oQMultiHash", 0); + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + pData = t.data(& CTestAll::m_oQRegExp, "m_oQRegExp", 0); +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + pData = t.data(& CTestAll::m_oQMap, "m_oQMap", 1); + pData = t.data(& CTestAll::m_oQMultiMap, "m_oQMultiMap", 1); + pData = t.data(& CTestAll::m_oQxCollection, "m_oQxCollection", 1); + pData = t.data(& CTestAll::m_oQList, "m_oQList", 1); + pData = t.data(& CTestAll::m_oQVector, "m_oQVector", 1); + pData = t.data(& CTestAll::m_oQPair, "m_oQPair", 1); + pData = t.data(& CTestAll::m_oBoostSharedPtr, "m_oBoostSharedPtr", 1); + pData = t.data(& CTestAll::m_oQSharedPointer, "m_oQSharedPointer", 1); + pData = t.data(& CTestAll::m_oQSize, "m_oQSize", 1); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + pData = t.data(& CTestAll::m_oQLinkedList, "m_oQLinkedList", 1); +#endif // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) + +#endif // ((! defined(Q_OS_WIN)) || (! defined(__GNUC__))) +}} diff --git a/test/qxDllSample/dll2/qx/CUser.qx.cpp b/test/qxDllSample/dll2/qx/CUser.qx.cpp new file mode 100644 index 0000000..5f4a6c7 --- /dev/null +++ b/test/qxDllSample/dll2/qx/CUser.qx.cpp @@ -0,0 +1,26 @@ +#include "../include/precompiled.h" + +#include "../include/CUser.h" + +#include + +QX_REGISTER_CPP_QX_DLL2(CUser) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + IxSqlRelation * pRelation = NULL; + IxValidator * pValidator = NULL; + + pData = t.data(& CUser::m_lUserId, "idUser", 0); + pData = t.data(& CUser::m_sProfil, "profil", 0); pData->setSqlAlias("profil"); + pData = t.data(& CUser::m_bIsAdmin, "isAdmin", 1); + pData = t.data(& CUser::m_dtModif, "dtModif", 1); + + pRelation = t.relationManyToOne(& CUser::m_pBrother, "brother", 2); + + QxValidatorX * pAllValidator = t.getAllValidator(); + if (! pAllValidator) { qAssert(false); return; } + pValidator = pAllValidator->add_RecursiveValidator("brother"); +}} diff --git a/test/qxDllSample/dll2/qx/Foo.qx.cpp b/test/qxDllSample/dll2/qx/Foo.qx.cpp new file mode 100644 index 0000000..2558f62 --- /dev/null +++ b/test/qxDllSample/dll2/qx/Foo.qx.cpp @@ -0,0 +1,28 @@ +#include "../include/precompiled.h" + +#include "../include/Foo.h" + +#include + +QX_REGISTER_CPP_QX_DLL2(Foo) +QX_PERSISTABLE_CPP(Foo) + +namespace qx { +template <> void register_class(QxClass & t) +{ + IxDataMember * pData = NULL; + IxSqlRelation * pRelation = NULL; + + pData = t.data(& Foo::m_sName, "name"); + pData = t.data(& Foo::m_sDesc, "desc"); + pData = t.data(& Foo::m_oDateNeutral, "date_neutral"); + pData = t.data(& Foo::m_oTimeNeutral, "time_neutral"); + pData = t.data(& Foo::m_oDateTimeNeutral, "dt_neutral"); + +#ifdef _QX_ENABLE_BOOST + pData = t.data(& Foo::m_optInt, "optional_int"); + pData = t.data(& Foo::m_optString, "optional_string"); +#endif // _QX_ENABLE_BOOST + + pRelation = t.relationOneToMany(& Foo::m_pBarX, "lstBar", "foo_id"); +}} diff --git a/test/qxDllSample/dll2/release/.gitignore b/test/qxDllSample/dll2/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/dll2/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/dll2/src/Bar.cpp b/test/qxDllSample/dll2/src/Bar.cpp new file mode 100644 index 0000000..e4a5aac --- /dev/null +++ b/test/qxDllSample/dll2/src/Bar.cpp @@ -0,0 +1,12 @@ +#include "../include/precompiled.h" + +#include "../include/Bar.h" +#include "../include/Foo.h" + +#include + +void Bar::setFoo(long l) +{ + m_pFoo.reset(new Foo()); + m_pFoo->setId(l); +} diff --git a/test/qxDllSample/dll2/src/BaseClassTrigger.cpp b/test/qxDllSample/dll2/src/BaseClassTrigger.cpp new file mode 100644 index 0000000..0f80f22 --- /dev/null +++ b/test/qxDllSample/dll2/src/BaseClassTrigger.cpp @@ -0,0 +1,21 @@ +#include "../include/precompiled.h" + +#include "../include/BaseClassTrigger.h" + +#include + +void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao) +{ + Q_UNUSED(dao); + m_dateCreation = QDateTime::currentDateTime(); + m_dateModification = QDateTime::currentDateTime(); + m_userCreation = "current_user_1"; + m_userModification = "current_user_1"; +} + +void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao) +{ + Q_UNUSED(dao); + m_dateModification = QDateTime::currentDateTime(); + m_userModification = "current_user_2"; +} diff --git a/test/qxDllSample/dll2/src/CTestAll.cpp b/test/qxDllSample/dll2/src/CTestAll.cpp new file mode 100644 index 0000000..fc4e462 --- /dev/null +++ b/test/qxDllSample/dll2/src/CTestAll.cpp @@ -0,0 +1,89 @@ +#include "../include/precompiled.h" + +#include "../include/CTestAll.h" + +#include + +void CTestAll::init() +{ + m_lId = 56; + m_oQxBool = qx_bool(true, "qx_bool description"); + m_oStdString = "std::string text"; + + m_oQString = "QString text\nwith a new line"; + m_oQDate = QDate::currentDate(); + m_oQDateTime = QDateTime::currentDateTime(); + m_oQTime = QTime::currentTime(); + m_oQColor = QColor(255, 200, 200); + m_oQFont.setBold(true); + m_oQFont.setFamily("font family from qx test"); + m_oQPoint = QPoint(8, 11); + m_oQRect = QRect(QPoint(52, 3), QPoint(574, 1112)); + m_oQSize = QSize(1024, 768); + m_oQUrl = QUrl("www.qxorm.com"); + m_oQStringList << "str1" << "str2" << "str3" << "str4"; + m_oQByteArray = QByteArray("QByteArray t\0ext\nwith a new line\0and null multi\0ple null char\0", 55); + m_oQVariant = QVariant(0.437); + m_oQObject.setProperty("prop_1", 1); + m_oQObject.setProperty("prop_2", 2); + +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + m_oQRegExp = QRegExp("qt reg exp"); +#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) + + QSharedPointer u1(new CUser()); + QSharedPointer u2(new CUser()); + + m_oStdPair = std::make_pair(QPoint(2, 6), QRect(99, 55, 44, 22)); + m_oStdList.push_back(QDateTime()); + m_oStdList.push_back(QDateTime::currentDateTime()); + m_oStdList.push_back(QDateTime()); + m_oStdMap.insert(std::make_pair("1", u1)); + m_oStdMap.insert(std::make_pair("2", u2)); + + m_oStdVector.push_back(QSharedPointer(new qx::test::CPerson())); + m_oStdVector.push_back(QSharedPointer(new CUser())); +} + +void CTestAll::terminate() +{ + Q_FOREACH(CUser * p2, m_oQVector) { if (p2) { delete p2; } } +} + +void CTestAll::test() +{ + std::shared_ptr o1; o1.reset(new CTestAll()); + std::shared_ptr o2; o2.reset(new CTestAll()); + + qx::QxCollection > coll; + coll.insert(0, o1); + coll.insert(1, o2); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_xml::to_file(coll, "test_all.xml"); + qx::serialization::polymorphic_xml::from_file(coll, "test_all.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + qx::serialization::binary::to_file(coll, "test_all.bin"); + qx::serialization::binary::from_file(coll, "test_all.bin"); +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(coll, "test_all.xml"); + qx::serialization::xml::from_file(coll, "test_all.xml"); +#endif // _QX_SERIALIZE_XML + +#if _QX_SERIALIZE_PORTABLE_BINARY + qx::serialization::portable_binary::to_file(coll, "test_all.bin2", 0); + qx::serialization::portable_binary::from_file(coll, "test_all.bin2", 0); +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(coll, "test_all.json"); + qx::serialization::json::from_file(coll, "test_all.json"); +#endif // _QX_NO_JSON + + qx::clone(coll); + qx::create("CTestAll"); +} diff --git a/test/qxDllSample/dll2/src/CUser.cpp b/test/qxDllSample/dll2/src/CUser.cpp new file mode 100644 index 0000000..4cd0916 --- /dev/null +++ b/test/qxDllSample/dll2/src/CUser.cpp @@ -0,0 +1,126 @@ +#include "../include/precompiled.h" + +#include "../include/CUser.h" + +#include + +void CUser::test() +{ + std::shared_ptr ptrTmp; + ptrTmp.reset(new CUser()); + qx::clone(ptrTmp); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_xml::to_file(ptrTmp, "pointer_from_CUser.xml"); + qx::serialization::polymorphic_xml::from_file(ptrTmp, "pointer_from_CUser.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(ptrTmp, "pointer_from_CUser.xml"); + qx::serialization::xml::from_file(ptrTmp, "pointer_from_CUser.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(ptrTmp, "pointer_from_CUser.json"); + qx::serialization::json::from_file(ptrTmp, "pointer_from_CUser.json"); +#endif // _QX_NO_JSON + + qx::test::CPerson person; + qx::clone(person); + qx::create("qx::test::CPerson"); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_binary::to_file(person, "person.bin"); + qx::serialization::polymorphic_binary::from_file(person, "person.bin"); + qx::serialization::polymorphic_xml::to_file(person, "person.xml"); + qx::serialization::polymorphic_xml::from_file(person, "person.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + qx::serialization::binary::to_file(person, "person.bin"); + qx::serialization::binary::from_file(person, "person.bin"); +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + qx::serialization::text::to_file(person, "person.txt"); + qx::serialization::text::from_file(person, "person.txt"); +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(person, "person.xml"); + qx::serialization::xml::from_file(person, "person.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(person, "person.json"); + qx::serialization::json::from_file(person, "person.json"); +#endif // _QX_NO_JSON + +#if _QX_SERIALIZE_PORTABLE_BINARY + qx::serialization::portable_binary::to_file(person, "person.bin2", 0); + qx::serialization::portable_binary::from_file(person, "person.bin2", 0); +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::to_string(person); + qx::serialization::to_file_compressed(person, "person.zip"); + qx::serialization::from_file_compressed(person, "person.zip"); +#else // _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::qt::to_string(person); + qx::serialization::qt::to_file_compressed(person, "person.zip"); + qx::serialization::qt::from_file_compressed(person, "person.zip"); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + //-------------------------------- + + CUser user; + qx::clone(user); + qx::create("CUser"); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_binary::to_file(user, "user.bin"); + qx::serialization::polymorphic_binary::from_file(user, "user.bin"); + qx::serialization::polymorphic_xml::to_file(user, "user.xml"); + qx::serialization::polymorphic_xml::from_file(user, "user.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + qx::serialization::binary::to_file(user, "user.bin"); + qx::serialization::binary::from_file(user, "user.bin"); +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + qx::serialization::text::to_file(user, "user.txt"); + qx::serialization::text::from_file(user, "user.txt"); +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(user, "user.xml"); + qx::serialization::xml::from_file(user, "user.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(user, "user.json"); + qx::serialization::json::from_file(user, "user.json"); +#endif // _QX_NO_JSON + +#if _QX_SERIALIZE_PORTABLE_BINARY + qx::serialization::portable_binary::to_file(user, "user.bin2", 0); + qx::serialization::portable_binary::from_file(user, "user.bin2", 0); +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::to_string(user); + qx::serialization::to_file_compressed(user, "user.zip"); + qx::serialization::from_file_compressed(user, "user.zip"); +#else // _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::qt::to_string(user); + qx::serialization::qt::to_file_compressed(user, "user.zip"); + qx::serialization::qt::from_file_compressed(user, "user.zip"); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + //-------------------------------- + + qx::test::CPerson * pPerson = new qx::test::CPerson(); // You find a memory leak !!! + Q_UNUSED(pPerson); +} diff --git a/test/qxDllSample/dll2/src/Foo.cpp b/test/qxDllSample/dll2/src/Foo.cpp new file mode 100644 index 0000000..9274d91 --- /dev/null +++ b/test/qxDllSample/dll2/src/Foo.cpp @@ -0,0 +1,5 @@ +#include "../include/precompiled.h" + +#include "../include/Foo.h" + +#include diff --git a/test/qxDllSample/dll2/src/main.cpp b/test/qxDllSample/dll2/src/main.cpp new file mode 100644 index 0000000..74ddba9 --- /dev/null +++ b/test/qxDllSample/dll2/src/main.cpp @@ -0,0 +1,20 @@ +#ifdef _MSC_VER + +#include + +extern "C" +int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReservedt */) +{ + (void)hInstance; + switch (dwReason) + { + case DLL_PROCESS_ATTACH: ::OutputDebugStringA("dll2.DllMain() ---> DLL_PROCESS_ATTACH\n"); break; + case DLL_PROCESS_DETACH: ::OutputDebugStringA("dll2.DllMain() ---> DLL_PROCESS_DETACH\n"); break; + case DLL_THREAD_ATTACH: ::OutputDebugStringA("dll2.DllMain() ---> DLL_THREAD_ATTACH\n"); break; + case DLL_THREAD_DETACH: ::OutputDebugStringA("dll2.DllMain() ---> DLL_THREAD_DETACH\n"); break; + } + + return 1; +} + +#endif // _MSC_VER diff --git a/test/qxDllSample/exe/CMakeLists.txt b/test/qxDllSample/exe/CMakeLists.txt new file mode 100644 index 0000000..78d57b5 --- /dev/null +++ b/test/qxDllSample/exe/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.1) + +project(exe LANGUAGES CXX) + +include(../../../QxOrm.cmake) + +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Gui Widgets REQUIRED) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_DEBUG_POSTFIX "d") + +set(HEADERS + ./include/precompiled.h + ./include/export.h + ) + +set(SRCS + ./src/main.cpp + ) + +add_executable(exe ${SRCS} ${HEADERS}) + +target_compile_definitions(exe PRIVATE -D_QX_BUILDING_EXE) + +if(COMMAND target_precompile_headers) + target_precompile_headers(exe PRIVATE ./include/precompiled.h) +endif() # (COMMAND target_precompile_headers) + +target_link_libraries(exe ${QX_LIBRARIES} Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets QxOrm dll1 dll2) + +set_target_properties(exe PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_SOURCE_DIR}/../../_bin" + ) + +set_target_properties(exe PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/test/qxDllSample/exe/debug/.gitignore b/test/qxDllSample/exe/debug/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/debug/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/exe.pro b/test/qxDllSample/exe/exe.pro new file mode 100644 index 0000000..584d577 --- /dev/null +++ b/test/qxDllSample/exe/exe.pro @@ -0,0 +1,39 @@ +include(../../../QxOrm.pri) + +TEMPLATE = app +DEFINES += _QX_BUILDING_EXE +INCLUDEPATH += ../../../../QxOrm/include/ +DESTDIR = ../../../../QxOrm/test/_bin/ + +QT += gui +greaterThan(QT_MAJOR_VERSION, 4) { QT += widgets } + +!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) { +PRECOMPILED_HEADER = ./include/precompiled.h +} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) + +macx:CONFIG-=app_bundle + +CONFIG(debug, debug|release) { +TARGET = exed +} else { +TARGET = exe +} # CONFIG(debug, debug|release) + +LIBS += -L"../../../../QxOrm/lib" +LIBS += -L"../../../../QxOrm/test/_bin" + +CONFIG(debug, debug|release) { +LIBS += -l"QxOrmd" +LIBS += -l"dll1d" +LIBS += -l"dll2d" +} else { +LIBS += -l"QxOrm" +LIBS += -l"dll1" +LIBS += -l"dll2" +} # CONFIG(debug, debug|release) + +HEADERS += ./include/precompiled.h +HEADERS += ./include/export.h + +SOURCES += ./src/main.cpp diff --git a/test/qxDllSample/exe/include/export.h b/test/qxDllSample/exe/include/export.h new file mode 100644 index 0000000..4a0af00 --- /dev/null +++ b/test/qxDllSample/exe/include/export.h @@ -0,0 +1,23 @@ +#ifndef _QX_EXE_EXPORT_H_ +#define _QX_EXE_EXPORT_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include "../../dll1/include/export.h" +#include "../../dll2/include/export.h" + +#ifdef _QX_BUILDING_EXE +#define QX_REGISTER_HPP_QX_EXE QX_REGISTER_HPP_EXPORT_DLL +#define QX_REGISTER_CPP_QX_EXE QX_REGISTER_CPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_EXE QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_EXE QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL +#else // _QX_BUILDING_EXE +#define QX_REGISTER_HPP_QX_EXE QX_REGISTER_HPP_IMPORT_DLL +#define QX_REGISTER_CPP_QX_EXE QX_REGISTER_CPP_IMPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_EXE QX_REGISTER_COMPLEX_CLASS_NAME_HPP_EXPORT_DLL +#define QX_REGISTER_COMPLEX_CLASS_NAME_CPP_QX_EXE QX_REGISTER_COMPLEX_CLASS_NAME_CPP_EXPORT_DLL +#endif // _QX_BUILDING_EXE + +#endif // _QX_EXE_EXPORT_H_ diff --git a/test/qxDllSample/exe/include/precompiled.h b/test/qxDllSample/exe/include/precompiled.h new file mode 100644 index 0000000..a8c1fb4 --- /dev/null +++ b/test/qxDllSample/exe/include/precompiled.h @@ -0,0 +1,14 @@ +#ifndef _QX_EXE_PRECOMPILED_HEADER_H_ +#define _QX_EXE_PRECOMPILED_HEADER_H_ + +#ifdef _MSC_VER +#pragma once +#endif + +#include +#include +#include + +#include "../include/export.h" + +#endif // _QX_EXE_PRECOMPILED_HEADER_H_ diff --git a/test/qxDllSample/exe/qt/moc/.gitignore b/test/qxDllSample/exe/qt/moc/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/qt/moc/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/qt/rcc/src/.gitignore b/test/qxDllSample/exe/qt/rcc/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/qt/rcc/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/qt/ui/include/.gitignore b/test/qxDllSample/exe/qt/ui/include/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/qt/ui/include/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/qt/ui/src/.gitignore b/test/qxDllSample/exe/qt/ui/src/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/qt/ui/src/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/qx/.gitignore b/test/qxDllSample/exe/qx/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/qx/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/release/.gitignore b/test/qxDllSample/exe/release/.gitignore new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/test/qxDllSample/exe/release/.gitignore @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/test/qxDllSample/exe/src/main.cpp b/test/qxDllSample/exe/src/main.cpp new file mode 100644 index 0000000..47238e8 --- /dev/null +++ b/test/qxDllSample/exe/src/main.cpp @@ -0,0 +1,555 @@ +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#else // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) +#include +#endif // (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + +#include "../include/precompiled.h" + +#include "../../dll1/include/CPerson.h" +#include "../../dll1/include/TestQtProperty.h" + +#include "../../dll2/include/CUser.h" +#include "../../dll2/include/CTestAll.h" +#include "../../dll2/include/Bar.h" +#include "../../dll2/include/Foo.h" + +#include + +void test_fct() { qDebug("[QxOrm] %s", "'test_fct()' called by 'qx::IxFunction()'"); } +struct test_class_fct { int class_fct() { qDebug("[QxOrm] %s", "'test_class_fct::class_fct()' called by 'qx::IxFunction()'"); return 123; }; }; + +int main(int argc, char * argv[]) +{ + QApplication app(argc, argv); + + //-------------------------------- + + std::shared_ptr ptrTmp; + ptrTmp.reset(new CUser()); + qx::clone(ptrTmp); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_xml::to_file(ptrTmp, "pointer_from_main.xml"); + qx::serialization::polymorphic_xml::from_file(ptrTmp, "pointer_from_main.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(ptrTmp, "pointer_from_main.xml"); + qx::serialization::xml::from_file(ptrTmp, "pointer_from_main.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(ptrTmp, "pointer_from_main.json"); + qx::serialization::json::from_file(ptrTmp, "pointer_from_main.json"); +#endif // _QX_NO_JSON + + //-------------------------------- + + qx::test::CPerson person; + std::shared_ptr personClone = qx::clone(person); + qx::any a = qx::create("qx::test::CPerson"); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_binary::to_file(person, "person.bin"); + qx::serialization::polymorphic_binary::from_file(person, "person.bin"); + qx::serialization::polymorphic_xml::to_file(person, "person.xml"); + qx::serialization::polymorphic_xml::from_file(person, "person.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + qx::serialization::binary::to_file(person, "person.bin"); + qx::serialization::binary::from_file(person, "person.bin"); +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + qx::serialization::text::to_file(person, "person.txt"); + qx::serialization::text::from_file(person, "person.txt"); +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(person, "person.xml"); + qx::serialization::xml::from_file(person, "person.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(person, "person.json"); + qx::serialization::json::from_file(person, "person.json"); +#endif // _QX_NO_JSON + +#if _QX_SERIALIZE_PORTABLE_BINARY + qx::serialization::portable_binary::to_file(person, "person.bin2", 0); + qx::serialization::portable_binary::from_file(person, "person.bin2", 0); +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::to_string(person); + qx::serialization::to_file_compressed(person, "person.zip"); + qx::serialization::from_file_compressed(person, "person.zip"); +#else // _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::qt::to_string(person); + qx::serialization::qt::to_file_compressed(person, "person.zip"); + qx::serialization::qt::from_file_compressed(person, "person.zip"); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + //-------------------------------- + + CUser user; + std::shared_ptr userClone = qx::clone(user); + qx::create("CUserXXX"); + + qx::cache::max_cost(2); + qx::cache::set("user", userClone); + qx::cache::set("object", ptrTmp); + qx::cache::set("person", personClone); + qAssert(qx::cache::count() == 2); + ptrTmp = qx::cache::get< std::shared_ptr >("object"); + qx_bool bCacheOk = qx::cache::get("user", userClone); + qAssert(! bCacheOk && (ptrTmp.get() != NULL)); + + std::shared_ptr personValidate = qx::clone(person); + if (! personValidate) { personValidate.reset(new qx::test::CPerson()); } + personValidate->setLastName("admin"); + personValidate->setDouble(305.86); + qx::QxInvalidValueX invalidValues = qx::validate(personValidate); + QString sInvalidValues = invalidValues.text(); + qDebug("[QxOrm] test 'QxValidator' module :\n%s", qPrintable(sInvalidValues)); + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_binary::to_file(user, "user.bin"); + qx::serialization::polymorphic_binary::from_file(user, "user.bin"); + qx::serialization::polymorphic_xml::to_file(user, "user.xml"); + qx::serialization::polymorphic_xml::from_file(user, "user.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_BINARY + qx::serialization::binary::to_file(user, "user.bin"); + qx::serialization::binary::from_file(user, "user.bin"); +#endif // _QX_SERIALIZE_BINARY + +#if _QX_SERIALIZE_TEXT + qx::serialization::text::to_file(user, "user.txt"); + qx::serialization::text::from_file(user, "user.txt"); +#endif // _QX_SERIALIZE_TEXT + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(user, "user.xml"); + qx::serialization::xml::from_file(user, "user.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(user, "user.json"); + qx::serialization::json::from_file(user, "user.json"); +#endif // _QX_NO_JSON + +#if _QX_SERIALIZE_PORTABLE_BINARY + qx::serialization::portable_binary::to_file(user, "user.bin2", 0); + qx::serialization::portable_binary::from_file(user, "user.bin2", 0); +#endif // _QX_SERIALIZE_PORTABLE_BINARY + +#ifdef _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::to_string(user); + qx::serialization::to_file_compressed(user, "user.zip"); + qx::serialization::from_file_compressed(user, "user.zip"); +#else // _QX_ENABLE_BOOST_SERIALIZATION + qx::serialization::qt::to_string(user); + qx::serialization::qt::to_file_compressed(user, "user.zip"); + qx::serialization::qt::from_file_compressed(user, "user.zip"); +#endif // _QX_ENABLE_BOOST_SERIALIZATION + + //-------------------------------- + + qx::any resultInvoke; + CUser * pUser = new CUser(); // You find a memory leak !!! + pUser->test(); + qx_bool bInvokeOk = qx::QxClass::invoke("fct_getPersonId", pUser); qAssert(bInvokeOk); + bInvokeOk = qx::QxClassX::invoke("CUser", "fct_getPersonId", pUser); qAssert(bInvokeOk); + bInvokeOk = qx::QxClassX::invokeStatic("CUser", "fct_testStaticFct", "182", (& resultInvoke)); qAssert(bInvokeOk.getValue() && (qx::any_cast(resultInvoke) == 182)); + + // Other way to invoke a function with parameters encapsulated in a list of qx::any : std::vector + resultInvoke = qx::any(); + std::vector lstParams; + QString invokeParam1 = "238"; + lstParams.push_back(invokeParam1); + bInvokeOk = qx::QxClassX::invokeStatic("CUser", "fct_testStaticFct", lstParams, (& resultInvoke)); + qAssert(bInvokeOk.getValue() && (qx::any_cast(resultInvoke) == 238)); + + //-------------------------------- + + typedef QSharedPointer CUser_ptr; + qx::QxCollection coll; + CUser_ptr p1(new CUser()); + CUser_ptr p2(new CUser()); + coll.insert(0, p1); + coll.insert(1, p2); + + { + // Test qx::IxCollection interface using a smart-pointer (test also qx::any_cast_dynamic::get(...) function) + QSharedPointer pTestIxCollection = coll._get< QSharedPointer >(1); + Q_UNUSED(pTestIxCollection); + } + +#if _QX_SERIALIZE_POLYMORPHIC + qx::serialization::polymorphic_xml::to_file(coll, "collection.xml"); +#endif // _QX_SERIALIZE_POLYMORPHIC + +#if _QX_SERIALIZE_XML + qx::serialization::xml::to_file(coll, "collection.xml"); +#endif // _QX_SERIALIZE_XML + +#ifndef _QX_NO_JSON + qx::serialization::json::to_file(coll, "collection.json"); +#endif // _QX_NO_JSON + + //-------------------------------- + + qx::any any_ret; + qx::IxFunction_ptr pFct1 = qx::function::bind_fct_0(& test_fct); + qx_bool bInvoke = pFct1->invoke(); + + qx::IxFunction_ptr pFct2 = qx::function::bind_member_fct_0(std::mem_fn(& test_class_fct::class_fct)); // using std::mem_fn() here is just a workaround for an issue with some versions of MSVC, it is not required with a full compliant C++11 compiler (http://stackoverflow.com/questions/23778883/vs2013-stdfunction-with-member-function) + test_class_fct o_test_class_fct; + bInvoke = pFct2->invoke(& o_test_class_fct, "", (& any_ret)); + int iReturnByInvoke = qx::any_cast(any_ret); + Q_UNUSED(iReturnByInvoke); + + //-------------------------------- + + CTestAll::test(); + + //-------------------------------- + + QString sTestCvt = qx::cvt::to_string(18, "%03d"); + sTestCvt = qx::cvt::to_string(int(4)); + sTestCvt = qx::cvt::to_string(QDateTime::currentDateTime()); + sTestCvt = qx::cvt::to_string(pUser); + sTestCvt = qx::cvt::to_string(p1, "%08d"); + QObject dummy_01; Q_UNUSED(dummy_01); // sTestCvt = qx::cvt::to_string(dummy_01); + CTestAll dummy_02; sTestCvt = qx::cvt::to_string(dummy_02); + + qx_bool bCvtOk = qx::cvt::from_string("34", pUser); + sTestCvt = qx::cvt::to_string(pUser); + + QVariant sTestCvtVar = qx::cvt::to_variant(QTime::currentTime()); + QVariant dummy_03; bCvtOk = qx::cvt::from_variant(dummy_03, p1); + + QVector< std::shared_ptr > lstCvtTest; + std::shared_ptr pp1; pp1.reset(new CUser()); lstCvtTest.push_back(pp1); + std::shared_ptr pp2; lstCvtTest.push_back(pp2); + std::shared_ptr pp3; pp3.reset(new CUser()); lstCvtTest.push_back(pp3); + sTestCvt = qx::cvt::to_string(lstCvtTest); + lstCvtTest.remove(1); + bCvtOk = qx::cvt::from_string(sTestCvt, lstCvtTest); + qAssert(lstCvtTest.size() == 3); + + //-------------------------------- + + QFile::remove("./database.db"); + + qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); + qx::QxSqlDatabase::getSingleton()->setDatabaseName("database.db"); + qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); + qx::QxSqlDatabase::getSingleton()->setUserName("root"); + qx::QxSqlDatabase::getSingleton()->setPassword(""); + qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle(qx::QxSqlDatabase::ph_style_2_point_name); + qx::QxSqlDatabase::getSingleton()->setTraceSqlQuery(true); + qx::QxSqlDatabase::getSingleton()->setTraceSqlRecord(false); + + // Only for debug purpose : assert if invalid offset detected fetching a relation + qx::QxSqlDatabase::getSingleton()->setVerifyOffsetRelation(true); + + qx::test::CPerson * pBrother = new qx::test::CPerson(); + pBrother->setFirstName("brother firstname"); + pBrother->setLastName("brother lastname"); + pUser->setBrother(pBrother); + pUser->setLastName("user lastname"); + + QSqlError daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + daoError = qx::dao::insert(pBrother); + long lBrotherId = pBrother->getPersonId(); + daoError = qx::dao::insert(pUser); + long lDaoCount = qx::dao::count(); qAssert(lDaoCount == 1); + pUser->setBrother(NULL); + daoError = qx::dao::fetch_by_id(pUser); qAssert(pUser->getBrother() && (pUser->getBrother()->getPersonId() == lBrotherId)); + pUser->setBrother(NULL); + daoError = qx::dao::fetch_by_id_with_relation("brother", pUser); qAssert(pUser->getBrother() && (pUser->getBrother()->getFirstName() == "brother firstname")); + qx_bool bDaoExist = qx::dao::exist(pUser); qAssert(bDaoExist); + daoError = qx::dao::update(pUser); + daoError = qx::dao::delete_by_id(pUser); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 0); + daoError = qx::dao::save(pUser); + daoError = qx::dao::save(pUser); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 1); + daoError = qx::dao::delete_all(); + bDaoExist = qx::dao::exist(pUser); qAssert(! bDaoExist); + pUser->setBrother(NULL); + + typedef qx::QxCollection< long, std::shared_ptr > type_lstUser; + std::shared_ptr ppp1; ppp1.reset(new CUser(53)); + ppp1->setProfil("profil 10"); + ppp1->setLastName("ppp1 lastname"); + std::shared_ptr ppp2; ppp2.reset(new CUser(108)); + ppp2->setDateModif(QDateTime::currentDateTime()); + ppp2->setLastName("ppp1 lastname"); + type_lstUser lstUser; + lstUser.insert(ppp1->getUserId(), ppp1); + lstUser.insert(ppp2->getUserId(), ppp2); + + QString sQuery1 = "WHERE profil LIKE '%pro%'"; + QString sQuery2 = "LIMIT 1"; + qx::QxSqlQuery qxQuery1("WHERE profil LIKE :profil"); + qxQuery1.bind(":profil", "%pro%"); + + daoError = qx::dao::insert(lstUser); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 2); + lDaoCount = qx::dao::count(sQuery1); qAssert(lDaoCount == 1); + lDaoCount = qx::dao::count(qxQuery1); qAssert(lDaoCount == 1); + daoError = qx::dao::fetch_by_id(lstUser); + bDaoExist = qx::dao::exist(lstUser); qAssert(bDaoExist); + daoError = qx::dao::update(lstUser); + daoError = qx::dao::delete_by_id(lstUser); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 0); + daoError = qx::dao::save(lstUser); + + pBrother = new qx::test::CPerson(); + pBrother->setFirstName("brother firstname from collection"); + pBrother->setLastName("brother lastname from collection"); + lstUser.getByIndex(0)->setBrother(pBrother); + + daoError = qx::dao::insert(pBrother); + lBrotherId = pBrother->getPersonId(); + daoError = qx::dao::save(lstUser); + daoError = qx::dao::fetch_by_query(sQuery2, lstUser); qAssert(lstUser.size() == 1); + daoError = qx::dao::fetch_all_with_all_relation(lstUser); qAssert((lstUser.size() == 2) && lstUser.getByIndex(0)->getBrother() && (lstUser.getByIndex(0)->getBrother()->getLastName() == "brother lastname from collection")); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 2); + daoError = qx::dao::fetch_all(lstUser); qAssert(lstUser.size() == 2); + daoError = qx::dao::delete_by_query(sQuery1); + lDaoCount = qx::dao::count(); qAssert(lDaoCount == 1); + daoError = qx::dao::delete_all(); + bDaoExist = qx::dao::exist(lstUser); qAssert(! bDaoExist); + daoError = qx::dao::fetch_all(lstUser); qAssert(lstUser.size() == 0); + + //-------------------------------- + + daoError = qx::dao::create_table(); + daoError = qx::dao::create_table(); + + Foo_ptr pFoo; + pFoo.reset(new Foo()); pFoo->setName("name1"); pFoo->setDesc("desc1"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 1); + pFoo.reset(new Foo()); pFoo->setName("name2"); pFoo->setDesc("desc2"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 2); + pFoo.reset(new Foo()); pFoo->setName("name3"); pFoo->setDesc("desc3"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 3); + pFoo.reset(new Foo()); pFoo->setName("name4"); pFoo->setDesc("desc4"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 4); + pFoo.reset(new Foo()); pFoo->setName("name5"); pFoo->setDesc("desc5"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 5); + pFoo.reset(new Foo()); pFoo->setName("name6"); pFoo->setDesc("desc6"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 6); + pFoo.reset(new Foo()); pFoo->setName("name7"); pFoo->setDesc("desc7"); daoError = qx::dao::save(pFoo); qAssert(pFoo->getId() == 7); + + // Test qx::IxPersistable interface + daoError = pFoo->qxFetchById(); qAssert(! daoError.isValid()); + daoError = pFoo->qxUpdate(); qAssert(! daoError.isValid()); + lDaoCount = pFoo->qxCount(); qAssert(lDaoCount == 7); + invalidValues = pFoo->qxValidate(); qAssert(invalidValues.count() == 0); + +#ifndef _QX_NO_JSON + QString fooAsJson = pFoo->toJson(); qDebug("[QxOrm] qx::IxPersistable::toJson() test 1 :\n%s", qPrintable(fooAsJson)); + qx::IxPersistable * pFooPersistable = static_cast(pFoo.get()); + fooAsJson = qx::serialization::json::to_string(* pFooPersistable); + qDebug("[QxOrm] qx::IxPersistable::toJson() test 2 :\n%s", qPrintable(fooAsJson)); + + qx::IxPersistableCollection_ptr pFooPersistableCollection = qx::IxPersistable::qxFetchAll("Foo"); + qAssert(pFooPersistableCollection && (pFooPersistableCollection->__count() != 0)); + fooAsJson = pFooPersistableCollection->toJson(); + qDebug("[QxOrm] qx::IxPersistableCollection::toJson() test 3 :\n%s", qPrintable(fooAsJson)); + daoError = pFooPersistableCollection->qxSave(); qAssert(! daoError.isValid()); + + QStringList emptyColumnsRelations; + pFooPersistableCollection = qx::IxPersistable::qxFetchAll("Foo", emptyColumnsRelations, emptyColumnsRelations, NULL, true); + qAssert(pFooPersistableCollection && (pFooPersistableCollection->__count() != 0)); + fooAsJson = pFooPersistableCollection->toJson(); + qDebug("[QxOrm] qx::IxPersistableCollection::toJson() test 4 :\n%s", qPrintable(fooAsJson)); + daoError = pFooPersistableCollection->qxSave(); qAssert(! daoError.isValid()); +#endif // _QX_NO_JSON + + Bar_ptr pBar; + pBar.reset(new Bar()); pBar->setCode("code1"); pBar->setValue("value1"); pBar->setFoo(3); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 1); + pBar.reset(new Bar()); pBar->setCode("code2"); pBar->setValue("value2"); pBar->setFoo(3); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 2); + pBar.reset(new Bar()); pBar->setCode("code3"); pBar->setValue("value3"); pBar->setFoo(2); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 3); + pBar.reset(new Bar()); pBar->setCode("code4"); pBar->setValue("value4"); pBar->setFoo(3); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 4); + pBar.reset(new Bar()); pBar->setCode("code5"); pBar->setValue("value5"); pBar->setFoo(2); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 5); + pBar.reset(new Bar()); pBar->setCode("code6"); pBar->setValue("value6"); pBar->setFoo(6); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 6); + pBar.reset(new Bar()); pBar->setCode("code7"); pBar->setValue("value7"); pBar->setFoo(3); daoError = qx::dao::save(pBar); qAssert(pBar->getId() == 7); + + // Test inserting a complex QVariant in database + pFoo.reset(new Foo()); pFoo->setId(3); daoError = pFoo->qxFetchById(); qAssert(! daoError.isValid()); + QMap testComplexVariant; testComplexVariant.insert("key_1", QVariant(QString("val_1"))); + QList testComplexVariantItem; testComplexVariantItem.append(QVariant(QString("val_2_inside_QVariantList"))); + testComplexVariantItem.append(QVariant(QString("val_3_inside_QVariantList"))); + testComplexVariant.insert("key_2", QVariant(testComplexVariantItem)); + pFoo->setDesc(testComplexVariant); + daoError = pFoo->qxUpdate(); qAssert(! daoError.isValid()); + + pFoo.reset(new Foo()); pFoo->setId(3); + daoError = qx::dao::fetch_by_id_with_relation("lstBar", pFoo); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 4)); qx::dump((* pFoo), true); + pFoo.reset(new Foo()); pFoo->setId(4); + daoError = qx::dao::fetch_by_id_with_relation("lstBar", pFoo); qAssert(! pFoo->getBarX() || (pFoo->getBarX()->size() == 0)); + pFoo.reset(new Foo()); pFoo->setId(2); + daoError = qx::dao::fetch_by_id_with_relation("lstBar", pFoo); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 2)); + + FooX_ptr pFooX; pFooX.reset(new FooX()); + daoError = qx::dao::fetch_all_with_all_relation(pFooX); qAssert(pFooX->size() == 7); + pFoo = pFooX->getByKey(3); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 4)); + pFoo = pFooX->getByKey(4); qAssert(! pFoo->getBarX() || (pFoo->getBarX()->size() == 0)); + pFoo = pFooX->getByKey(2); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 2)); + + { + // Test eager fetching an instance (with relationships) which is not a pointer or smart-pointer + QList pFooX1; daoError = qx::dao::fetch_all_with_all_relation(pFooX1); qAssert(pFooX1.size() == 7); + QHash pFooX2; daoError = qx::dao::fetch_all_with_all_relation(pFooX2); qAssert(pFooX2.size() == 7); + qx::QxCollection pFooX3; daoError = qx::dao::fetch_all_with_all_relation(pFooX3); qAssert(pFooX3.size() == 7); + +#ifdef _QX_ENABLE_BOOST +#if (BOOST_VERSION >= 105000) + boost::unordered_map pFooX4; daoError = qx::dao::fetch_all_with_all_relation(pFooX4); qAssert(pFooX4.size() == 7); +#endif // (BOOST_VERSION >= 105000) +#endif // _QX_ENABLE_BOOST + + std::vector pFooX5; daoError = qx::dao::fetch_all_with_all_relation(pFooX5); qAssert(pFooX5.size() == 7); + QSet pFooX6; daoError = qx::dao::fetch_all_with_all_relation(pFooX6); qAssert(pFooX6.size() == 7); Q_FOREACH(Foo * pFooTemp, pFooX6) { delete pFooTemp; } + std::set pFooX7; daoError = qx::dao::fetch_all_with_all_relation(pFooX7); qAssert(pFooX7.size() == 7); + +#ifdef _QX_ENABLE_BOOST + boost::unordered_set pFooX8; daoError = qx::dao::fetch_all_with_all_relation(pFooX8); qAssert(pFooX8.size() == 7); +#endif // _QX_ENABLE_BOOST + } + + pBar.reset(new Bar()); pBar->setId(7); + daoError = qx::dao::fetch_by_id_with_relation("foo_id", pBar); qAssert(pBar->getFoo() && (pBar->getFoo()->getName() == "name3")); + pFoo = pBar->getFoo(); if (pFoo) { pFoo->setDate(QDate::currentDate()); pFoo->setTime(QTime::currentTime()); pFoo->setDateTime(QDateTime::currentDateTime()); } + qx::dump(pBar, false); + qx::dump(pBar, true); + + // Test soft delete behavior + pBar.reset(new Bar()); + pBar->setId(5); + daoError = qx::dao::delete_by_id(pBar); qAssert(! daoError.isValid()); // This Bar item is now soft-deleted in database + bDaoExist = qx::dao::exist(pBar); qAssert(! bDaoExist); + daoError = qx::dao::delete_all(); qAssert(! daoError.isValid()); // All Bar items are now soft-deleted in database + long lBarCount = qx::dao::count(); qAssert(lBarCount == 0); Q_UNUSED(lBarCount); + + { + // Fetch soft-deleted items from database using session and ignoreSoftDelete() behavior + qx::QxSession session; + session.ignoreSoftDelete(); // The second parameter allows to select classes to ignore soft delete behavior (by default, if empty, then all classes are ignored) + BarX lstOfSoftDeletedBars; + daoError = session.fetchAll(lstOfSoftDeletedBars); + qAssert((! daoError.isValid()) && (lstOfSoftDeletedBars.size() > 0)); + lBarCount = session.count(); qAssert(lBarCount > 0); Q_UNUSED(lBarCount); + + // Try to fetch soft-deleted items from database through relationships + pFooX.reset(new FooX()); + daoError = session.fetchAll(pFooX, QStringList(), QStringList() << "lstBar"); + qAssert((! daoError.isValid()) && (pFooX->size() == 7)); + pFoo = pFooX->getByKey(3); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 4)); + pFoo = pFooX->getByKey(4); qAssert(! pFoo->getBarX() || (pFoo->getBarX()->size() == 0)); + pFoo = pFooX->getByKey(2); qAssert(pFoo->getBarX() && (pFoo->getBarX()->size() == 2)); + + // Remove physically items in database even if a soft delete behavior has been defined (using destroy functions) + daoError = session.destroyAll(); qAssert(! daoError.isValid()); + daoError = session.fetchAll(lstOfSoftDeletedBars); + qAssert((! daoError.isValid()) && (lstOfSoftDeletedBars.size() == 0)); + lBarCount = session.count(); qAssert(lBarCount == 0); Q_UNUSED(lBarCount); + } + + { + pFoo.reset(new Foo()); pFoo->setName("name10"); pFoo->setDesc("desc10"); + pFoo->setDate(QDate::currentDate()); pFoo->setTime(QTime::currentTime()); pFoo->setDateTime(QDateTime::currentDateTime()); +#ifdef _QX_ENABLE_BOOST + boost::optional optionalString("test boost optional"); pFoo->setOptString(optionalString); +#endif // _QX_ENABLE_BOOST + + // Test session to manage automatically database transactions (using C++ RAII) + qx::QxSession session; + session += qx::dao::insert(pFoo, session.database()); + session += qx::dao::update(pFoo, session.database()); + session += qx::dao::fetch_by_id(pFoo, session.database()); + session += qx::dao::delete_by_id(pFoo, session.database()); + qAssert(session.isValid()); + } + + //-------------------------------- + + // Dump all registered classes into QxOrm context (introspection engine) + qx::QxClassX::dumpAllClasses(); + + pBar.reset(new Bar()); + qx::IxDataMember * pDataMember = qx::QxClassX::getDataMember("Bar", "code"); qAssert(pDataMember != NULL); + bool bIntrospectionOk = pDataMember->setValue(pBar.get(), QString("test introspection engine")); qAssert(bIntrospectionOk); + QString sIntrospectionTest = pDataMember->getValue(pBar.get(), (& bIntrospectionOk)); + qAssert(bIntrospectionOk && (sIntrospectionTest == "test introspection engine")); + qAssert(pBar->getCode() == "test introspection engine"); + + //-------------------------------- + + daoError = qx::dao::create_table(); + TestQtProperty testQtMetaProperty; + QString sQtPropertyDesc = "test Qt introspection engine : meta-property using Q_PROPERTY() macro"; + testQtMetaProperty.setDesc(sQtPropertyDesc); + testQtMetaProperty.setBirthDate(QDateTime::currentDateTime()); + daoError = qx::dao::insert(testQtMetaProperty); qAssert(! daoError.isValid()); + daoError = qx::dao::fetch_by_id(testQtMetaProperty); qAssert(! daoError.isValid()); + qx::IxDataMember * pQtMetaProperty = qx::QxClassX::getDataMember("TestQtProperty", "desc"); Q_UNUSED(pQtMetaProperty); + qAssert(pQtMetaProperty && pQtMetaProperty->getValue(& testQtMetaProperty) == sQtPropertyDesc); + qx::dump(testQtMetaProperty, false); + qx::dump(testQtMetaProperty, true); + + //-------------------------------- + + QDateTime queryDT1, queryDT2; + qx_query queryToTest; + queryToTest.where("sex").isEqualTo("female") + .and_("age").isGreaterThan(38) + .or_("last_name").isNotEqualTo("Dupont") + .or_("first_name").like("Alfred") + .and_OpenParenthesis("id").isLessThanOrEqualTo(999) + .and_("birth_date").isBetween(queryDT1, queryDT2) + .closeParenthesis() + .or_("id").in(50, 999, 11, 23, 78945) + .and_("is_deleted").isNotNull() + .orderAsc("last_name", "first_name", "sex") + .limit(50, 150); + + QString sQueryToTest = queryToTest.query(); + qDebug("[QxOrm] test SQL query using C++ syntax : '%s'", qPrintable(sQueryToTest)); + + //-------------------------------- + + qx::QxRepository repositoryFoo; + pFooX.reset(new FooX()); + daoError = repositoryFoo.fetchAll(pFooX); + qAssert(! daoError.isValid()); + Foo_ptr pFooTmp; + pFooTmp.reset(repositoryFoo.fetchById(3)); + if (pFooTmp) + { + pFooTmp->setDesc("desc_modified"); + daoError = repositoryFoo.save(pFooTmp); + qAssert(! daoError.isValid()); + } + + //-------------------------------- + + // Just to check compilation of model/view template class + qx::IxModel * pModel = new qx::QxModel(); + Q_UNUSED(pModel); + + //-------------------------------- + + qAssert(qx::QxClassX::implementIxPersistable("qx::QxPersistable")); + qAssert(qx::QxClassX::implementIxPersistable("Bar")); + + qx::cache::clear(); + + return 0; +} diff --git a/tools/_build_debug.bat b/tools/_build_debug.bat new file mode 100644 index 0000000..0b70b45 --- /dev/null +++ b/tools/_build_debug.bat @@ -0,0 +1,2 @@ +qmake %QXORM_QMAKE_PARAMS% +nmake debug diff --git a/tools/_build_release.bat b/tools/_build_release.bat new file mode 100644 index 0000000..eb095a3 --- /dev/null +++ b/tools/_build_release.bat @@ -0,0 +1,2 @@ +qmake %QXORM_QMAKE_PARAMS% +nmake release diff --git a/tools/_clean_debug.bat b/tools/_clean_debug.bat new file mode 100644 index 0000000..8344b5d --- /dev/null +++ b/tools/_clean_debug.bat @@ -0,0 +1,6 @@ +cd "./debug/" +del /F /S /Q "./*.*" +cd "../lib/" +del /F /S /Q "./QxOrmd.*" +cd "../" +del /F /S /Q "./vc90.pdb" diff --git a/tools/_clean_release.bat b/tools/_clean_release.bat new file mode 100644 index 0000000..ed4adb4 --- /dev/null +++ b/tools/_clean_release.bat @@ -0,0 +1,5 @@ +cd "./release/" +del /F /S /Q "./*.*" +cd "../lib/" +del /F /S /Q "./QxOrm.*" +cd "../" diff --git a/tools/clean_all.bat b/tools/clean_all.bat new file mode 100644 index 0000000..da287c2 --- /dev/null +++ b/tools/clean_all.bat @@ -0,0 +1,571 @@ +cd "../" +call "./tools/_clean_debug.bat" +call "./tools/_clean_release.bat" +rmdir /S /Q "./obj/" +del /F /S /Q /A "*.suo" +del /F /S /Q "./QxOrm.sdf" +del /F /S /Q "./QxOrm.ncb" +del /F /S /Q "./QxOrm.vcproj.A*" +del /F /S /Q "./QxOrm.vcproj.B*" +del /F /S /Q "./QxOrm.vcproj.C*" +del /F /S /Q "./QxOrm.vcproj.D*" +del /F /S /Q "./QxOrm.vcproj.E*" +del /F /S /Q "./QxOrm.vcproj.F*" +del /F /S /Q "./QxOrm.vcproj.G*" +del /F /S /Q "./QxOrm.vcproj.H*" +del /F /S /Q "./QxOrm.vcproj.I*" +del /F /S /Q "./QxOrm.vcproj.J*" +del /F /S /Q "./QxOrm.vcproj.K*" +del /F /S /Q "./QxOrm.vcproj.L*" +del /F /S /Q "./QxOrm.vcproj.M*" +del /F /S /Q "./QxOrm.vcproj.N*" +del /F /S /Q "./QxOrm.vcproj.O*" +del /F /S /Q "./QxOrm.vcproj.P*" +del /F /S /Q "./QxOrm.vcproj.Q*" +del /F /S /Q "./QxOrm.vcproj.R*" +del /F /S /Q "./QxOrm.vcproj.S*" +del /F /S /Q "./QxOrm.vcproj.T*" +del /F /S /Q "./QxOrm.vcproj.U*" +del /F /S /Q "./QxOrm.vcproj.V*" +del /F /S /Q "./QxOrm.vcproj.W*" +del /F /S /Q "./QxOrm.vcproj.X*" +del /F /S /Q "./QxOrm.vcproj.Y*" +del /F /S /Q "./QxOrm.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "./test/qxDllSample/" +rmdir /S /Q "./obj/" +del /F /S /Q "./test.sdf" +del /F /S /Q "./test.ncb" +cd "../../test/qxBlog/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxDllSample/dll1/" +rmdir /S /Q "./obj/" +del /F /S /Q "./dll1.sdf" +del /F /S /Q "./dll1.ncb" +del /F /S /Q "./dll1.vcproj.A*" +del /F /S /Q "./dll1.vcproj.B*" +del /F /S /Q "./dll1.vcproj.C*" +del /F /S /Q "./dll1.vcproj.D*" +del /F /S /Q "./dll1.vcproj.E*" +del /F /S /Q "./dll1.vcproj.F*" +del /F /S /Q "./dll1.vcproj.G*" +del /F /S /Q "./dll1.vcproj.H*" +del /F /S /Q "./dll1.vcproj.I*" +del /F /S /Q "./dll1.vcproj.J*" +del /F /S /Q "./dll1.vcproj.K*" +del /F /S /Q "./dll1.vcproj.L*" +del /F /S /Q "./dll1.vcproj.M*" +del /F /S /Q "./dll1.vcproj.N*" +del /F /S /Q "./dll1.vcproj.O*" +del /F /S /Q "./dll1.vcproj.P*" +del /F /S /Q "./dll1.vcproj.Q*" +del /F /S /Q "./dll1.vcproj.R*" +del /F /S /Q "./dll1.vcproj.S*" +del /F /S /Q "./dll1.vcproj.T*" +del /F /S /Q "./dll1.vcproj.U*" +del /F /S /Q "./dll1.vcproj.V*" +del /F /S /Q "./dll1.vcproj.W*" +del /F /S /Q "./dll1.vcproj.X*" +del /F /S /Q "./dll1.vcproj.Y*" +del /F /S /Q "./dll1.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/qxDllSample/dll2/" +rmdir /S /Q "./obj/" +del /F /S /Q "./dll2.sdf" +del /F /S /Q "./dll2.ncb" +del /F /S /Q "./dll2.vcproj.A*" +del /F /S /Q "./dll2.vcproj.B*" +del /F /S /Q "./dll2.vcproj.C*" +del /F /S /Q "./dll2.vcproj.D*" +del /F /S /Q "./dll2.vcproj.E*" +del /F /S /Q "./dll2.vcproj.F*" +del /F /S /Q "./dll2.vcproj.G*" +del /F /S /Q "./dll2.vcproj.H*" +del /F /S /Q "./dll2.vcproj.I*" +del /F /S /Q "./dll2.vcproj.J*" +del /F /S /Q "./dll2.vcproj.K*" +del /F /S /Q "./dll2.vcproj.L*" +del /F /S /Q "./dll2.vcproj.M*" +del /F /S /Q "./dll2.vcproj.N*" +del /F /S /Q "./dll2.vcproj.O*" +del /F /S /Q "./dll2.vcproj.P*" +del /F /S /Q "./dll2.vcproj.Q*" +del /F /S /Q "./dll2.vcproj.R*" +del /F /S /Q "./dll2.vcproj.S*" +del /F /S /Q "./dll2.vcproj.T*" +del /F /S /Q "./dll2.vcproj.U*" +del /F /S /Q "./dll2.vcproj.V*" +del /F /S /Q "./dll2.vcproj.W*" +del /F /S /Q "./dll2.vcproj.X*" +del /F /S /Q "./dll2.vcproj.Y*" +del /F /S /Q "./dll2.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/qxDllSample/exe/" +rmdir /S /Q "./obj/" +del /F /S /Q "./exe.sdf" +del /F /S /Q "./exe.ncb" +del /F /S /Q "./exe.vcproj.A*" +del /F /S /Q "./exe.vcproj.B*" +del /F /S /Q "./exe.vcproj.C*" +del /F /S /Q "./exe.vcproj.D*" +del /F /S /Q "./exe.vcproj.E*" +del /F /S /Q "./exe.vcproj.F*" +del /F /S /Q "./exe.vcproj.G*" +del /F /S /Q "./exe.vcproj.H*" +del /F /S /Q "./exe.vcproj.I*" +del /F /S /Q "./exe.vcproj.J*" +del /F /S /Q "./exe.vcproj.K*" +del /F /S /Q "./exe.vcproj.L*" +del /F /S /Q "./exe.vcproj.M*" +del /F /S /Q "./exe.vcproj.N*" +del /F /S /Q "./exe.vcproj.O*" +del /F /S /Q "./exe.vcproj.P*" +del /F /S /Q "./exe.vcproj.Q*" +del /F /S /Q "./exe.vcproj.R*" +del /F /S /Q "./exe.vcproj.S*" +del /F /S /Q "./exe.vcproj.T*" +del /F /S /Q "./exe.vcproj.U*" +del /F /S /Q "./exe.vcproj.V*" +del /F /S /Q "./exe.vcproj.W*" +del /F /S /Q "./exe.vcproj.X*" +del /F /S /Q "./exe.vcproj.Y*" +del /F /S /Q "./exe.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.db" +del /F /S /Q "./*.xml" +del /F /S /Q "./*.bin" +del /F /S /Q "./*.zip" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/qxBlogCompositeKey/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxBlogModelView/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxBlogMongoDB/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxBlogRestApi/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxBlogPImpl/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxBlogCpp11/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxBlog.sdf" +del /F /S /Q "./qxBlog.ncb" +del /F /S /Q "./qxBlog.vcproj.A*" +del /F /S /Q "./qxBlog.vcproj.B*" +del /F /S /Q "./qxBlog.vcproj.C*" +del /F /S /Q "./qxBlog.vcproj.D*" +del /F /S /Q "./qxBlog.vcproj.E*" +del /F /S /Q "./qxBlog.vcproj.F*" +del /F /S /Q "./qxBlog.vcproj.G*" +del /F /S /Q "./qxBlog.vcproj.H*" +del /F /S /Q "./qxBlog.vcproj.I*" +del /F /S /Q "./qxBlog.vcproj.J*" +del /F /S /Q "./qxBlog.vcproj.K*" +del /F /S /Q "./qxBlog.vcproj.L*" +del /F /S /Q "./qxBlog.vcproj.M*" +del /F /S /Q "./qxBlog.vcproj.N*" +del /F /S /Q "./qxBlog.vcproj.O*" +del /F /S /Q "./qxBlog.vcproj.P*" +del /F /S /Q "./qxBlog.vcproj.Q*" +del /F /S /Q "./qxBlog.vcproj.R*" +del /F /S /Q "./qxBlog.vcproj.S*" +del /F /S /Q "./qxBlog.vcproj.T*" +del /F /S /Q "./qxBlog.vcproj.U*" +del /F /S /Q "./qxBlog.vcproj.V*" +del /F /S /Q "./qxBlog.vcproj.W*" +del /F /S /Q "./qxBlog.vcproj.X*" +del /F /S /Q "./qxBlog.vcproj.Y*" +del /F /S /Q "./qxBlog.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.sqlite" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../" +cd "../../test/qxClientServer/qxClient/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxClient.sdf" +del /F /S /Q "./qxClient.ncb" +del /F /S /Q "./qxClient.vcproj.A*" +del /F /S /Q "./qxClient.vcproj.B*" +del /F /S /Q "./qxClient.vcproj.C*" +del /F /S /Q "./qxClient.vcproj.D*" +del /F /S /Q "./qxClient.vcproj.E*" +del /F /S /Q "./qxClient.vcproj.F*" +del /F /S /Q "./qxClient.vcproj.G*" +del /F /S /Q "./qxClient.vcproj.H*" +del /F /S /Q "./qxClient.vcproj.I*" +del /F /S /Q "./qxClient.vcproj.J*" +del /F /S /Q "./qxClient.vcproj.K*" +del /F /S /Q "./qxClient.vcproj.L*" +del /F /S /Q "./qxClient.vcproj.M*" +del /F /S /Q "./qxClient.vcproj.N*" +del /F /S /Q "./qxClient.vcproj.O*" +del /F /S /Q "./qxClient.vcproj.P*" +del /F /S /Q "./qxClient.vcproj.Q*" +del /F /S /Q "./qxClient.vcproj.R*" +del /F /S /Q "./qxClient.vcproj.S*" +del /F /S /Q "./qxClient.vcproj.T*" +del /F /S /Q "./qxClient.vcproj.U*" +del /F /S /Q "./qxClient.vcproj.V*" +del /F /S /Q "./qxClient.vcproj.W*" +del /F /S /Q "./qxClient.vcproj.X*" +del /F /S /Q "./qxClient.vcproj.Y*" +del /F /S /Q "./qxClient.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.db" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/qxClientServer/qxServer/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxServer.sdf" +del /F /S /Q "./qxServer.ncb" +del /F /S /Q "./qxServer.vcproj.A*" +del /F /S /Q "./qxServer.vcproj.B*" +del /F /S /Q "./qxServer.vcproj.C*" +del /F /S /Q "./qxServer.vcproj.D*" +del /F /S /Q "./qxServer.vcproj.E*" +del /F /S /Q "./qxServer.vcproj.F*" +del /F /S /Q "./qxServer.vcproj.G*" +del /F /S /Q "./qxServer.vcproj.H*" +del /F /S /Q "./qxServer.vcproj.I*" +del /F /S /Q "./qxServer.vcproj.J*" +del /F /S /Q "./qxServer.vcproj.K*" +del /F /S /Q "./qxServer.vcproj.L*" +del /F /S /Q "./qxServer.vcproj.M*" +del /F /S /Q "./qxServer.vcproj.N*" +del /F /S /Q "./qxServer.vcproj.O*" +del /F /S /Q "./qxServer.vcproj.P*" +del /F /S /Q "./qxServer.vcproj.Q*" +del /F /S /Q "./qxServer.vcproj.R*" +del /F /S /Q "./qxServer.vcproj.S*" +del /F /S /Q "./qxServer.vcproj.T*" +del /F /S /Q "./qxServer.vcproj.U*" +del /F /S /Q "./qxServer.vcproj.V*" +del /F /S /Q "./qxServer.vcproj.W*" +del /F /S /Q "./qxServer.vcproj.X*" +del /F /S /Q "./qxServer.vcproj.Y*" +del /F /S /Q "./qxServer.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.db" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/qxClientServer/qxService/" +rmdir /S /Q "./obj/" +del /F /S /Q "./qxService.sdf" +del /F /S /Q "./qxService.ncb" +del /F /S /Q "./qxService.vcproj.A*" +del /F /S /Q "./qxService.vcproj.B*" +del /F /S /Q "./qxService.vcproj.C*" +del /F /S /Q "./qxService.vcproj.D*" +del /F /S /Q "./qxService.vcproj.E*" +del /F /S /Q "./qxService.vcproj.F*" +del /F /S /Q "./qxService.vcproj.G*" +del /F /S /Q "./qxService.vcproj.H*" +del /F /S /Q "./qxService.vcproj.I*" +del /F /S /Q "./qxService.vcproj.J*" +del /F /S /Q "./qxService.vcproj.K*" +del /F /S /Q "./qxService.vcproj.L*" +del /F /S /Q "./qxService.vcproj.M*" +del /F /S /Q "./qxService.vcproj.N*" +del /F /S /Q "./qxService.vcproj.O*" +del /F /S /Q "./qxService.vcproj.P*" +del /F /S /Q "./qxService.vcproj.Q*" +del /F /S /Q "./qxService.vcproj.R*" +del /F /S /Q "./qxService.vcproj.S*" +del /F /S /Q "./qxService.vcproj.T*" +del /F /S /Q "./qxService.vcproj.U*" +del /F /S /Q "./qxService.vcproj.V*" +del /F /S /Q "./qxService.vcproj.W*" +del /F /S /Q "./qxService.vcproj.X*" +del /F /S /Q "./qxService.vcproj.Y*" +del /F /S /Q "./qxService.vcproj.Z*" +del /F /S /Q "./Makefile*" +del /F /S /Q "./vc90.pdb" +del /F /S /Q "./vc110.pdb" +del /F /S /Q "./*.db" +cd "./qt/moc/" +del /F /S /Q "./*.cpp" +cd "../../../" +cd "../../test/_bin/" +del /F /S /Q "./*.*" +cd "../../test/qxDllSample/dll1/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxDllSample/dll1/release/" +del /F /S /Q "./*.*" +cd "../../../../test/qxDllSample/dll2/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxDllSample/dll2/release/" +del /F /S /Q "./*.*" +cd "../../../../test/qxDllSample/exe/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxDllSample/exe/release/" +del /F /S /Q "./*.*" +cd "../../../../test/qxBlog/debug/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlog/release/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogCompositeKey/debug/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogCompositeKey/release/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogModelView/debug/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogModelView/release/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogCpp11/debug/" +del /F /S /Q "./*.*" +cd "../../../test/qxBlogCpp11/release/" +del /F /S /Q "./*.*" +cd "../../../test/qxClientServer/qxClient/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxClientServer/qxClient/release/" +del /F /S /Q "./*.*" +cd "../../../../test/qxClientServer/qxServer/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxClientServer/qxServer/release/" +del /F /S /Q "./*.*" +cd "../../../../test/qxClientServer/qxService/debug/" +del /F /S /Q "./*.*" +cd "../../../../test/qxClientServer/qxService/release/" +del /F /S /Q "./*.*" +cd "../../../../" +cd "./tools/" +call "./gitignore_recursive.bat" +pause diff --git a/tools/gcc_build_all_debug_full.sh b/tools/gcc_build_all_debug_full.sh new file mode 100644 index 0000000..ae57fd3 --- /dev/null +++ b/tools/gcc_build_all_debug_full.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +if [[ $1 == "release" ]]; +then + CONFIG=release +else + CONFIG=debug + SUFFIX=d +fi + +if [[ $2 == "full" ]] || [ -z "$2" ]; +then + QMAKEPARAMS="\"DEFINES += _QX_ENABLE_BOOST_SERIALIZATION\" \"DEFINES += _QX_ENABLE_QT_GUI\" \"DEFINES += _QX_ENABLE_QT_NETWORK\"" +fi + +clear +pwd + +echo "-- BOOST ENVIRONMENT VARIABLES --" +export BOOST_INCLUDE=/usr/include +export BOOST_LIB=/usr/lib +export BOOST_LIB_SERIALIZATION_DEBUG=boost_serialization-mt-d +export BOOST_LIB_SERIALIZATION_RELEASE=boost_serialization-mt +export BOOST_LIB_WIDE_SERIALIZATION_DEBUG=boost_wserialization-mt-d +export BOOST_LIB_WIDE_SERIALIZATION_RELEASE=boost_wserialization-mt + +echo "-- MAKE OPTIONS : USE 8 CORE CPU TO REDUCE BUILD TIMES --" +MAKEOPT=-j8 + +GCCVERSION="$(gcc -dumpversion)" +if [ "$GCCVERSION" = "4.4.1" ]; +then + echo "-- ADD GCC C++11 FEATURES --" + QMAKEPARAMS="$QMAKEPARAMS \"QMAKE_CXXFLAGS += -std=c++0x\"" +fi + +echo "-- BUILD QXORM LIBRARY --" +cd "../" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ./lib/libQxOrm$SUFFIX.so ]; +then + exit 1 +fi +cd "./lib/" +cp libQxOrm$SUFFIX.* "../test/_bin/" +cd "../" + +echo "-- BUILD TEST DLL1 --" +cd "./test/qxDllSample/dll1/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/libdll1$SUFFIX.so ]; +then + exit 1 +fi + +echo "-- BUILD TEST DLL2 --" +cd "../dll2/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/libdll2$SUFFIX.so ]; +then + exit 1 +fi + +echo "-- BUILD TEST EXE --" +cd "../exe/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/exe$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXBLOG --" +cd "../../qxBlog/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../_bin/qxBlog$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXBLOG COMPOSITE KEY --" +cd "../qxBlogCompositeKey/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../_bin/qxBlogCompositeKey$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXBLOG MODEL VIEW --" +cd "../qxBlogModelView/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../_bin/qxBlogModelView$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXBLOG PIMPL IDIOM --" +cd "../qxBlogPImpl/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../_bin/qxBlogPImpl$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXBLOG REST API AND HTTP SERVER --" +cd "../qxBlogRestApi/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../_bin/qxBlogRestApi$SUFFIX ]; +then + exit 1 +fi + +echo "-- CHECK BATCH TYPE : FULL OR MINIMAL --" +if [[ $2 == "minimal" ]]; +then + exit 0 +fi + +echo "-- BUILD TEST QXCLIENTSERVER QXSERVICE --" +cd "../qxClientServer/qxService" +eval qmake $QMAKEPARAMS qxServiceServer.pro +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/libqxServiceServer$SUFFIX.so ]; +then + exit 1 +fi +eval qmake $QMAKEPARAMS qxServiceClient.pro +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/libqxServiceClient$SUFFIX.so ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXCLIENTSERVER QXSERVER --" +cd "../qxServer/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/qxServer$SUFFIX ]; +then + exit 1 +fi + +echo "-- BUILD TEST QXCLIENTSERVER QXCLIENT --" +cd "../qxClient/" +eval qmake $QMAKEPARAMS +make $CONFIG $MAKEOPT +if [ ! -f ../../_bin/qxClient$SUFFIX ]; +then + exit 1 +fi + +exit 0 diff --git a/tools/gcc_build_all_debug_minimal.sh b/tools/gcc_build_all_debug_minimal.sh new file mode 100644 index 0000000..8aa39bb --- /dev/null +++ b/tools/gcc_build_all_debug_minimal.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +chmod u+rwx ./gcc_build_all_debug_full.sh +./gcc_build_all_debug_full.sh debug minimal diff --git a/tools/gcc_build_all_release_full.sh b/tools/gcc_build_all_release_full.sh new file mode 100644 index 0000000..75a6fa8 --- /dev/null +++ b/tools/gcc_build_all_release_full.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +chmod u+rwx ./gcc_build_all_debug_full.sh +./gcc_build_all_debug_full.sh release full diff --git a/tools/gcc_build_all_release_minimal.sh b/tools/gcc_build_all_release_minimal.sh new file mode 100644 index 0000000..3b1ba63 --- /dev/null +++ b/tools/gcc_build_all_release_minimal.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +chmod u+rwx ./gcc_build_all_debug_full.sh +./gcc_build_all_debug_full.sh release minimal diff --git a/tools/gitignore_recursive.bat b/tools/gitignore_recursive.bat new file mode 100644 index 0000000..8befc99 --- /dev/null +++ b/tools/gitignore_recursive.bat @@ -0,0 +1 @@ +cscript.exe gitignore_recursive.vbs diff --git a/tools/gitignore_recursive.file b/tools/gitignore_recursive.file new file mode 100644 index 0000000..efadbd8 --- /dev/null +++ b/tools/gitignore_recursive.file @@ -0,0 +1,7 @@ +# git does not allow empty directories. +# Yet, we need to add this empty directory on git. +# To achieve that, we created this .gitignore file, so that the directory will not be empty thus enabling us to commit it. +# Since we want all generated files/folders in this directory to be ignored by git, we add a rule for this. +* +# And then add an exception for this specifc file (so that we can commit it). +!.gitignore diff --git a/tools/gitignore_recursive.vbs b/tools/gitignore_recursive.vbs new file mode 100644 index 0000000..13bc7a7 --- /dev/null +++ b/tools/gitignore_recursive.vbs @@ -0,0 +1,22 @@ +gitRepoFolder = "../" +gitIgnoreFile = "./gitignore_recursive.file" + +Set fso = CreateObject("Scripting.FileSystemObject") +Call checkFolder(fso.GetFolder(gitRepoFolder), 999) + +Sub checkFolder(folder, depth) + If (depth > 0) Then + For Each subFolder In folder.SubFolders + Call checkFolder(subFolder, (depth - 1)) + Next + End If + + folderPath = Replace(folder.Path, "\", "/") + If (Right(folderPath, 1) <> "/") Then folderPath = (folderPath + "/") + If (InStr(folderPath, ".git") > 0) Then Exit Sub + + If (((folder.Files.Count <= 0) And (folder.SubFolders.Count <= 0)) Or (Right(folderPath, 17) = "doc/doxygen/html/")) Then + Call Wscript.Echo("add '.gitignore' file to folder : " + folderPath) + Call fso.CopyFile(gitIgnoreFile, (folderPath + ".gitignore")) + End If +End Sub diff --git a/tools/mingw_build_all_debug_qt4_full.bat b/tools/mingw_build_all_debug_qt4_full.bat new file mode 100644 index 0000000..ed3b68e --- /dev/null +++ b/tools/mingw_build_all_debug_qt4_full.bat @@ -0,0 +1,106 @@ +REM -- BATCH PARAMETERS -- +set BATCH_TYPE=full +set MINGW_CONFIG=debug +set LIB_SUFFIX=d +if "%1"=="release" set MINGW_CONFIG=%1 +if "%1"=="release" set LIB_SUFFIX= +if "%2"=="minimal" set BATCH_TYPE=%2 +if "%BATCH_TYPE%"=="full" set QXORM_QMAKE_PARAMS="DEFINES += _QX_ENABLE_BOOST_SERIALIZATION" "DEFINES += _QX_ENABLE_QT_GUI" "DEFINES += _QX_ENABLE_QT_NETWORK" +set QXORM_QMAKE_PARAMS=%QXORM_QMAKE_PARAMS% "QMAKE_CXXFLAGS += -std=c++0x" + +REM -- QT ENVIRONMENT VARIABLES -- +set QT_DIR=%QT4_MINGW% +set PATH=%QT_DIR%\bin;%PATH% + +REM -- BOOST ENVIRONMENT VARIABLES -- +set BOOST_INCLUDE=%BOOST_DIR%\include +set BOOST_LIB=%BOOST_DIR%\lib_shared +set BOOST_LIB_SERIALIZATION_DEBUG=libboost_serialization-mgw45-mt-d-1_57 +set BOOST_LIB_SERIALIZATION_RELEASE=libboost_serialization-mgw45-mt-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_DEBUG=libboost_wserialization-mgw45-mt-d-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_RELEASE=libboost_wserialization-mgw45-mt-1_57 + +REM -- MAKE OPTIONS : USE 8 CORE CPU TO REDUCE BUILD TIMES -- +set MAKE_COMMAND=make -j8 + +REM -- BUILD QXORM LIBRARY -- +cd "../" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "./lib/QxOrm%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST DLL1 -- +cd "./test/qxDllSample/dll1/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/dll1%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST DLL2 -- +cd "../dll2/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/dll2%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST EXE -- +cd "../exe/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/exe%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG -- +cd "../../qxBlog/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlog%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG COMPOSITE KEY -- +cd "../qxBlogCompositeKey/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogCompositeKey%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG MODEL VIEW -- +cd "../qxBlogModelView/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogModelView%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG PIMPL IDIOM -- +cd "../qxBlogPImpl/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogPImpl%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG REST API AND HTTP SERVER -- +cd "../qxBlogRestApi/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogRestApi%LIB_SUFFIX%.exe" GOTO END + +REM -- CHECK BATCH TYPE : FULL OR MINIMAL -- +IF "%BATCH_TYPE%"=="minimal" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXSERVICE -- +cd "../qxClientServer/qxService" +qmake %QXORM_QMAKE_PARAMS% qxServiceServer.pro +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServiceServer%LIB_SUFFIX%.dll" GOTO END +qmake %QXORM_QMAKE_PARAMS% qxServiceClient.pro +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServiceClient%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXSERVER -- +cd "../qxServer/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServer%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXCLIENT -- +cd "../qxClient/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxClient%LIB_SUFFIX%.exe" GOTO END + +REM -- BATCH FINISHED -- +:END +pause diff --git a/tools/mingw_build_all_debug_qt4_minimal.bat b/tools/mingw_build_all_debug_qt4_minimal.bat new file mode 100644 index 0000000..aa44f87 --- /dev/null +++ b/tools/mingw_build_all_debug_qt4_minimal.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt4_full.bat debug minimal diff --git a/tools/mingw_build_all_debug_qt5_full.bat b/tools/mingw_build_all_debug_qt5_full.bat new file mode 100644 index 0000000..8ae6cdd --- /dev/null +++ b/tools/mingw_build_all_debug_qt5_full.bat @@ -0,0 +1,113 @@ +REM -- BATCH PARAMETERS -- +set BATCH_TYPE=full +set MINGW_CONFIG=debug +set LIB_SUFFIX=d +set QXORM_QMAKE_PARAMS="DEFINES += _QX_NO_PRECOMPILED_HEADER" +if "%1"=="release" set MINGW_CONFIG=%1 +if "%1"=="release" set LIB_SUFFIX= +if "%2"=="minimal" set BATCH_TYPE=%2 +if "%BATCH_TYPE%"=="full" set QXORM_QMAKE_PARAMS=%QXORM_QMAKE_PARAMS% "DEFINES += _QX_ENABLE_BOOST_SERIALIZATION" "DEFINES += _QX_ENABLE_QT_GUI" "DEFINES += _QX_ENABLE_QT_NETWORK" + +REM -- QT ENVIRONMENT VARIABLES -- +set MINGW_DIR=%MINGW_QT5_DIR% +set QT_DIR=%QT5_MINGW% +set PATH=%MINGW_DIR%\bin;%QT_DIR%\bin;%PATH% + +REM -- BOOST ENVIRONMENT VARIABLES -- +set BOOST_INCLUDE=%BOOST_DIR%\include +set BOOST_LIB=%BOOST_DIR%\lib_shared +set BOOST_LIB_SERIALIZATION_DEBUG=libboost_serialization-mgw49-mt-d-1_57 +set BOOST_LIB_SERIALIZATION_RELEASE=libboost_serialization-mgw49-mt-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_DEBUG=libboost_wserialization-mgw49-mt-d-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_RELEASE=libboost_wserialization-mgw49-mt-1_57 + +REM -- MAKE OPTIONS : USE 8 CORE CPU TO REDUCE BUILD TIMES -- +set MAKE_COMMAND=make -j8 + +REM -- BUILD QXORM LIBRARY -- +cd "../" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "./lib/QxOrm%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST DLL1 -- +cd "./test/qxDllSample/dll1/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/dll1%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST DLL2 -- +cd "../dll2/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/dll2%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST EXE -- +cd "../exe/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/exe%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG -- +cd "../../qxBlog/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlog%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG COMPOSITE KEY -- +cd "../qxBlogCompositeKey/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogCompositeKey%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG MODEL VIEW -- +cd "../qxBlogModelView/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogModelView%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG PIMPL IDIOM -- +cd "../qxBlogPImpl/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogPImpl%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG REST API AND HTTP SERVER -- +cd "../qxBlogRestApi/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogRestApi%LIB_SUFFIX%.exe" GOTO END + +REM -- CHECK BATCH TYPE : FULL OR MINIMAL -- +IF "%BATCH_TYPE%"=="minimal" GOTO END + +REM -- BUILD TEST QXBLOG C++11 -- +cd "../qxBlogCpp11/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../_bin/qxBlogCpp11%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXSERVICE -- +cd "../qxClientServer/qxService" +qmake %QXORM_QMAKE_PARAMS% qxServiceServer.pro +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServiceServer%LIB_SUFFIX%.dll" GOTO END +qmake %QXORM_QMAKE_PARAMS% qxServiceClient.pro +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServiceClient%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXSERVER -- +cd "../qxServer/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxServer%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER QXCLIENT -- +cd "../qxClient/" +qmake %QXORM_QMAKE_PARAMS% +make %MINGW_CONFIG% +IF NOT EXIST "../../_bin/qxClient%LIB_SUFFIX%.exe" GOTO END + +REM -- BATCH FINISHED -- +:END +pause diff --git a/tools/mingw_build_all_debug_qt5_minimal.bat b/tools/mingw_build_all_debug_qt5_minimal.bat new file mode 100644 index 0000000..373d2e3 --- /dev/null +++ b/tools/mingw_build_all_debug_qt5_minimal.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt5_full.bat debug minimal diff --git a/tools/mingw_build_all_release_qt4_full.bat b/tools/mingw_build_all_release_qt4_full.bat new file mode 100644 index 0000000..5a80bca --- /dev/null +++ b/tools/mingw_build_all_release_qt4_full.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt4_full.bat release full diff --git a/tools/mingw_build_all_release_qt4_minimal.bat b/tools/mingw_build_all_release_qt4_minimal.bat new file mode 100644 index 0000000..daadd5d --- /dev/null +++ b/tools/mingw_build_all_release_qt4_minimal.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt4_full.bat release minimal diff --git a/tools/mingw_build_all_release_qt5_full.bat b/tools/mingw_build_all_release_qt5_full.bat new file mode 100644 index 0000000..a913bfd --- /dev/null +++ b/tools/mingw_build_all_release_qt5_full.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt5_full.bat release full diff --git a/tools/mingw_build_all_release_qt5_minimal.bat b/tools/mingw_build_all_release_qt5_minimal.bat new file mode 100644 index 0000000..83d610b --- /dev/null +++ b/tools/mingw_build_all_release_qt5_minimal.bat @@ -0,0 +1 @@ +CALL mingw_build_all_debug_qt5_full.bat release minimal diff --git a/tools/msvc2012_build_all_debug_32b_full.bat b/tools/msvc2012_build_all_debug_32b_full.bat new file mode 100644 index 0000000..a8eea00 --- /dev/null +++ b/tools/msvc2012_build_all_debug_32b_full.bat @@ -0,0 +1,76 @@ +REM -- BATCH PARAMETERS -- +set BATCH_TYPE=full +set MSVC_CONFIG=Debug +set MSVC_PLATFORM=Win32 +set LIB_SUFFIX=d +if "%1"=="release" set MSVC_CONFIG=Release +if "%1"=="release" set LIB_SUFFIX= +if "%2"=="x64" set MSVC_PLATFORM=x64 +if "%3"=="minimal" set BATCH_TYPE=%3 +if "%BATCH_TYPE%"=="full" set QXORM_QMAKE_PARAMS="DEFINES += _QX_ENABLE_BOOST_SERIALIZATION" "DEFINES += _QX_ENABLE_QT_GUI" "DEFINES += _QX_ENABLE_QT_NETWORK" "DEFINES += _QX_ENABLE_MONGODB" + +REM -- QT ENVIRONMENT VARIABLES -- +set QT_DIR=%QT5_MSVC2012_32B% +if "%2"=="x64" set QT_DIR=%QT5_MSVC2012_64B% +set PATH=%QT_DIR%\bin;%PATH% + +REM -- BOOST ENVIRONMENT VARIABLES -- +set BOOST_INCLUDE=%BOOST_DIR%\include +set BOOST_LIB=%BOOST_DIR%\lib_shared +if "%2"=="x64" set BOOST_LIB=%BOOST_DIR%\lib_shared_64b +set BOOST_LIB_SERIALIZATION_DEBUG=boost_serialization-vc110-mt-gd-1_57 +set BOOST_LIB_SERIALIZATION_RELEASE=boost_serialization-vc110-mt-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_DEBUG=boost_wserialization-vc110-mt-gd-1_57 +set BOOST_LIB_WIDE_SERIALIZATION_RELEASE=boost_wserialization-vc110-mt-1_57 + +REM -- LOAD MSVC ENVIRONMENT VARIABLES -- +IF EXIST "%PROGRAMFILES(X86)%" SET PROGFILES32=%PROGRAMFILES(X86)% +IF NOT EXIST "%PROGRAMFILES(X86)%" SET PROGFILES32=%PROGRAMFILES% +CALL "%PROGFILES32%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" x86 +SET CL=/MP +CD "..\" + +REM -- BUILD QXORM LIBRARY -- +msbuild ".\QxOrm.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\lib\QxOrm%LIB_SUFFIX%.dll" GOTO END + +REM -- BUILD TEST DLL SAMPLE -- +msbuild ".\test\qxDllSample\test.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\exe%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG -- +msbuild ".\test\qxBlog\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlog%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG COMPOSITE KEY -- +msbuild ".\test\qxBlogCompositeKey\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlogCompositeKey%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG MODEL VIEW -- +msbuild ".\test\qxBlogModelView\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlogModelView%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG PIMPL IDIOM -- +msbuild ".\test\qxBlogPImpl\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlogPImpl%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXBLOG REST API AND HTTP SERVER -- +msbuild ".\test\qxBlogRestApi\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlogRestApi%LIB_SUFFIX%.exe" GOTO END + +REM -- CHECK BATCH TYPE : FULL OR MINIMAL -- +IF "%BATCH_TYPE%"=="minimal" GOTO END + +REM -- BUILD TEST QXBLOG C++11 -- +msbuild ".\test\qxBlogCpp11\qxBlog.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxBlogCpp11%LIB_SUFFIX%.exe" GOTO END + +REM -- BUILD TEST QXCLIENTSERVER -- +msbuild ".\test\qxClientServer\qxClient\qxClient.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxClient%LIB_SUFFIX%.exe" GOTO END +msbuild ".\test\qxClientServer\qxServer\qxServer.sln" /p:Configuration="%MSVC_CONFIG%" /p:Platform="%MSVC_PLATFORM%" /t:build /nologo /v:detailed +IF NOT EXIST ".\test\_bin\qxServer%LIB_SUFFIX%.exe" GOTO END + +REM -- BATCH FINISHED -- +:END +PAUSE diff --git a/tools/msvc2012_build_all_debug_32b_minimal.bat b/tools/msvc2012_build_all_debug_32b_minimal.bat new file mode 100644 index 0000000..c5212dd --- /dev/null +++ b/tools/msvc2012_build_all_debug_32b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat debug x86 minimal diff --git a/tools/msvc2012_build_all_debug_64b_full.bat b/tools/msvc2012_build_all_debug_64b_full.bat new file mode 100644 index 0000000..485037c --- /dev/null +++ b/tools/msvc2012_build_all_debug_64b_full.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat debug x64 full diff --git a/tools/msvc2012_build_all_debug_64b_minimal.bat b/tools/msvc2012_build_all_debug_64b_minimal.bat new file mode 100644 index 0000000..a891890 --- /dev/null +++ b/tools/msvc2012_build_all_debug_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat debug x64 minimal diff --git a/tools/msvc2012_build_all_release_32b_full.bat b/tools/msvc2012_build_all_release_32b_full.bat new file mode 100644 index 0000000..afb42da --- /dev/null +++ b/tools/msvc2012_build_all_release_32b_full.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat release x86 full diff --git a/tools/msvc2012_build_all_release_32b_minimal.bat b/tools/msvc2012_build_all_release_32b_minimal.bat new file mode 100644 index 0000000..29ad044 --- /dev/null +++ b/tools/msvc2012_build_all_release_32b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat release x86 minimal diff --git a/tools/msvc2012_build_all_release_64b_full.bat b/tools/msvc2012_build_all_release_64b_full.bat new file mode 100644 index 0000000..67e92c1 --- /dev/null +++ b/tools/msvc2012_build_all_release_64b_full.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat release x64 full diff --git a/tools/msvc2012_build_all_release_64b_minimal.bat b/tools/msvc2012_build_all_release_64b_minimal.bat new file mode 100644 index 0000000..e4ddd64 --- /dev/null +++ b/tools/msvc2012_build_all_release_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2012_build_all_debug_32b_full.bat release x64 minimal diff --git a/tools/msvc2015_build_all_debug_64b_full.bat b/tools/msvc2015_build_all_debug_64b_full.bat new file mode 100644 index 0000000..ef0133e --- /dev/null +++ b/tools/msvc2015_build_all_debug_64b_full.bat @@ -0,0 +1,23 @@ +REM -- BATCH DEFAULT PARAMETERS -- +set QT_DIR=%QT5_8_MSVC2015_64B% +set PATH=%QT_DIR%\bin;%PATH% +set MSVC_CONFIG=Debug +set CL=/MP +set BATCH_TYPE=full +set CMAKE_OPTIONS=-D_QX_UNITY_BUILD=1 + +REM -- CHECK BATCH COMMAND LINE OPTIONS -- +if "%1"=="release" set MSVC_CONFIG=Release +if "%2"=="minimal" set BATCH_TYPE=%2 +if "%BATCH_TYPE%"=="full" set CMAKE_OPTIONS=%CMAKE_OPTIONS% -D_QX_ENABLE_BOOST=1 -D_QX_ENABLE_QT_GUI=1 -D_QX_ENABLE_QT_NETWORK=1 + +REM -- BATCH EXECUTION DIRECTORY -- +cd "..\test\" +set QX_TEST_DIR="%cd%" +cd ".\build\" + +REM -- CALL CMAKE TO BUILD QXORM LIBRARY AND ALL SAMPLES PROJECTS -- +cmake -G"Visual Studio 14 2015 Win64" %QX_TEST_DIR% %CMAKE_OPTIONS% +cmake --build . --config %MSVC_CONFIG% + +pause diff --git a/tools/msvc2015_build_all_debug_64b_minimal.bat b/tools/msvc2015_build_all_debug_64b_minimal.bat new file mode 100644 index 0000000..8688bbe --- /dev/null +++ b/tools/msvc2015_build_all_debug_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2015_build_all_debug_64b_full.bat debug minimal diff --git a/tools/msvc2015_build_all_release_64b_full.bat b/tools/msvc2015_build_all_release_64b_full.bat new file mode 100644 index 0000000..f694f04 --- /dev/null +++ b/tools/msvc2015_build_all_release_64b_full.bat @@ -0,0 +1 @@ +CALL msvc2015_build_all_debug_64b_full.bat release full diff --git a/tools/msvc2015_build_all_release_64b_minimal.bat b/tools/msvc2015_build_all_release_64b_minimal.bat new file mode 100644 index 0000000..67e8c56 --- /dev/null +++ b/tools/msvc2015_build_all_release_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2015_build_all_debug_64b_full.bat release minimal diff --git a/tools/msvc2017_build_all_debug_64b_full.bat b/tools/msvc2017_build_all_debug_64b_full.bat new file mode 100644 index 0000000..575fde1 --- /dev/null +++ b/tools/msvc2017_build_all_debug_64b_full.bat @@ -0,0 +1,26 @@ +REM -- BATCH DEFAULT PARAMETERS -- +set QT_DIR=%QT5_9_MSVC2015_64B% +set BOOST_ROOT=%BOOST_ROOT_1_66% +set MONGOC_LIB=%MONGOC_LIB_MSVC2017% +set BSON_LIB=%MONGOC_LIB% +set PATH=%QT_DIR%\bin;%BOOST_ROOT%\lib_shared;%MONGOC_LIB%;%PATH% +set MSVC_CONFIG=Debug +set CL=/MP +set BATCH_TYPE=full +set CMAKE_OPTIONS=-D_QX_UNITY_BUILD=1 + +REM -- CHECK BATCH COMMAND LINE OPTIONS -- +if "%1"=="release" set MSVC_CONFIG=Release +if "%2"=="minimal" set BATCH_TYPE=%2 +if "%BATCH_TYPE%"=="full" set CMAKE_OPTIONS=%CMAKE_OPTIONS% -D_QX_ENABLE_BOOST=1 -D_QX_ENABLE_QT_GUI=1 -D_QX_ENABLE_QT_NETWORK=1 -D_QX_ENABLE_MONGODB=1 + +REM -- BATCH EXECUTION DIRECTORY -- +cd "..\test\" +set QX_TEST_DIR="%cd%" +cd ".\build\" + +REM -- CALL CMAKE TO BUILD QXORM LIBRARY AND ALL SAMPLES PROJECTS -- +cmake -G"Visual Studio 15 2017 Win64" %QX_TEST_DIR% %CMAKE_OPTIONS% +cmake --build . --config %MSVC_CONFIG% + +pause diff --git a/tools/msvc2017_build_all_debug_64b_minimal.bat b/tools/msvc2017_build_all_debug_64b_minimal.bat new file mode 100644 index 0000000..d6ff3bc --- /dev/null +++ b/tools/msvc2017_build_all_debug_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2017_build_all_debug_64b_full.bat debug minimal diff --git a/tools/msvc2017_build_all_release_64b_full.bat b/tools/msvc2017_build_all_release_64b_full.bat new file mode 100644 index 0000000..a651b3c --- /dev/null +++ b/tools/msvc2017_build_all_release_64b_full.bat @@ -0,0 +1 @@ +CALL msvc2017_build_all_debug_64b_full.bat release full diff --git a/tools/msvc2017_build_all_release_64b_minimal.bat b/tools/msvc2017_build_all_release_64b_minimal.bat new file mode 100644 index 0000000..1281e5b --- /dev/null +++ b/tools/msvc2017_build_all_release_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2017_build_all_debug_64b_full.bat release minimal diff --git a/tools/msvc2019_build_all_debug_64b_full.bat b/tools/msvc2019_build_all_debug_64b_full.bat new file mode 100644 index 0000000..e93d8db --- /dev/null +++ b/tools/msvc2019_build_all_debug_64b_full.bat @@ -0,0 +1,26 @@ +REM -- BATCH DEFAULT PARAMETERS -- +set QT_DIR=%QT6_0_MSVC2019_64B% +set BOOST_ROOT=%BOOST_ROOT_1_66% +set MONGOC_LIB=%MONGOC_LIB_MSVC2017% +set BSON_LIB=%MONGOC_LIB% +set PATH=%QT_DIR%\bin;%BOOST_ROOT%\lib_shared;%MONGOC_LIB%;%PATH% +set MSVC_CONFIG=Debug +set CL=/MP +set BATCH_TYPE=full +set CMAKE_OPTIONS= + +REM -- CHECK BATCH COMMAND LINE OPTIONS -- +if "%1"=="release" set MSVC_CONFIG=Release +if "%2"=="minimal" set BATCH_TYPE=%2 +if "%BATCH_TYPE%"=="full" set CMAKE_OPTIONS=%CMAKE_OPTIONS% -D_QX_ENABLE_BOOST=1 -D_QX_ENABLE_QT_GUI=1 -D_QX_ENABLE_QT_NETWORK=1 -D_QX_ENABLE_MONGODB=1 -D_QX_UNITY_BUILD=1 + +REM -- BATCH EXECUTION DIRECTORY -- +cd "..\test\" +set QX_TEST_DIR="%cd%" +cd ".\build\" + +REM -- CALL CMAKE TO BUILD QXORM LIBRARY AND ALL SAMPLES PROJECTS -- +cmake -G"Visual Studio 16 2019" -A x64 %QX_TEST_DIR% %CMAKE_OPTIONS% +cmake --build . --config %MSVC_CONFIG% + +pause diff --git a/tools/msvc2019_build_all_debug_64b_minimal.bat b/tools/msvc2019_build_all_debug_64b_minimal.bat new file mode 100644 index 0000000..c339b8d --- /dev/null +++ b/tools/msvc2019_build_all_debug_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2019_build_all_debug_64b_full.bat debug minimal diff --git a/tools/msvc2019_build_all_release_64b_full.bat b/tools/msvc2019_build_all_release_64b_full.bat new file mode 100644 index 0000000..5af958a --- /dev/null +++ b/tools/msvc2019_build_all_release_64b_full.bat @@ -0,0 +1 @@ +CALL msvc2019_build_all_debug_64b_full.bat release full diff --git a/tools/msvc2019_build_all_release_64b_minimal.bat b/tools/msvc2019_build_all_release_64b_minimal.bat new file mode 100644 index 0000000..29742ef --- /dev/null +++ b/tools/msvc2019_build_all_release_64b_minimal.bat @@ -0,0 +1 @@ +CALL msvc2019_build_all_debug_64b_full.bat release minimal diff --git a/tools/osx_build_all_debug_full.sh b/tools/osx_build_all_debug_full.sh new file mode 100644 index 0000000..4540117 --- /dev/null +++ b/tools/osx_build_all_debug_full.sh @@ -0,0 +1,179 @@ +#!/bin/bash + +if [[ $1 == "release" ]]; +then + CONFIG=release + LIBBOOSTSERIALIZATION=libboost_serialization-mt.dylib +else + CONFIG=debug + SUFFIX=d + LIBBOOSTSERIALIZATION=libboost_serialization-mt-d.dylib +fi + +if [[ $2 == "full" ]] || [ -z "$2" ]; +then + QMAKEPARAMS="\"DEFINES += _QX_ENABLE_BOOST_SERIALIZATION\" \"DEFINES += _QX_ENABLE_QT_GUI\" \"DEFINES += _QX_ENABLE_QT_NETWORK\"" +fi + +if [ ! -f ../lib/$LIBBOOSTSERIALIZATION ] +then + echo "You must copy '$LIBBOOSTSERIALIZATION' in 'QxOrm/lib/' before launching this script." + exit 0 +fi + +function testFile { +if [ ! $1 $2 ] +then + echo "$2 Error." + exit 1 +else + echo "$2 OK." +fi +} + +clear +pwd +cd .. + +echo "-- BOOST ENVIRONMENT VARIABLES --" +export BOOST_INCLUDE=/usr/include +export BOOST_LIB=/usr/lib +export BOOST_LIB_SERIALIZATION_DEBUG=boost_serialization-mt-d +export BOOST_LIB_SERIALIZATION_RELEASE=boost_serialization-mt +export BOOST_LIB_WIDE_SERIALIZATION_DEBUG=boost_wserialization-mt-d +export BOOST_LIB_WIDE_SERIALIZATION_RELEASE=boost_wserialization-mt + +echo "-- MAKE OPTIONS : USE 8 CORE CPU TO REDUCE BUILD TIMES --" +MAKEOPT=-j8 + +echo "-- BUILD QXORM LIBRARY --" +eval qmake $QMAKEPARAMS QxOrm.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ./lib/libQxOrm$SUFFIX.* +cp -R -v ./lib/libQxOrm$SUFFIX.* ./test/_bin/ +cp -R -v ./lib/$LIBBOOSTSERIALIZATION ./test/_bin/ +install_name_tool -id @executable_path/libQxOrm$SUFFIX.dylib ./test/_bin/libQxOrm$SUFFIX.dylib +install_name_tool -id @executable_path/$LIBBOOSTSERIALIZATION ./test/_bin/$LIBBOOSTSERIALIZATION +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./test/_bin/libQxOrm$SUFFIX.dylib + +cd ./test/ + +echo "-- BUILD DLLSAMPLE --" +cd ./qxDllSample/dll1/ +eval qmake $QMAKEPARAMS dll1.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../../_bin/libdll1$SUFFIX.* +cd ../../ +install_name_tool -id @executable_path/libdll1$SUFFIX.dylib ./_bin/libdll1$SUFFIX.dylib +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/libdll1$SUFFIX.dylib +cd ./qxDllSample/dll2/ +eval qmake $QMAKEPARAMS dll2.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../../_bin/libdll2$SUFFIX.* +cd ../../ +install_name_tool -id @executable_path/libdll2$SUFFIX.dylib ./_bin/libdll2$SUFFIX.dylib +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/libdll2$SUFFIX.dylib +#install_name_tool -change libdll1$SUFFIX.1.dylib @executable_path/libdll1$SUFFIX.dylib ./_bin/libdll2$SUFFIX.dylib +cd ./qxDllSample/exe/ +eval qmake $QMAKEPARAMS exe.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../../_bin/exe$SUFFIX +cd ../../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/exe$SUFFIX + +echo "-- BUILD TEST QXBLOG --" +cd ./qxBlog/ +eval qmake $QMAKEPARAMS qxBlog.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../_bin/qxBlog$SUFFIX +cd ../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/qxBlog$SUFFIX + +echo "-- BUILD TEST QXBLOG COMPOSITE KEY --" +cd ./qxBlogCompositeKey/ +eval qmake $QMAKEPARAMS qxBlog.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../_bin/qxBlogCompositeKey$SUFFIX +cd ../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/qxBlogCompositeKey$SUFFIX + +echo "-- BUILD TEST QXBLOG MODEL VIEW --" +cd ./qxBlogModelView/ +eval qmake $QMAKEPARAMS qxBlog.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../_bin/qxBlogModelView$SUFFIX +cd ../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/qxBlogModelView$SUFFIX + +echo "-- BUILD TEST QXBLOG PIMPL IDIOM --" +cd ./qxBlogPImpl/ +eval qmake $QMAKEPARAMS qxBlog.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../_bin/qxBlogPImpl$SUFFIX +cd ../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/qxBlogPImpl$SUFFIX + +echo "-- BUILD TEST QXBLOG REST API AND HTTP SERVER --" +cd ./qxBlogRestApi/ +eval qmake $QMAKEPARAMS qxBlog.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../_bin/qxBlogRestApi$SUFFIX +cd ../ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/$LIBBOOSTSERIALIZATION ./_bin/qxBlogRestApi$SUFFIX + +echo "-- CHECK BATCH TYPE : FULL OR MINIMAL --" +if [[ $2 == "minimal" ]]; +then + exit 0 +fi + +echo "-- BUILD TEST QXCLIENTSERVER QXSERVICE --" +cd ./qxClientServer/qxService +eval qmake $QMAKEPARAMS qxServiceServer.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../../_bin/libqxServiceServer$SUFFIX.* +install_name_tool -id @executable_path/../Frameworks/libqxServiceServer$SUFFIX.dylib ../../_bin/libqxServiceServer$SUFFIX.dylib +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ../../_bin/libqxServiceServer$SUFFIX.dylib +install_name_tool -change @executable_path/libQxOrm$SUFFIX.dylib @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ../../_bin/libqxServiceServer$SUFFIX.dylib +eval qmake $QMAKEPARAMS qxServiceClient.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -f ../../_bin/libqxServiceClient$SUFFIX.* +install_name_tool -id @executable_path/../Frameworks/libqxServiceClient$SUFFIX.dylib ../../_bin/libqxServiceClient$SUFFIX.dylib +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ../../_bin/libqxServiceClient$SUFFIX.dylib +install_name_tool -change @executable_path/libQxOrm$SUFFIX.dylib @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ../../_bin/libqxServiceClient$SUFFIX.dylib +cd ../../ + +echo "-- BUILD TEST QXCLIENTSERVER QXSERVER --" +cd ./qxClientServer/qxServer/ +eval qmake $QMAKEPARAMS qxServer.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -d ../../_bin/qxServer$SUFFIX.app +cd ../../ +mkdir -p ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/ +cp -R -v ./_bin/libQxOrm$SUFFIX.* ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/ +install_name_tool -id @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/libQxOrm$SUFFIX.dylib +install_name_tool -change @executable_path/$LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/libQxOrm$SUFFIX.dylib +cp -R -v ./_bin/$LIBBOOSTSERIALIZATION ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/ +install_name_tool -id @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/$LIBBOOSTSERIALIZATION +mv -v ./_bin/libqxServiceServer$SUFFIX.* ./_bin/qxServer$SUFFIX.app/Contents/Frameworks/ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxServer$SUFFIX.app/Contents/MacOS/qxServer$SUFFIX +install_name_tool -change @executable_path/libQxOrm$SUFFIX.dylib @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ./_bin/qxServer$SUFFIX.app/Contents/MacOS/qxServer$SUFFIX + +echo "-- BUILD TEST QXCLIENTSERVER QXCLIENT --" +cd ./qxClientServer/qxClient/ +eval qmake $QMAKEPARAMS qxClient.pro -r -spec macx-g++ +make -w $CONFIG $MAKEOPT +testFile -d ../../_bin/qxClient$SUFFIX.app +cd ../../ +mkdir -p ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/ +cp -R -v ./_bin/libQxOrm$SUFFIX.* ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/ +install_name_tool -id @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/libQxOrm$SUFFIX.dylib +install_name_tool -change @executable_path/$LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/libQxOrm$SUFFIX.dylib +cp -R -v ./_bin/$LIBBOOSTSERIALIZATION ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/ +install_name_tool -id @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/$LIBBOOSTSERIALIZATION +mv -v ./_bin/libqxServiceClient$SUFFIX.* ./_bin/qxClient$SUFFIX.app/Contents/Frameworks/ +install_name_tool -change $LIBBOOSTSERIALIZATION @executable_path/../Frameworks/$LIBBOOSTSERIALIZATION ./_bin/qxClient$SUFFIX.app/Contents/MacOS/qxClient$SUFFIX +install_name_tool -change @executable_path/libQxOrm$SUFFIX.dylib @executable_path/../Frameworks/libQxOrm$SUFFIX.dylib ./_bin/qxClient$SUFFIX.app/Contents/MacOS/qxClient$SUFFIX +cd ../ + +echo "Success !" diff --git a/tools/osx_build_all_debug_minimal.sh b/tools/osx_build_all_debug_minimal.sh new file mode 100644 index 0000000..0dd1cc0 --- /dev/null +++ b/tools/osx_build_all_debug_minimal.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./osx_build_all_debug_full.sh debug minimal diff --git a/tools/osx_build_all_release_full.sh b/tools/osx_build_all_release_full.sh new file mode 100644 index 0000000..b4fdb61 --- /dev/null +++ b/tools/osx_build_all_release_full.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./osx_build_all_debug_full.sh release full diff --git a/tools/osx_build_all_release_minimal.sh b/tools/osx_build_all_release_minimal.sh new file mode 100644 index 0000000..d335cd6 --- /dev/null +++ b/tools/osx_build_all_release_minimal.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./osx_build_all_debug_full.sh release minimal diff --git a/tools/qxorm.ebuild b/tools/qxorm.ebuild new file mode 100644 index 0000000..fe36310 --- /dev/null +++ b/tools/qxorm.ebuild @@ -0,0 +1,67 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v3 +# $Header: /var/cvsroot/gentoo-x86/dev-cpp/qxorm/qxorm-1.5.0-r1.ebuild,v 1.5.0-r1 2011/04/04 $ + +EAPI="2" + +inherit qt4-r2 + +DESCRIPTION="C++ Object Relational Mapping library" +HOMEPAGE="https://www.qxorm.com/" +SRC_URI="https://www.qxorm.com/version/QxOrm_${PV}.zip" +S=${WORKDIR}/QxOrm + +LICENSE="GPL-3" +SLOT="0" +KEYWORDS="amd64 x86" + +IUSE="gui" + +RDEPEND="x11-libs/qt-sql:4 + gui? ( x11-libs/qt-gui:4 )" + +DEPEND="${RDEPEND}" + +PACKNAME="QxOrm" + +PATCHES=( + "${FILESDIR}/${P}-20110413.patch" +) + +src_configure() { + local conf_add + conf_add="${conf_add} $(use_enable gui)" + + eqmake4 "${PACKNAME}.pro" \ + CONFIG+="${conf_add}" \ + || die "eqmake4 failed." +} + +src_compile() { + default + emake all || die "make all failed" +} + +src_install() { + emake install DESTDIR="${D}"|| die "make install failed" + # deploy headers + dodir /usr/include/${PACKNAME} || die "create include directory failed" + insinto /usr/include/${PACKNAME} + doins -r ${S}/include/* || die "headers copy failed" + doins -r ${S}/inl/* || die "inline headers copy failed" + find "${D}"/usr/include -type f -name "*.h" -exec sed -i 's,../inl/,,g' {} \; + find "${D}"/usr/include -type f -name "*.inl" -exec sed -i 's,../inl/,,g' {} \; + + # deploy library + insinto /usr/lib + #doins ${S}/lib/libQxOrm.a || die "copy library failed" + #doins ${S}/lib/libQxOrm.la || die "copy library failed" + exeinto /usr/lib + doexe ${S}/lib/libQxOrm.so.1.0.0 || die "copy library failed" + + # rename library + LIBDIR=`ls "${D}"/usr/|grep lib` + mv "${D}"/usr/${LIBDIR}/lib${PACKNAME}.so.1.0.0 "${D}"/usr/${LIBDIR}/lib${PACKNAME}-1.1.so.${PV} || die "rename library failed" + ln -sf lib${PACKNAME}-1.1.so.${PV} "${D}"/usr/${LIBDIR}/lib${PACKNAME}-1.1.so || die "create symbolic link failed" + ln -sf lib${PACKNAME}-1.1.so.${PV} "${D}"/usr/${LIBDIR}/lib${PACKNAME}.so || die "create symbolic link failed" +} diff --git a/tools/qxorm.spec b/tools/qxorm.spec new file mode 100644 index 0000000..69511c6 --- /dev/null +++ b/tools/qxorm.spec @@ -0,0 +1,84 @@ +%define version 1.5.0 + +Name: QxOrm +Version: %{version} +Release: 1%{?dist} +License: GPLv3+ +Group: System Environment/Libraries +Summary: C++ Object Relational Mapping (ORM) library +URL: https://www.qxorm.com/ + +Source0: QxOrm_%{version}.zip + +Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root +BuildRequires: boost-devel,qt-devel + +%description +QxOrm is a C++ library designed to provide Object Relational Mapping (ORM) feature to C++ users. +QxOrm is developed by XDL Team, a software development engineer since 2003. +QxOrm provides many functionalities starting from a simple C++ setting function by class : + +* persistence : communication with a lot of databases (with 1-1, 1-n, n-1 and n-n relationships) +* serialization : binary and xml format +* reflection (or introspection) : access to classes definitions, retrieve properties and call classes methods + +%package devel +Summary: Development tools for QxOrm +Group: Development/Libraries +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The QxOrm-devel package contains header files and documentation necessary +for developing programs using the QxOrm + +%package doc +Summary: Documentation for QxOrm +Group: Development/Libraries +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description doc +The QxOrm-devel package contains the Doxygen files for +QxOrm. + +%prep +%setup -q -n QxOrm + +%build + +# Otherwise qmake installs everything into $PREFIX/lib +sed QxOrm.usrlib.pro "s#/lib#/%{_lib}#" +qmake-qt4 PREFIX=$RPM_BUILD_ROOT%{_usr} QxOrm.usrlib.pro +make release %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +make release-install + +# We move the 'inl' into the include directory +# otherwise the name would be '/usr/inl' +mv $RPM_BUILD_ROOT%{_usr}/inl $RPM_BUILD_ROOT%{_includedir} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-,root,root) +%doc license.gpl3.txt +%{_libdir}/libQxOrm.so* + +%files devel +%defattr(-,root,root) +%{_includedir}/* + +%files doc +%defattr(-,root,root) +%doc doc + +%clean +rm -rf $RPM_BUILD_ROOT + +%changelog +* Wed Apr 3 2013 Erik Wasser 1.2.5-1 +- First version +