├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── entity ├── mysql_entity.xml ├── mysql_entity.xsd ├── psql_entity.xml ├── psql_entity.xsd ├── sqlite_entity.xml ├── sqlite_entity.xsd ├── sqlserver_entity.xml └── sqlserver_entity.xsd ├── include ├── builder │ ├── countbuilder.h │ ├── deletebuilder.h │ ├── insertbuilder.h │ ├── insertintoselectbuilder.h │ ├── joinbuilder.h │ ├── option │ │ ├── columnbuilder.h │ │ ├── constraintbuilder.h │ │ ├── debugbuilder.h │ │ ├── filterbuilder.h │ │ ├── frombuilder.h │ │ ├── fromselectbuilder.h │ │ ├── joinconnectbuilder.h │ │ ├── onconditionbuilder.h │ │ ├── sessionbuilder.h │ │ ├── setbuilder.h │ │ └── unionbuilder.h │ ├── recursivequerybuilder.h │ ├── selectbuilder.h │ ├── updatebuilder.h │ └── upsertbuilder.h ├── condition │ ├── conditionconstraint.h │ ├── conditionoperator.h │ ├── connector │ │ ├── connectable.h │ │ ├── constraintconnector.h │ │ ├── entityconnector.h │ │ ├── fieldconnector.h │ │ └── groupconnector.h │ ├── entitycondition.h │ ├── entityfield.h │ ├── foreignkey.h │ └── functioncondition.h ├── config │ ├── configbuilder.h │ ├── configmanager.h │ ├── configmysql.h │ ├── configpsql.h │ ├── configsqlite.h │ ├── configsqlserver.h │ └── configtype.h ├── configselector.h ├── connectionpool.h ├── dao.h ├── dbclients │ ├── abstractclient.h │ ├── mysqlclient.h │ ├── psqlclient.h │ ├── sqliteclient.h │ └── sqlserverclient.h ├── dbexception.h ├── global.h ├── macro │ └── macro.h ├── query │ ├── basequery.h │ ├── delete.h │ ├── deleteimpl.h │ ├── explaininfo.h │ ├── insert.h │ ├── insertimpl.h │ ├── insertintoselect.h │ ├── insertintoselectimpl.h │ ├── join.h │ ├── joinimpl.h │ ├── reader │ │ ├── builderreaderinterface.h │ │ └── entityreaderinterface.h │ ├── select.h │ ├── selectimpl.h │ ├── update.h │ ├── updateimpl.h │ ├── upsert.h │ └── upsertimpl.h ├── utils │ ├── dbupgrader.h │ ├── listutils.h │ ├── logging.h │ ├── serializing.h │ └── variantcast.h └── versionctl │ ├── version.h │ ├── version_table.xml │ └── versioncontrol.h ├── qt5.natvis ├── qt6.natvis ├── qtdaolib ├── qtdaolib.pri └── qtdaolib.pro ├── readme.md ├── src ├── CMakeLists.txt ├── QtDaoConfig.cmake.in ├── builder │ ├── frombuilder.cpp │ └── unionbuilder.cpp ├── condition │ ├── conditionconstraint.cpp │ ├── connector │ │ ├── connectable.cpp │ │ ├── entityconnector.cpp │ │ └── groupconnector.cpp │ ├── entitycondition.cpp │ └── functioncondition.cpp ├── config │ ├── configbuilder.cpp │ ├── configmanager.cpp │ ├── configmysql.cpp │ ├── configpsql.cpp │ ├── configsqlite.cpp │ └── configsqlserver.cpp ├── configselector.cpp ├── connectionpool.cpp ├── dao.version.in ├── dbclients │ ├── abstractclient.cpp │ ├── mysqlclient.cpp │ ├── psqlclient.cpp │ ├── sqliteclient.cpp │ └── sqlserverclient.cpp ├── qtdao.cpp ├── query │ ├── basequery.cpp │ ├── deleteimpl.cpp │ ├── insertimpl.cpp │ ├── insertintoselectimpl.cpp │ ├── joinimpl.cpp │ ├── selectimpl.cpp │ ├── updateimpl.cpp │ └── upsertimpl.cpp ├── utils │ ├── dbupgrader.cpp │ └── logging.cpp └── versionctl │ └── versioncontrol.cpp ├── test ├── acommontestutil │ ├── CMakeLists.txt │ ├── databaseselector.h │ ├── multitestrunner.h │ ├── test-config.json │ └── utils │ │ ├── datakey.h │ │ ├── testconfigloader.cpp │ │ ├── testconfigloader.h │ │ ├── testutils.cpp │ │ └── testutils.h ├── clienttest │ ├── CMakeLists.txt │ ├── clientmysqltest.cpp │ ├── clientmysqltest.h │ ├── clientpsqltest.cpp │ ├── clientpsqltest.h │ ├── clientsqlitetest.cpp │ ├── clientsqlitetest.h │ ├── clientsqlservertest.cpp │ ├── clientsqlservertest.h │ ├── main.cpp │ ├── mysql │ │ └── mysql_entity.xml │ ├── psql │ │ └── psql_entity.xml │ ├── sqlite │ │ └── sqlite_entity.xml │ └── sqlserver │ │ └── sqlserver_entity.xml ├── corelibtest │ ├── BaseTest.cpp │ ├── BaseTest.h │ ├── CMakeLists.txt │ ├── entity │ │ ├── mysqlentity │ │ │ └── mysql_entity.xml │ │ ├── psqlentity │ │ │ └── psql_entity.xml │ │ ├── sqliteentity │ │ │ └── sqlite_entity.xml │ │ └── sqlserverentity │ │ │ └── sqlserver_entity.xml │ ├── main.cpp │ ├── other │ │ ├── ConnectionPoolTest.cpp │ │ ├── ConnectionPoolTest.h │ │ ├── ConnectorTest.cpp │ │ ├── ConnectorTest.h │ │ ├── DbLoaderTest.cpp │ │ └── DbLoaderTest.h │ └── query │ │ ├── BaseQueryTest.cpp │ │ ├── BaseQueryTest.h │ │ ├── DeleteTest.cpp │ │ ├── DeleteTest.h │ │ ├── InsertIntoSelectTest.cpp │ │ ├── InsertIntoSelectTest.h │ │ ├── InsertTest.cpp │ │ ├── InsertTest.h │ │ ├── JoinTest.cpp │ │ ├── JoinTest.h │ │ ├── LoggingTest.cpp │ │ ├── LoggingTest.h │ │ ├── SelectTest.cpp │ │ ├── SelectTest.h │ │ ├── UpdateTest.cpp │ │ ├── UpdateTest.h │ │ ├── UpsertTest.cpp │ │ └── UpsertTest.h ├── customtypetest │ ├── CMakeLists.txt │ ├── customtypetest.cpp │ ├── customtypetest.h │ ├── entity │ │ ├── custom_entity.xml │ │ └── mystruct.h │ └── main.cpp ├── foreignkeytest │ ├── CMakeLists.txt │ ├── foreignkeytest.cpp │ ├── foreignkeytest.h │ ├── main.cpp │ ├── mysql │ │ └── mysql_entity.xml │ ├── psql │ │ └── psql_entity.xml │ ├── sqlite │ │ └── sqlite_entity.xml │ └── sqlserver │ │ └── sqlserver_entity.xml ├── keywordstest │ ├── CMakeLists.txt │ ├── keywordstest.cpp │ ├── keywordstest.h │ ├── main.cpp │ ├── mysql │ │ └── keywords_entity.xml │ ├── psql │ │ └── keywords_entity.xml │ ├── sqlite │ │ └── keywords_entity.xml │ └── sqlserver │ │ └── keywords_entity.xml ├── multidatabasetest │ ├── CMakeLists.txt │ ├── main.cpp │ ├── multidbtest.cpp │ ├── multidbtest.h │ ├── mysql │ │ └── mysql_entity.xml │ ├── psql │ │ └── psql_entity.xml │ ├── sqlite │ │ ├── v1 │ │ │ └── sqlite_entity.xml │ │ └── v2 │ │ │ └── sqlite_entity.xml │ └── sqlserver │ │ └── sqlserver_entity.xml └── upgradetest │ ├── CMakeLists.txt │ ├── main.cpp │ ├── mydbupgrader.cpp │ ├── mydbupgrader.h │ ├── mysql │ ├── v1 │ │ └── mysql_entity.xml │ ├── v2 │ │ └── mysql_entity.xml │ └── v3 │ │ └── mysql_entity.xml │ ├── psql │ ├── v1 │ │ └── psql_entity.xml │ ├── v2 │ │ └── psql_entity.xml │ └── v3 │ │ └── psql_entity.xml │ ├── sqlite │ ├── v1 │ │ └── sqlite_entity.xml │ ├── v2 │ │ └── sqlite_entity.xml │ └── v3 │ │ └── sqlite_entity.xml │ ├── sqlserver │ ├── v1 │ │ └── sqlserver_entity.xml │ ├── v2 │ │ └── sqlserver_entity.xml │ └── v3 │ │ └── sqlserver_entity.xml │ ├── upgradetest.cpp │ └── upgradetest.h └── todo └── readme.md /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: None 6 | AlignOperands: Align 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 4 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 0 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build* -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdao) 3 | 4 | add_subdirectory(src) 5 | 6 | option(QTDAO_BUILD_TEST "enable qtdao test projects" OFF) 7 | 8 | if (QTDAO_BUILD_TEST) 9 | message("config qtdao unit tests!") 10 | 11 | add_subdirectory(test/acommontestutil) 12 | 13 | add_subdirectory(test/corelibtest) 14 | add_subdirectory(test/keywordstest) 15 | add_subdirectory(test/customtypetest) 16 | add_subdirectory(test/clienttest) 17 | add_subdirectory(test/upgradetest) 18 | add_subdirectory(test/foreignkeytest) 19 | add_subdirectory(test/multidatabasetest) 20 | endif () -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 daonvshu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /include/builder/countbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/filterbuilder.h" 5 | #include "option/fromselectbuilder.h" 6 | #include "option/sessionbuilder.h" 7 | 8 | #include "selectbuilder.h" 9 | 10 | #include "../macro/macro.h" 11 | 12 | QTDAO_BEGIN_NAMESPACE 13 | 14 | template 15 | class CountBuilder 16 | : public DebugBuilder> 17 | , public FilterBuilder> 18 | , public FromSelfSelectBuilder 19 | , public SessionBuilder> 20 | { 21 | public: 22 | using SessionBuilder>::SessionBuilder; 23 | 24 | int count() { 25 | SelectBuilder builder; 26 | builder.column(FunctionConnector("count(*) as __selectcount")); 27 | builder.loggingCategoryPtr = this->loggingCategoryPtr; 28 | builder.filterCondition = this->filterCondition; 29 | builder.fromData = this->fromData; 30 | 31 | QList data = builder.build().list(); 32 | if (data.isEmpty()) { 33 | return 0; 34 | } 35 | return data[0].template __getExtra("__selectcount"); 36 | } 37 | }; 38 | 39 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/deletebuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/filterbuilder.h" 5 | #include "option/sessionbuilder.h" 6 | 7 | #include "../macro/macro.h" 8 | 9 | #include "../query/delete.h" 10 | 11 | QTDAO_BEGIN_NAMESPACE 12 | 13 | template 14 | class DeleteBuilder 15 | : public DebugBuilder> 16 | , public FilterBuilder> 17 | , public SessionBuilder> 18 | { 19 | public: 20 | using SessionBuilder>::SessionBuilder; 21 | 22 | Delete build() { 23 | return Delete(*this); 24 | } 25 | }; 26 | 27 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/insertbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/setbuilder.h" 5 | #include "option/sessionbuilder.h" 6 | 7 | #include "../macro/macro.h" 8 | 9 | #include "../query/insert.h" 10 | 11 | QTDAO_BEGIN_NAMESPACE 12 | 13 | template 14 | class InsertBuilder 15 | : public DebugBuilder> 16 | , public SetBuilder> 17 | , public SessionBuilder> 18 | { 19 | public: 20 | using SessionBuilder>::SessionBuilder; 21 | 22 | Insert build() { 23 | return Insert(*this); 24 | } 25 | }; 26 | 27 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/insertintoselectbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/columnbuilder.h" 5 | #include "option/fromselectbuilder.h" 6 | #include "option/sessionbuilder.h" 7 | 8 | #include "../macro/macro.h" 9 | 10 | #include "../query/insertintoselect.h" 11 | 12 | QTDAO_BEGIN_NAMESPACE 13 | 14 | template 15 | class InsertIntoSelectBuilder 16 | : public DebugBuilder> 17 | , public ColumnBuilder> 18 | , public FromE2SelectBuilder> 19 | , public SessionBuilder> 20 | { 21 | public: 22 | using SessionBuilder>::SessionBuilder; 23 | 24 | InsertIntoSelect build() { 25 | return InsertIntoSelect(*this); 26 | } 27 | }; 28 | 29 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/joinbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../query/join.h" 4 | 5 | #include "option/debugbuilder.h" 6 | #include "option/columnbuilder.h" 7 | #include "option/filterbuilder.h" 8 | #include "option/onconditionbuilder.h" 9 | #include "option/constraintbuilder.h" 10 | #include "option/unionbuilder.h" 11 | #include "option/joinconnectbuilder.h" 12 | #include "option/sessionbuilder.h" 13 | 14 | #include "../macro/macro.h" 15 | 16 | QTDAO_BEGIN_NAMESPACE 17 | 18 | template 19 | class JoinBuilder 20 | : public DebugBuilder> 21 | , public ColumnBuilder> 22 | , public FilterBuilder> 23 | , public OnConditionBuilder> 24 | , public ConstraintBuilder> 25 | , public UnionBuilder> 26 | , public JoinConnectBuilder> 27 | , public FromEsSelectBuilder 28 | , public SessionBuilder> 29 | { 30 | public: 31 | using SessionBuilder>::SessionBuilder; 32 | using FromEsSelectBuilder::from; 33 | 34 | template 35 | JoinBuilder& from(); 36 | 37 | Join build(); 38 | 39 | void solveLastJoinData() override; 40 | 41 | private: 42 | QString mainTable; 43 | QHash subJoinData; 44 | 45 | private: 46 | QString getFirstJoinTbName(); 47 | }; 48 | 49 | template 50 | inline void JoinBuilder::solveLastJoinData() { 51 | if (this->tbName.isEmpty() || this->joinType == JoinType::Unset) { 52 | return; 53 | } 54 | JoinData data; 55 | data.joinType = this->joinType; 56 | data.filter = OnConditionBuilder>::filterCondition; 57 | data.fromBuildData = this->JoinConnectBuilder>::fromData; 58 | subJoinData.insert(this->tbName, data); 59 | OnConditionBuilder>::filterCondition = FilterGroupConnector(); 60 | this->JoinConnectBuilder>::fromDataClear(); 61 | 62 | this->joinType = JoinType::Unset; 63 | this->tbName = QString(); 64 | } 65 | 66 | template 67 | template 68 | inline JoinBuilder& JoinBuilder::from() { 69 | mainTable = E2::Info::getTableName(); 70 | return *this; 71 | } 72 | 73 | template 74 | inline Join JoinBuilder::build() { 75 | solveLastJoinData(); 76 | if (mainTable.isEmpty()) { 77 | mainTable = getFirstJoinTbName(); 78 | } 79 | return Join(mainTable, subJoinData, *this); 80 | } 81 | 82 | template 83 | QString JoinBuilder::getFirstJoinTbName() { 84 | auto tbNames = JoinEUnpackHelper::getTbName(); 85 | return tbNames.first().first; 86 | } 87 | 88 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/constraintbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include "../../condition/connector/groupconnector.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class ConstraintBuilder { 11 | public: 12 | /** 13 | * add constraint conditions, example: 14 | * _limit(5, 20), _orderBy(field.name, field.age) 15 | * @tparam Cst type of ConstraintConnector or ConstraintGroupGroupConnector or HavingGroupConnector 16 | * @tparam Args types 17 | * @param constraint constraint condition 18 | * @param args other types of constraint condition 19 | * @return this 20 | */ 21 | template 22 | T& with(Cst&& constraint, Args&&... args) { 23 | constraintCondition.append(std::forward(constraint)); 24 | return with(args...); 25 | } 26 | 27 | /** 28 | * add constraint condition, using enabled to add condition optional 29 | * @tparam Cst type of ConstraintConnector or ConstraintGroupGroupConnector or HavingGroupConnector 30 | * @param enabled add condition if enabled 31 | * @param constraint condition 32 | * @return this 33 | */ 34 | template 35 | T& with(bool enabled, Cst&& constraint) { 36 | if (enabled) { 37 | constraintCondition.append(std::forward(constraint)); 38 | } 39 | return static_cast(*this); 40 | } 41 | 42 | /** 43 | * end function recursion 44 | * @return this 45 | */ 46 | T& with() { 47 | return static_cast(*this); 48 | } 49 | 50 | private: 51 | //use default connect conditions 52 | ConstraintGroupConnector constraintCondition; 53 | 54 | template class, typename> 55 | friend class BuilderReaderProvider; 56 | 57 | template class, typename...> 58 | friend class BuilderJbReaderProvider; 59 | }; 60 | 61 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/debugbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include "../../utils/logging.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class DebugBuilder { 11 | public: 12 | /** 13 | * set current query logging category, call 'dao::loggingUseDefault' to use default category 'qtdao.query' 14 | * @param ptr new logging category function pointer 15 | * @return this 16 | */ 17 | T& logging(LoggingCategoryPtr ptr) { 18 | loggingCategoryPtr = ptr; 19 | return static_cast(*this); 20 | } 21 | 22 | protected: 23 | //print sql query log use target category 24 | LoggingCategoryPtr loggingCategoryPtr = nullptr; 25 | 26 | friend class BaseQuery; 27 | }; 28 | 29 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/filterbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include "../../condition/entitycondition.h" 6 | #include "../../condition/functioncondition.h" 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | template 11 | class FilterBuilderImpl { 12 | protected: 13 | /** 14 | * use fields to add filter conditions, example: fields.name == "Alice" 15 | * @tparam F condition type, EntityConnector/FunctionConnector/FilterGroupGroupConnector 16 | * @tparam Args types 17 | * @param condition field/combination/function condition 18 | * @param args other types of conditions 19 | */ 20 | template 21 | void doFilter(F&& condition, Args&&... args) { 22 | filterCondition.append(std::forward(condition)); 23 | doFilter(args...); 24 | } 25 | 26 | /** 27 | * use fields to add filter conditions, using enabled to add optional 28 | * @tparam F condition type, EntityConnector/FunctionConnector/FilterGroupGroupConnector 29 | * @param enabled add condition if enabled 30 | * @param condition field/combination/function condition 31 | */ 32 | template 33 | void doFilter(bool enabled, F&& condition) { 34 | if (enabled) { 35 | filterCondition.append(std::forward(condition)); 36 | } 37 | } 38 | 39 | /** 40 | * end function recursion 41 | */ 42 | void doFilter() {} 43 | 44 | protected: 45 | //use 'and' connect conditions 46 | FilterGroupConnector filterCondition; 47 | }; 48 | 49 | template 50 | class FilterBuilder : FilterBuilderImpl> { 51 | public: 52 | /** 53 | * add some filter conditions, example: 54 | * fields.name == "Alice", _and(fields.name == "Alice", fields.age == 1), 55 | * _fun("%1 + %2 > 100").field(fields.score1, fields.score2) 56 | * @tparam Args condition type, EntityConnector/FunctionConnector/FilterGroupGroupConnector 57 | * @param args conditions 58 | * @return this 59 | */ 60 | template 61 | T& filter(Args&& ...args) { 62 | this->doFilter(std::forward(args)...); 63 | return static_cast(*this); 64 | } 65 | 66 | /** 67 | * add a filter condition, using enabled to add optional 68 | * @tparam Arg condition type, EntityConnector/FunctionConnector/FilterGroupGroupConnector 69 | * @param enabled add condition if enabled 70 | * @param arg conditions 71 | * @return this 72 | */ 73 | template 74 | T& filter(bool enabled, Arg&& arg) { 75 | this->doFilter(enabled, std::forward(arg)); 76 | return static_cast(*this); 77 | } 78 | 79 | protected: 80 | template class, typename> 81 | friend class BuilderReaderProvider; 82 | 83 | template class, typename...> 84 | friend class BuilderJbReaderProvider; 85 | 86 | template 87 | friend class JoinBuilder; 88 | 89 | template 90 | friend class CountBuilder; 91 | }; 92 | 93 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/frombuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | struct FromBuildData { 10 | QString statement; 11 | QVariantList values; 12 | QString asName; 13 | bool recursiveQuery = false; 14 | 15 | void clear() { 16 | statement = QString(); 17 | values.clear(); 18 | asName = QString(); 19 | recursiveQuery = false; 20 | } 21 | }; 22 | 23 | class SelectImpl; 24 | class JoinImpl; 25 | class RecursiveQueryBuilder; 26 | 27 | class FromBuilder { 28 | public: 29 | void fromDataClear() { 30 | fromData.clear(); 31 | } 32 | 33 | protected: 34 | virtual void fromSelect(SelectImpl& select); 35 | 36 | virtual void fromJoin(JoinImpl& join); 37 | 38 | virtual void fromBuilder(RecursiveQueryBuilder& builder); 39 | 40 | protected: 41 | FromBuildData fromData; 42 | 43 | template class, typename> 44 | friend class BuilderReaderProvider; 45 | 46 | template class, typename...> 47 | friend class BuilderJbReaderProvider; 48 | 49 | template 50 | friend class CountBuilder; 51 | }; 52 | 53 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/onconditionbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "filterbuilder.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | //same as FilterBuilder 8 | template 9 | class OnConditionBuilder : FilterBuilderImpl> { 10 | public: 11 | /** 12 | * add some on filter conditions, example: 13 | * fields.name == "Alice", _and(fields.name == "Alice", fields.age == 1), 14 | * _fun("%1 + %2 > 100").field(fields.score1, fields.score2) 15 | * @tparam Args condition type, EntityCondition/Connector/FunctionCondition 16 | * @param args conditions 17 | * @return this 18 | */ 19 | template 20 | T& on(Args&& ...args) { 21 | this->doFilter(std::forward(args)...); 22 | return static_cast(*this); 23 | } 24 | 25 | /** 26 | * add a on filter condition, using enabled to add optional 27 | * @tparam Arg condition type, EntityCondition/Connector/FunctionCondition 28 | * @param enabled add condition if enabled 29 | * @param arg conditions 30 | * @return this 31 | */ 32 | template 33 | T& on(bool enabled, Arg&& arg) { 34 | this->doFilter(enabled, std::forward(arg)); 35 | return static_cast(*this); 36 | } 37 | 38 | template class, typename> 39 | friend class BuilderReaderProvider; 40 | 41 | template class, typename...> 42 | friend class BuilderJbReaderProvider; 43 | 44 | template 45 | friend class JoinBuilder; 46 | }; 47 | 48 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/sessionbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | template 8 | class SessionBuilder { 9 | public: 10 | explicit SessionBuilder(qint64 sessionId = -1) : querySessionId(sessionId) {} 11 | 12 | public: 13 | //query used session id 14 | qint64 querySessionId; 15 | }; 16 | 17 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/setbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include "../../condition/connector/groupconnector.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class SetBuilder { 11 | public: 12 | /** 13 | * use fields to add set conditions, example: 14 | * fields.name = "Alice", fields.age = 18 15 | * @tparam E type of EntityConnector or FunctionConnector 16 | * @tparam Args types 17 | * @param condition set conditions 18 | * @param args other fields of conditions 19 | */ 20 | template 21 | T& set(E&& condition, Args&&... args){ 22 | setCondition.append(std::forward(condition)); 23 | return set(args...); 24 | } 25 | 26 | /** 27 | * add a set conditions, using enabled to add optional 28 | * @tparam E type of EntityConnector or FunctionConnector 29 | * @param enabled add condition if enabled 30 | * @param condition set conditions 31 | */ 32 | template 33 | T& set(bool enabled, E&& condition){ 34 | if (enabled) { 35 | setCondition.append(std::forward(condition)); 36 | } 37 | return static_cast(*this); 38 | } 39 | 40 | /** 41 | * end function recursion 42 | */ 43 | T& set() { 44 | return static_cast(*this); 45 | } 46 | 47 | private: 48 | //use ',' connect conditions 49 | SetGroupConnector setCondition; 50 | 51 | template class, typename> 52 | friend class BuilderReaderProvider; 53 | 54 | template class, typename...> 55 | friend class BuilderJbReaderProvider; 56 | }; 57 | 58 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/option/unionbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | struct UnionBuildData { 10 | QString statement; 11 | QVariantList values; 12 | bool unionAll = false; 13 | 14 | void clear() { 15 | statement = QString(); 16 | values.clear(); 17 | unionAll = false; 18 | } 19 | }; 20 | 21 | template 22 | class Select; 23 | 24 | template 25 | class Join; 26 | 27 | class SelectImpl; 28 | class JoinImpl; 29 | 30 | class UnionBuilderImpl { 31 | protected: 32 | void unionWithSelect(SelectImpl& select, bool unionAll); 33 | 34 | void unionWithJoin(JoinImpl& join, bool unionAll); 35 | 36 | private: 37 | UnionBuildData unionData; 38 | 39 | template class, typename> 40 | friend class BuilderReaderProvider; 41 | 42 | template class, typename...> 43 | friend class BuilderJbReaderProvider; 44 | }; 45 | 46 | template 47 | class UnionBuilder : UnionBuilderImpl { 48 | public: 49 | template 50 | T& unionSelect(Select& select, bool unionAll = false) { 51 | unionWithSelect(select, unionAll); 52 | return static_cast(*this); 53 | } 54 | 55 | template 56 | T& unionSelect(Select&& select, bool unionAll = false) { 57 | return unionSelect(select, unionAll); 58 | } 59 | 60 | template 61 | T& unionSelect(Join& join, bool unionAll = false) { 62 | unionWithJoin(join, unionAll); 63 | return static_cast(*this); 64 | } 65 | 66 | template 67 | T& unionSelect(Join&& join, bool unionAll = false) { 68 | return unionSelect(join, unionAll); 69 | } 70 | 71 | template class, typename> 72 | friend class BuilderReaderProvider; 73 | 74 | template class, typename...> 75 | friend class BuilderJbReaderProvider; 76 | }; 77 | 78 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/recursivequerybuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../query/select.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | class RecursiveQueryBuilder { 8 | public: 9 | explicit RecursiveQueryBuilder(bool unionAll = false) : unionAll(unionAll) {} 10 | 11 | template 12 | RecursiveQueryBuilder& initialSelect(Select& select); 13 | 14 | template 15 | RecursiveQueryBuilder& initialSelect(Join& join); 16 | 17 | template 18 | RecursiveQueryBuilder& recursiveSelect(Select& select); 19 | 20 | template 21 | RecursiveQueryBuilder& recursiveSelect(Join& join); 22 | 23 | template 24 | RecursiveQueryBuilder& tmp(); 25 | 26 | private: 27 | QString initialQueryStatement, recursiveQueryStatement; 28 | QVariantList initialQueryValue, recursiveQueryValue; 29 | QString tmpTableName; 30 | bool unionAll; 31 | 32 | friend class FromBuilder; 33 | }; 34 | 35 | template 36 | inline RecursiveQueryBuilder& RecursiveQueryBuilder::initialSelect(Select& select) { 37 | select.buildFilterSqlStatement(); 38 | initialQueryStatement = select.statement; 39 | initialQueryValue = select.values; 40 | return *this; 41 | } 42 | 43 | template 44 | inline RecursiveQueryBuilder& RecursiveQueryBuilder::initialSelect(Join& join) { 45 | join.insideRecursiveQuery = true; 46 | join.buildJoinSqlStatement(); 47 | initialQueryStatement = join.statement; 48 | initialQueryValue = join.values; 49 | return *this; 50 | } 51 | 52 | template 53 | inline RecursiveQueryBuilder& RecursiveQueryBuilder::recursiveSelect(Select& select) { 54 | select.buildFilterSqlStatement(); 55 | recursiveQueryStatement = select.statement; 56 | recursiveQueryValue = select.values; 57 | return *this; 58 | } 59 | 60 | template 61 | inline RecursiveQueryBuilder& RecursiveQueryBuilder::recursiveSelect(Join& join) { 62 | join.insideRecursiveQuery = true; 63 | join.buildJoinSqlStatement(); 64 | recursiveQueryStatement = join.statement; 65 | recursiveQueryValue = join.values; 66 | return *this; 67 | } 68 | 69 | template 70 | inline RecursiveQueryBuilder& RecursiveQueryBuilder::tmp() { 71 | tmpTableName = E::Info::getTableName(); 72 | return *this; 73 | } 74 | 75 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/selectbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/columnbuilder.h" 5 | #include "option/filterbuilder.h" 6 | #include "option/constraintbuilder.h" 7 | #include "option/fromselectbuilder.h" 8 | #include "option/unionbuilder.h" 9 | #include "option/sessionbuilder.h" 10 | 11 | #include "../macro/macro.h" 12 | 13 | #include "../query/select.h" 14 | 15 | QTDAO_BEGIN_NAMESPACE 16 | 17 | template 18 | class CountBuilder; 19 | 20 | template 21 | class SelectBuilder 22 | : public DebugBuilder> 23 | , public ColumnBuilder> 24 | , public FilterBuilder> 25 | , public ConstraintBuilder> 26 | , public FromSelfSelectBuilder 27 | , public UnionBuilder> 28 | , public SessionBuilder> 29 | { 30 | public: 31 | using SessionBuilder>::SessionBuilder; 32 | 33 | Select build() { 34 | return Select(*this); 35 | } 36 | 37 | friend class CountBuilder; 38 | }; 39 | 40 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/updatebuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/filterbuilder.h" 5 | #include "option/setbuilder.h" 6 | #include "option/sessionbuilder.h" 7 | 8 | #include "../macro/macro.h" 9 | 10 | #include "../query/update.h" 11 | 12 | QTDAO_BEGIN_NAMESPACE 13 | 14 | template 15 | class UpdateBuilder 16 | : public DebugBuilder> 17 | , public FilterBuilder> 18 | , public SetBuilder> 19 | , public SessionBuilder> 20 | { 21 | public: 22 | using SessionBuilder>::SessionBuilder; 23 | 24 | Update build() { 25 | return Update(*this); 26 | } 27 | }; 28 | 29 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/builder/upsertbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "option/debugbuilder.h" 4 | #include "option/columnbuilder.h" 5 | #include "option/filterbuilder.h" 6 | #include "option/setbuilder.h" 7 | #include "option/sessionbuilder.h" 8 | 9 | #include "../macro/macro.h" 10 | 11 | #include "../query/upsert.h" 12 | 13 | QTDAO_BEGIN_NAMESPACE 14 | 15 | template 16 | class UpsertBuilder 17 | : public DebugBuilder> 18 | , public ConflictColumnBuilder> 19 | , public UpdateColumnBuilder> 20 | , public FilterBuilder> //only supported for sqlite 21 | , public SetBuilder> 22 | , public SessionBuilder> 23 | { 24 | public: 25 | using SessionBuilder>::SessionBuilder; 26 | 27 | Upsert build() { 28 | return Upsert(*this); 29 | } 30 | }; 31 | 32 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/condition/conditionconstraint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "connector/constraintconnector.h" 6 | #include "functioncondition.h" 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | template 11 | class EntityField; 12 | 13 | class LimitConstraintConnector : public ConstraintConnector { 14 | public: 15 | explicit LimitConstraintConnector(int rows); 16 | 17 | explicit LimitConstraintConnector(int offset, int rows); 18 | 19 | QVariantList getValueList() override; 20 | 21 | void combine() override; 22 | 23 | bool isEmpty() override; 24 | }; 25 | 26 | class OrderByConstraintConnector : public ConstraintConnector { 27 | public: 28 | template 29 | void orderBy(const EntityField& field, const EntityField&... next) { 30 | addField(getEntityFieldInfo(field)); 31 | orderBy(next...); 32 | } 33 | 34 | void orderBy() {} 35 | 36 | void combine() override; 37 | }; 38 | 39 | class GroupByConstraintConnector : public ConstraintConnector { 40 | public: 41 | template 42 | void groupBy(const EntityField& field, const EntityField&... next) { 43 | addField(getEntityFieldInfo(field)); 44 | groupBy(next...); 45 | } 46 | 47 | void groupBy() {} 48 | 49 | void combine() override; 50 | }; 51 | 52 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/condition/conditionoperator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "connector/groupconnector.h" 6 | #include "conditionconstraint.h" 7 | 8 | template 9 | inline dao::FilterGroupGroupConnector* _and(T&&... t) { 10 | auto ptr = new dao::AndFilterGroupConnector; 11 | ptr->appends(std::forward(t)...); 12 | return ptr; 13 | } 14 | 15 | template 16 | inline dao::FilterGroupGroupConnector* _or(T&&... t) { 17 | auto ptr = new dao::OrFilterGroupConnector; 18 | ptr->appends(std::forward(t)...); 19 | return ptr; 20 | } 21 | 22 | template 23 | inline dao::ConstraintGroupGroupConnector* _constraint(T&&... t) { 24 | auto ptr = new dao::ConstraintGroupGroupConnector; 25 | ptr->appends(std::forward(t)...); 26 | return ptr; 27 | } 28 | 29 | inline dao::ConstraintConnector* _limit(int a, int b) { 30 | return new dao::LimitConstraintConnector(a, b); 31 | } 32 | 33 | inline dao::ConstraintConnector* _limit(int a) { 34 | return new dao::LimitConstraintConnector(a); 35 | } 36 | 37 | template 38 | inline dao::ConstraintConnector* _orderBy(const dao::EntityField&... n) { 39 | auto ptr = new dao::OrderByConstraintConnector; 40 | ptr->orderBy(n...); 41 | return ptr; 42 | } 43 | 44 | template 45 | inline dao::ConstraintConnector* _groupBy(const dao::EntityField&... n) { 46 | auto ptr = new dao::GroupByConstraintConnector; 47 | ptr->groupBy(n...); 48 | return ptr; 49 | } 50 | 51 | template 52 | inline dao::HavingGroupConnector* _having(T&&... t) { 53 | auto ptr = new dao::HavingGroupConnector; 54 | ptr->appends(std::forward(t)...); 55 | return ptr; 56 | } 57 | 58 | inline dao::FunctionConnector _fun(const QString& expressions) { 59 | return dao::FunctionConnector(expressions); 60 | } -------------------------------------------------------------------------------- /include/condition/connector/connectable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../global.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | QTDAO_BEGIN_NAMESPACE 11 | 12 | struct FieldInfo { 13 | QString name; 14 | QString bindTable; 15 | 16 | bool operator==(const FieldInfo& other) const { 17 | return name == other.name && bindTable == other.bindTable; 18 | } 19 | }; 20 | 21 | #if QT_VERSION_MAJOR >= 6 22 | inline size_t qHash(const FieldInfo& type, size_t seed) { 23 | return qHashMulti(seed, type.name, type.bindTable); 24 | } 25 | #else 26 | inline uint qHash(const FieldInfo& type, uint seed) { 27 | return ::qHash(type.name, seed) ^ ::qHash(type.bindTable, seed); 28 | } 29 | #endif 30 | 31 | typedef std::function FieldPrefixGetter; 32 | 33 | template 34 | class EntityField; 35 | 36 | struct ConnectableData : QSharedData { 37 | FieldPrefixGetter fieldPrefixGetter; 38 | QList fields; 39 | QVariantList values; 40 | QString connectedStr; 41 | 42 | void clear() { 43 | fields.clear(); 44 | values.clear(); 45 | connectedStr = QString(); 46 | } 47 | }; 48 | 49 | class Connectable { 50 | public: 51 | Connectable() { 52 | d = new ConnectableData; 53 | } 54 | 55 | void setFieldPrefixGetter(const FieldPrefixGetter& getter) { 56 | d->fieldPrefixGetter = getter; 57 | } 58 | 59 | virtual void combine() = 0; 60 | 61 | virtual QList getUsedFields(); 62 | 63 | virtual QString getConditionSegment(); 64 | 65 | virtual QVariantList getValueList(); 66 | 67 | virtual bool isEmpty(); 68 | 69 | virtual ~Connectable() = default; 70 | 71 | protected: 72 | QString getField(int index) const; 73 | 74 | protected: 75 | QExplicitlySharedDataPointer d; 76 | 77 | template 78 | FieldInfo getEntityFieldInfo(const EntityField& entityField); 79 | }; 80 | 81 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/condition/connector/constraintconnector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "entityconnector.h" 4 | 5 | #include 6 | #include 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | class ConstraintConnector : EntityConnector { 11 | public: 12 | using EntityConnector::addField; 13 | 14 | //only used for single inheritance structure! 15 | Connectable* ptr() { 16 | return this; 17 | } 18 | 19 | protected: 20 | using Connectable::getField; 21 | using Connectable::getEntityFieldInfo; 22 | using Connectable::d; 23 | }; 24 | 25 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/condition/connector/entityconnector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "connectable.h" 4 | 5 | #include 6 | #include 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | class EntityConnector : public Connectable { 11 | public: 12 | virtual void addField(const FieldInfo& field); 13 | 14 | virtual void addValue(const QVariant& value); 15 | 16 | template 17 | void addCustomValue(const T& value) { 18 | addValue(serializeCustomTypeToBinary(value)); 19 | } 20 | 21 | //only used for single inheritance structure! 22 | EntityConnector* ptr() { 23 | return this; 24 | } 25 | }; 26 | 27 | QTDAO_END_NAMESPACE 28 | -------------------------------------------------------------------------------- /include/condition/connector/fieldconnector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "connectable.h" 4 | 5 | #include "../entityfield.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class FieldConnector : public Connectable { 10 | public: 11 | template 12 | void setField(const EntityField& field) { 13 | d->fields << getEntityFieldInfo(field); 14 | } 15 | 16 | void setField(const FieldInfo& fieldInfo) { 17 | d->fields << fieldInfo; 18 | } 19 | 20 | void combine() override { 21 | d->connectedStr = getField(0); 22 | } 23 | }; 24 | 25 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/condition/foreignkey.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct ForeignKey { 6 | enum Action { 7 | FK_NO_ACTION, //no_action 8 | FK_RESTRICT, //restrict 9 | FK_SET_NULL, //set_null 10 | FK_SET_DEFAULT,//set_default 11 | FK_CASCADE, //cascade 12 | 13 | FK_NotSet, 14 | }; 15 | 16 | ForeignKey(QString referenceTb, Action onUpdate, Action onDelete, bool deferrable = false) 17 | : referenceTb(std::move(referenceTb)) 18 | , onUpdate(onUpdate) 19 | , onDelete(onDelete) 20 | , deferrable(deferrable) 21 | {} 22 | 23 | template 24 | ForeignKey& field(const QString& name, const QString& referTo, Args... args) { 25 | fieldKeys << name; 26 | referenceKeys << referTo; 27 | return field(args...); 28 | } 29 | 30 | ForeignKey& field() { 31 | return *this; 32 | } 33 | 34 | QString referenceTb; 35 | Action onUpdate; 36 | Action onDelete; 37 | bool deferrable; //sqlite 38 | 39 | QStringList fieldKeys; 40 | QStringList referenceKeys; 41 | }; -------------------------------------------------------------------------------- /include/condition/functioncondition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | #include "../builder/option/fromselectbuilder.h" 5 | 6 | #include "connector/connectable.h" 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | template 11 | class EntityField; 12 | 13 | class FunctionConnector : Connectable, public FromE2SelectBuilder { 14 | public: 15 | explicit FunctionConnector(QString expressions): expressions(std::move(expressions)) {} 16 | 17 | template 18 | FunctionConnector& field(const EntityField& f, const EntityField&... n) { 19 | d->fields << getEntityFieldInfo(f); 20 | return field(n...); 21 | } 22 | 23 | FunctionConnector& field() { 24 | return *this; 25 | } 26 | 27 | template 28 | FunctionConnector& value(const QVariant& v, Args... args) { 29 | d->values << v; 30 | return value(args...); 31 | } 32 | 33 | FunctionConnector& value() { 34 | return *this; 35 | } 36 | 37 | QList getUsedFields() override; 38 | 39 | void combine() override; 40 | 41 | Connectable* ptr() { 42 | return this; 43 | } 44 | 45 | private: 46 | bool isEmpty() override; 47 | 48 | protected: 49 | void fromSelect(SelectImpl& select) override; 50 | 51 | void fromJoin(JoinImpl& join) override; 52 | 53 | void fromBuilder(RecursiveQueryBuilder& builder) override; 54 | 55 | void solveFromQueryBuildResult(); 56 | 57 | private: 58 | QString expressions; 59 | }; 60 | 61 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configbuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../global.h" 6 | #include "../dbclients/abstractclient.h" 7 | 8 | #include "configtype.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class ConnectionPool; 15 | 16 | QTDAO_BEGIN_NAMESPACE 17 | 18 | class ConfigBuilder { 19 | public: 20 | explicit ConfigBuilder(ConfigType type); 21 | 22 | virtual ConfigBuilder& version(int ver) = 0; 23 | 24 | virtual ConfigBuilder& driver(const QString& driver) = 0; 25 | 26 | virtual ConfigBuilder& databaseName(const QString& name) = 0; 27 | 28 | virtual ConfigBuilder& configAlias(const QString& alias) = 0; 29 | 30 | virtual ConfigBuilder& session(qint64 sessionId) = 0; 31 | 32 | virtual ConfigBuilder& password(const QString& password) = 0; 33 | 34 | virtual ConfigBuilder& options(const QString& options) = 0; 35 | 36 | ConfigBuilder& setDatabaseUpgrader(DatabaseUpgrader* databaseUpgrader); 37 | 38 | virtual QSqlDatabase getConnection(const QString& connectionName, const QString& databaseName) = 0; 39 | 40 | QSqlDatabase getConnection(const QString& connectionName); 41 | 42 | ConfigBuilder& disableCreateDatabase() { 43 | createDbEnabled = false; 44 | return *this; 45 | } 46 | 47 | ConfigBuilder& disableCreateTables() { 48 | createTableEnabled = false; 49 | return *this; 50 | } 51 | 52 | virtual void initializeDatabase() = 0; 53 | 54 | virtual ~ConfigBuilder() = default; 55 | 56 | bool isSqlite() const { 57 | return configType == ConfigType::Sqlite; 58 | } 59 | 60 | bool isMysql() const { 61 | return configType == ConfigType::Mysql; 62 | } 63 | 64 | bool isSqlServer() const { 65 | return configType == ConfigType::SqlServer; 66 | } 67 | 68 | bool isPSql() const { 69 | return configType == ConfigType::PSql; 70 | } 71 | 72 | QSharedPointer getClient() const { 73 | return dbClient; 74 | } 75 | 76 | static int getLocalVersion(qint64 sessionId = -1); 77 | 78 | protected: 79 | ConfigType configType; 80 | 81 | int mVersion = 1; 82 | QString mDriver; 83 | QString mDatabaseName; 84 | QString mPassword; 85 | QString mOptions; 86 | QString mAlias; 87 | qint64 mSessionId = -1; 88 | 89 | bool createDbEnabled = true; 90 | 91 | bool createTableEnabled = true; 92 | 93 | QSharedPointer dbClient; 94 | QSharedPointer dbUpgrader; 95 | 96 | friend class AbstractClient; 97 | friend class BaseQuery; 98 | friend class ::ConnectionPool; 99 | friend class VersionControl; 100 | friend class ConfigManager; 101 | 102 | protected: 103 | void setupDatabase(); 104 | }; 105 | 106 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configmanager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../global.h" 8 | 9 | QTDAO_BEGIN_NAMESPACE 10 | 11 | class ConfigBuilder; 12 | class ConfigManager { 13 | public: 14 | static void registerConfig(ConfigBuilder* config); 15 | static QSharedPointer getConfig(qint64 sessionId = -1); 16 | }; 17 | 18 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configmysql.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "configbuilder.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | class ConfigMysqlBuilder : public ConfigBuilder { 8 | public: 9 | explicit ConfigMysqlBuilder(); 10 | 11 | ConfigMysqlBuilder& version(int ver) override; 12 | 13 | ConfigMysqlBuilder& driver(const QString& driver) override; 14 | 15 | ConfigMysqlBuilder& databaseName(const QString& name) override; 16 | 17 | ConfigBuilder & configAlias(const QString &alias) override; 18 | 19 | ConfigBuilder & session(qint64 sessionId) override; 20 | 21 | ConfigMysqlBuilder& password(const QString& password) override; 22 | 23 | ConfigMysqlBuilder& options(const QString& options) override; 24 | 25 | ConfigMysqlBuilder& host(const QString& host); 26 | 27 | ConfigMysqlBuilder& user(const QString& user); 28 | 29 | ConfigMysqlBuilder& port(int port); 30 | 31 | ConfigMysqlBuilder& character(const QString& character); 32 | 33 | ConfigMysqlBuilder& collate(const QString& collate); 34 | 35 | QSqlDatabase getConnection(const QString& connectionName, const QString& databaseName) override; 36 | 37 | void initializeDatabase() override; 38 | 39 | private: 40 | QString mHost; 41 | QString mUser; 42 | int mPort; 43 | QString mCharacter; 44 | QString mCollate; 45 | 46 | friend class MysqlClient; 47 | }; 48 | 49 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configpsql.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "configbuilder.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | class ConfigPSqlBuilder : public ConfigBuilder { 8 | public: 9 | ConfigPSqlBuilder(); 10 | 11 | ConfigPSqlBuilder& version(int ver) override; 12 | 13 | ConfigPSqlBuilder& driver(const QString &driver) override; 14 | 15 | ConfigPSqlBuilder& databaseName(const QString &name) override; 16 | 17 | ConfigBuilder& configAlias(const QString &alias) override; 18 | 19 | ConfigBuilder& session(qint64 sessionId) override; 20 | 21 | ConfigPSqlBuilder& password(const QString &password) override; 22 | 23 | ConfigPSqlBuilder& options(const QString &options) override; 24 | 25 | ConfigPSqlBuilder& host(const QString& host); 26 | 27 | ConfigPSqlBuilder& user(const QString& user); 28 | 29 | ConfigPSqlBuilder& port(int port); 30 | 31 | ConfigPSqlBuilder& owner(const QString& owner); 32 | 33 | ConfigPSqlBuilder& encoding(const QString& encoding); 34 | 35 | ConfigPSqlBuilder& collate(const QString& collate); 36 | 37 | ConfigPSqlBuilder& ctype(const QString& ctype); 38 | 39 | ConfigPSqlBuilder& tableSpace(const QString& tableSpace); 40 | 41 | QSqlDatabase getConnection(const QString &connectionName, const QString &databaseName) override; 42 | 43 | void initializeDatabase() override; 44 | 45 | private: 46 | QString mHost; 47 | QString mUser; 48 | int mPort; 49 | QString mOwner; 50 | QString mEncoding; 51 | QString mCollate; 52 | QString mCType; 53 | QString mTableSpace; 54 | 55 | friend class PSqlClient; 56 | }; 57 | 58 | QTDAO_END_NAMESPACE 59 | -------------------------------------------------------------------------------- /include/config/configsqlite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "configbuilder.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | class ConfigSqliteBuilder : public ConfigBuilder { 8 | public: 9 | explicit ConfigSqliteBuilder(); 10 | 11 | ConfigSqliteBuilder& version(int ver) override; 12 | 13 | ConfigSqliteBuilder& driver(const QString& driver) override; 14 | 15 | ConfigSqliteBuilder& databaseName(const QString& name) override; 16 | 17 | ConfigBuilder & configAlias(const QString &alias) override; 18 | 19 | ConfigBuilder & session(qint64 sessionId) override; 20 | 21 | ConfigSqliteBuilder& password(const QString& password) override; 22 | 23 | ConfigSqliteBuilder& options(const QString& options) override; 24 | 25 | ConfigSqliteBuilder& saveDir(const QString& path); 26 | 27 | QSqlDatabase getConnection(const QString& connectionName, const QString& databaseName) override; 28 | 29 | void initializeDatabase() override; 30 | 31 | QString getDbStoreDirectory() const; 32 | 33 | QString getDbStorePath() const; 34 | 35 | private: 36 | QString mSaveDir; 37 | 38 | friend class SqliteClient; 39 | }; 40 | 41 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configsqlserver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "configbuilder.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | class ConfigSqlServerBuilder : public ConfigBuilder { 8 | public: 9 | explicit ConfigSqlServerBuilder(); 10 | 11 | ConfigSqlServerBuilder& version(int ver) override; 12 | 13 | ConfigSqlServerBuilder& driver(const QString& driver) override; 14 | 15 | ConfigSqlServerBuilder& databaseName(const QString& name) override; 16 | 17 | ConfigBuilder & configAlias(const QString &alias) override; 18 | 19 | ConfigBuilder & session(qint64 sessionId) override; 20 | 21 | ConfigSqlServerBuilder& password(const QString& password) override; 22 | 23 | ConfigSqlServerBuilder& options(const QString& options) override; 24 | 25 | ConfigSqlServerBuilder& host(const QString& host); 26 | 27 | ConfigSqlServerBuilder& user(const QString& user); 28 | 29 | ConfigSqlServerBuilder& port(int port); 30 | 31 | QSqlDatabase getConnection(const QString& connectionName, const QString& databaseName) override; 32 | 33 | void initializeDatabase() override; 34 | 35 | private: 36 | QString mHost; 37 | QString mUser; 38 | int mPort; 39 | }; 40 | 41 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/config/configtype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | enum class ConfigType { 8 | Sqlite, 9 | Mysql, 10 | SqlServer, 11 | PSql, 12 | }; 13 | 14 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/configselector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "global.h" 4 | 5 | #include 6 | #include 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | class ConfigBuilder; 11 | class EntityConfigDelegate { 12 | public: 13 | virtual void createEntityTables(ConfigBuilder* config) = 0; 14 | virtual void entityTablesUpgrade(ConfigBuilder* config, int oldVer, int newVer) = 0; 15 | 16 | virtual ~EntityConfigDelegate() = default; 17 | }; 18 | 19 | class ConfigSelector { 20 | public: 21 | static int registerConfig(const QString& alias, EntityConfigDelegate* delegate); 22 | 23 | static QSharedPointer getConfig(const QString& alias); 24 | }; 25 | 26 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/connectionpool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class ConnectionData { 14 | public: 15 | explicit ConnectionData(QString name); 16 | ~ConnectionData(); 17 | 18 | QSqlDatabase getOpenedConnection(qint64 sessionId); 19 | 20 | void beginSession(qint64 sessionId); 21 | void endSession(); 22 | qint64 stackTopSession(); 23 | 24 | private: 25 | QString baseConnectionName; 26 | QHash usedConnectionNames; 27 | QStack holdSessionIdStack; 28 | 29 | qint64 currentProcessSessionId = -1; 30 | 31 | private: 32 | void openNewConnection(); 33 | void testConnection(); 34 | 35 | QString nameForDatabase() const; 36 | }; 37 | 38 | class ConnectionPool { 39 | public: 40 | static QSqlDatabase getConnection(qint64 sessionId = -1); // get current thread connection 41 | 42 | static void scopeSessionBegin(qint64 sessionId); // begin use session id in current thread 43 | static void scopeSessionEnd(); // end use session id in current thread 44 | static qint64 scopeCurrentSessionId(); // read current thread session id 45 | 46 | static void closeAllConnection(); // close all opened connection 47 | static void closeConnection(qint64 sessionId = -1); // close all connections reference to the session id 48 | 49 | static int getUsedConnectionSize();// get current used connection names 50 | 51 | static QSqlDatabase prepareConnect(const QString& connectName, qint64 sessionId); 52 | 53 | private: 54 | ConnectionPool(); 55 | 56 | static ConnectionPool& getInstance(); 57 | 58 | static void initializeLocalData(); 59 | static void closeConnection(const QString& connectionName, const QStringList& nameInDatabase);// close target connection name, and push into unused names 60 | static QSqlDatabase createConnection(qint64 sessionId, const QString &connectionName); // create database connection 61 | 62 | QQueue unusedConnectionNames; 63 | int usedConnectionSize; 64 | QMutex mutex; 65 | 66 | static QThreadStorage localConnection; 67 | 68 | friend class ConnectionData; 69 | }; 70 | 71 | class ConnectionScopedSessionControl { 72 | public: 73 | explicit ConnectionScopedSessionControl(qint64 sessionId) { 74 | ConnectionPool::scopeSessionBegin(sessionId); 75 | } 76 | 77 | ~ConnectionScopedSessionControl() { 78 | ConnectionPool::scopeSessionEnd(); 79 | } 80 | }; 81 | 82 | #define DAO_SCOPED_SESSION_BEGIN(sessionId) QScopedPointer scopedSession##sessionId(new ConnectionScopedSessionControl(sessionId)) -------------------------------------------------------------------------------- /include/dbclients/mysqlclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "abstractclient.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class MysqlClient : public AbstractClient { 10 | public: 11 | void testConnect() override; 12 | 13 | void createDatabase() override; 14 | 15 | void dropDatabase() override; 16 | 17 | QStringList exportAllTables() override; 18 | 19 | bool checkTableExist(const QString& tbName) override; 20 | 21 | void createTableIfNotExist(const QString &tbName, 22 | const QStringList &fieldsType, 23 | const QStringList &primaryKeys, 24 | const QList& foreignKeys, 25 | const QString &engine) override; 26 | 27 | void renameTable(const QString& oldName, const QString& newName) override; 28 | 29 | void dropTable(const QString& tbName) override; 30 | 31 | void truncateTable(const QString& tbName) override; 32 | 33 | void enableForeignKey(const QString &tbName, bool enabled) override; 34 | 35 | void dropReferencedForeignKey(const QString &tbName) override; 36 | 37 | QList> exportAllFields(const QString &tbName) override; 38 | 39 | void addField(const QString &tbName, const QString &field) override; 40 | 41 | void dropField(const QString &tbName, const QString &fieldName) override; 42 | 43 | void renameField(const QString &tbName, const QString &oldFieldName, const QString &newFieldName) override; 44 | 45 | QHash exportAllIndexes(const QString &tbName) override; 46 | 47 | void createIndex(const QString &tbName, 48 | const QString &indexName, 49 | const QStringList& fields, 50 | dao::IndexType type, 51 | const QString &indexOption) override; 52 | 53 | void dropIndex(const QString& tbName, const QString& indexName) override; 54 | 55 | QString getIndexFromFields(const QString& tbName, const QStringList &fields) override; 56 | 57 | QString createEscapeCharsForName(const QString &sourceName) const override; 58 | 59 | QString removeEscapeCharsForName(const QString &sourceName) const override; 60 | }; 61 | 62 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/dbclients/psqlclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "abstractclient.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class PSqlClient : public AbstractClient { 10 | public: 11 | void testConnect() override; 12 | 13 | void createDatabase() override; 14 | 15 | void dropDatabase() override; 16 | 17 | QStringList exportAllTables() override; 18 | 19 | bool checkTableExist(const QString &tbName) override; 20 | 21 | void createTableIfNotExist(const QString &tbName, const QStringList &fieldsType, const QStringList &primaryKeys, const QList &foreignKeys, const QString &engine) override; 22 | 23 | void renameTable(const QString &oldName, const QString &newName) override; 24 | 25 | void dropTable(const QString &tbName) override; 26 | 27 | void truncateTable(const QString &tbName) override; 28 | 29 | void enableForeignKey(const QString &tbName, bool enabled) override; 30 | 31 | void dropReferencedForeignKey(const QString &tbName) override; 32 | 33 | QList> exportAllFields(const QString &tbName) override; 34 | 35 | void addField(const QString &tbName, const QString &field) override; 36 | 37 | void dropField(const QString &tbName, const QString &fieldName) override; 38 | 39 | void renameField(const QString &tbName, const QString &oldFieldName, const QString &newFieldName) override; 40 | 41 | QHash exportAllIndexes(const QString &tbName) override; 42 | 43 | void createIndex(const QString &tbName, const QString &indexName, const QStringList &fields, IndexType type, const QString &indexOption) override; 44 | 45 | void dropIndex(const QString &tbName, const QString &indexName) override; 46 | 47 | QString getIndexFromFields(const QString& tbName, const QStringList &fields) override; 48 | 49 | QString createEscapeCharsForName(const QString &sourceName) const override; 50 | 51 | QString removeEscapeCharsForName(const QString &sourceName) const override; 52 | }; 53 | 54 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/dbclients/sqliteclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "abstractclient.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class SqliteClient : public AbstractClient { 10 | public: 11 | void testConnect() override; 12 | 13 | void createDatabase() override; 14 | 15 | void dropDatabase() override; 16 | 17 | QStringList exportAllTables() override; 18 | 19 | bool checkTableExist(const QString& tbName) override; 20 | 21 | void createTableIfNotExist(const QString &tbName, 22 | const QStringList &fieldsType, 23 | const QStringList &primaryKeys, 24 | const QList& foreignKeys, 25 | const QString &engine) override; 26 | 27 | void renameTable(const QString& oldName, const QString& newName) override; 28 | 29 | void dropTable(const QString& tbName) override; 30 | 31 | void truncateTable(const QString& tbName) override; 32 | 33 | void enableForeignKey(const QString &tbName, bool enabled) override; 34 | 35 | void dropReferencedForeignKey(const QString &tbName) override; 36 | 37 | QList> exportAllFields(const QString &tbName) override; 38 | 39 | void addField(const QString &tbName, const QString &field) override; 40 | 41 | void dropField(const QString &tbName, const QString &fieldName) override; 42 | 43 | static bool dropColumnSupported(); 44 | 45 | void renameField(const QString &tbName, const QString &oldFieldName, const QString &newFieldName) override; 46 | 47 | static bool renameColumnSupported(); 48 | 49 | QHash exportAllIndexes(const QString &tbName) override; 50 | 51 | void createIndex(const QString &tbName, 52 | const QString &indexName, 53 | const QStringList& fields, 54 | dao::IndexType type, 55 | const QString &indexOption) override; 56 | 57 | void dropIndex(const QString& tbName, const QString& indexName) override; 58 | 59 | QString getIndexFromFields(const QString& tbName, const QStringList &fields) override; 60 | 61 | QString createEscapeCharsForName(const QString &sourceName) const override; 62 | 63 | QString removeEscapeCharsForName(const QString &sourceName) const override; 64 | }; 65 | 66 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/dbclients/sqlserverclient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include "abstractclient.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class SqlServerClient : public AbstractClient { 10 | public: 11 | void testConnect() override; 12 | 13 | void createDatabase() override; 14 | 15 | void dropDatabase() override; 16 | 17 | QStringList exportAllTables() override; 18 | 19 | bool checkTableExist(const QString& tbName) override; 20 | 21 | void createTableIfNotExist(const QString &tbName, 22 | const QStringList &fieldsType, 23 | const QStringList &primaryKeys, 24 | const QList& foreignKeys, 25 | const QString &engine) override; 26 | 27 | void renameTable(const QString& oldName, const QString& newName) override; 28 | 29 | void dropTable(const QString& tbName) override; 30 | 31 | void truncateTable(const QString& tbName) override; 32 | 33 | void enableForeignKey(const QString &tbName, bool enabled) override; 34 | 35 | void dropReferencedForeignKey(const QString &tbName) override; 36 | 37 | QList> exportAllFields(const QString &tbName) override; 38 | 39 | void addField(const QString &tbName, const QString &field) override; 40 | 41 | void dropField(const QString &tbName, const QString &fieldName) override; 42 | 43 | void dropConstraint(const QString& tbName, const QString& constraintName); 44 | 45 | void renameField(const QString &tbName, const QString &oldFieldName, const QString &newFieldName) override; 46 | 47 | QHash exportAllIndexes(const QString &tbName) override; 48 | 49 | void createIndex(const QString &tbName, 50 | const QString &indexName, 51 | const QStringList& fields, 52 | dao::IndexType type, 53 | const QString &indexOption) override; 54 | 55 | void dropIndex(const QString& tbName, const QString& indexName) override; 56 | 57 | QString getIndexFromFields(const QString& tbName, const QStringList &fields) override; 58 | 59 | void transferData(const QString &fromTb, const QString &toTb) override; 60 | 61 | void transferDataBefore(const QString& tbName); 62 | 63 | void transferDataAfter(const QString& tbName); 64 | 65 | QString createEscapeCharsForName(const QString &sourceName) const override; 66 | 67 | QString removeEscapeCharsForName(const QString &sourceName) const override; 68 | }; 69 | 70 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/dbexception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "global.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | QTDAO_BEGIN_NAMESPACE 11 | 12 | class DaoException : public QException { 13 | public: 14 | explicit DaoException(const QSqlError& error, QString sql = QString(), QVariantList values = QVariantList()) 15 | : reason(error.text()) 16 | , errorType(error.type()) 17 | , nativeCode(error.nativeErrorCode()) 18 | , sql(std::move(sql)) 19 | , values(std::move(values)) 20 | {} 21 | 22 | explicit DaoException(QString reason, QString sql = QString(), QVariantList values = QVariantList()) 23 | : reason(std::move(reason)) 24 | , errorType(QSqlError::ConnectionError) 25 | , sql(std::move(sql)) 26 | , values(std::move(values)) 27 | {} 28 | 29 | void raise() const override { throw* this; } 30 | DaoException* clone() const override { return new DaoException(*this); } 31 | 32 | QString reason; 33 | QSqlError::ErrorType errorType; 34 | QString nativeCode; 35 | 36 | QString sql; 37 | QVariantList values; 38 | }; 39 | 40 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/global.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dao.version.h" 4 | 5 | #define QTDAO_BEGIN_NAMESPACE namespace dao { 6 | 7 | #define QTDAO_END_NAMESPACE } 8 | 9 | #define QTDAO_USING_NAMESPACE using namespace dao; 10 | 11 | #define QTDAO_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) 12 | #define QTDAO_VERSION QTDAO_VERSION_CHECK(QTDAO_VERSION_MAJOR, QTDAO_VERSION_MINOR, QTDAO_VERSION_PATCH) 13 | 14 | //#define QTDAO_DEBUG 15 | 16 | #ifdef QTDAO_DEBUG 17 | #include 18 | #include 19 | 20 | //#define DEBUG_USE_STD 21 | #ifdef DEBUG_USE_STD 22 | #define PRINT_DEBUGGER std::cout 23 | #else 24 | #define PRINT_DEBUGGER qDebug() 25 | #endif 26 | 27 | #define MESSAGE_DEBUG(...) messageDebug(PRINT_DEBUGGER, __VA_ARGS__) 28 | 29 | QTDAO_BEGIN_NAMESPACE 30 | 31 | template 32 | inline void printMessage(D& debug, const T& msg) { 33 | debug << msg; 34 | } 35 | 36 | template<> 37 | inline void printMessage(decltype(std::cout)& debug, const QString& msg) { 38 | debug << msg.toStdString(); 39 | } 40 | 41 | template 42 | inline void messageDebug(D& debug, const T& msg, const Args&... args) { 43 | printMessage(debug, msg); 44 | messageDebug(debug, args...); 45 | } 46 | 47 | template 48 | inline void messageDebug(D&) {} 49 | 50 | template<> 51 | inline void messageDebug(decltype(std::cout)& debug) { 52 | debug << std::endl; 53 | } 54 | 55 | QTDAO_END_NAMESPACE 56 | 57 | #else 58 | #define MESSAGE_DEBUG(...) 59 | #endif -------------------------------------------------------------------------------- /include/macro/macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define BASE_QUERY_CONSTRUCTOR_DECLARE(Q)\ 4 | friend class Q##Builder;\ 5 | explicit Q(Q##Builder builder): BuilderReaderProvider(std::move(builder)) {} 6 | -------------------------------------------------------------------------------- /include/query/delete.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "deleteimpl.h" 4 | 5 | #include "../macro/macro.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class DeleteBuilder; 11 | 12 | template 13 | class Delete 14 | : EntityReaderProvider 15 | , BuilderReaderProvider 16 | , DeleteImpl 17 | { 18 | public: 19 | /** 20 | * delete by filter condition 21 | */ 22 | void deleteBy(); 23 | 24 | /** 25 | * delete by filter condition in batches 26 | */ 27 | void deleteBatch(); 28 | 29 | /** 30 | * delete object by primary key 31 | * @param entity 32 | */ 33 | void deleteBy(const E& entity); 34 | 35 | /** 36 | * delete object by primary key in batches 37 | * @param entities 38 | */ 39 | void deleteBatch(const QList& entities); 40 | 41 | private: 42 | BASE_QUERY_CONSTRUCTOR_DECLARE(Delete) 43 | }; 44 | 45 | template 46 | inline void Delete::deleteBy() { 47 | buildDeleteByFilterSqlStatement(); 48 | setDebug(this->builder); 49 | exec(getSessionId()); 50 | } 51 | 52 | template 53 | inline void Delete::deleteBatch() { 54 | buildDeleteByFilterSqlStatement(); 55 | setDebug(this->builder); 56 | execBatch(getSessionId()); 57 | } 58 | 59 | template 60 | inline void Delete::deleteBy(const E& entity) { 61 | buildDeleteEntitiesCondition(QList() << entity); 62 | return deleteBy(); 63 | } 64 | 65 | template 66 | inline void Delete::deleteBatch(const QList& entities) { 67 | if (entities.isEmpty()) { 68 | return; 69 | } 70 | buildDeleteEntitiesCondition(entities); 71 | return deleteBatch(); 72 | } 73 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/deleteimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | #include 8 | 9 | QTDAO_BEGIN_NAMESPACE 10 | 11 | class DeleteImpl 12 | : protected BaseQuery 13 | , protected virtual EntityReaderInterface 14 | , protected virtual BuilderReaderInterface 15 | { 16 | public: 17 | using BaseQuery::BaseQuery; 18 | 19 | protected: 20 | void buildDeleteByFilterSqlStatement(); 21 | 22 | void buildDeleteEntitiesCondition(const std::function& fieldColValuesReader); 23 | 24 | template 25 | void buildDeleteEntitiesCondition(const QList& entities); 26 | }; 27 | 28 | template 29 | inline void DeleteImpl::buildDeleteEntitiesCondition(const QList &entities) { 30 | buildDeleteEntitiesCondition([&](const QString& fieldName) { 31 | return listMap(entities, [&](const E& entity) { 32 | return E::Tool::getValueByName(entity, fieldName); 33 | }); 34 | }); 35 | } 36 | 37 | QTDAO_END_NAMESPACE 38 | -------------------------------------------------------------------------------- /include/query/explaininfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | struct SqliteExplainInfo { 10 | qint64 addr; 11 | QString opcode; 12 | qint64 p1; 13 | qint64 p2; 14 | qint64 p3; 15 | QString p4; 16 | QString p5; 17 | QString comment; 18 | }; 19 | 20 | struct SqliteExplainQueryPlanInfo { 21 | QList> data; 22 | }; 23 | 24 | struct MysqlExplainInfo { 25 | quint64 id; 26 | QString selectType; 27 | QString table; 28 | QString partitions; 29 | QString type; 30 | QString possibleKeys; 31 | QString key; 32 | QString keyLen; 33 | QString ref; 34 | quint64 rows; 35 | qreal filtered; 36 | QString extra; 37 | }; 38 | 39 | struct SqlServerExplainInfo { 40 | qint64 Rows; 41 | qint64 Executes; 42 | QString StmtText; 43 | int StmtId; 44 | int NodeId; 45 | int Parent; 46 | QString PhysicalOp; 47 | QString LogicalOp; 48 | QString Argument; 49 | QString DefinedValues; 50 | qreal EstimateRows; 51 | qreal EstimateIO; 52 | qreal EstimateCPU; 53 | int AvgRowSize; 54 | qreal TotalSubtreeCost; 55 | QString OutputList; 56 | QString Warnings; 57 | QString Type; 58 | uint Parallel; 59 | qreal EstimateExecutions; 60 | }; 61 | 62 | struct PSqlExplainInfo { 63 | QString nodeType; 64 | bool parallelAware; 65 | bool asyncCapable; 66 | QString relationName; 67 | QString alias; 68 | double startupCost; 69 | double totalCost; 70 | double planRows; 71 | double planWidth; 72 | }; 73 | 74 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/insertimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class InsertImpl 10 | : protected BaseQuery 11 | , protected virtual EntityReaderInterface 12 | , protected virtual BuilderReaderInterface 13 | { 14 | public: 15 | using BaseQuery::BaseQuery; 16 | 17 | protected: 18 | bool buildInsertBySetSqlStatement(); 19 | 20 | QString buildInsertObjectSqlStatement(); 21 | 22 | QString buildInsertObjectsSqlStatement(); 23 | 24 | QString buildInsertObjects2SqlStatement(int valueSize); 25 | 26 | protected: 27 | enum class InsertMode { 28 | INSERT_ONLY, 29 | INSERT_OR_REPLACE, 30 | INSERT_OR_IGNORE, 31 | }; 32 | 33 | InsertMode insertMode = InsertMode::INSERT_ONLY; 34 | 35 | private: 36 | QString buildInsertPrefix(); 37 | }; 38 | 39 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/insertintoselect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "insertintoselectimpl.h" 4 | 5 | #include "../macro/macro.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class InsertIntoSelectBuilder; 11 | 12 | template 13 | class InsertIntoSelect 14 | : EntityReaderProvider 15 | , BuilderReaderProvider 16 | , InsertIntoSelectImpl 17 | { 18 | public: 19 | /** 20 | * select and copy from other select results 21 | */ 22 | void insert(); 23 | 24 | private: 25 | BASE_QUERY_CONSTRUCTOR_DECLARE(InsertIntoSelect) 26 | }; 27 | 28 | template 29 | inline void InsertIntoSelect::insert() { 30 | buildSqlStatement(); 31 | setDebug(this->builder); 32 | exec(getSessionId()); 33 | } 34 | 35 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/insertintoselectimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class InsertIntoSelectImpl 10 | : protected BaseQuery 11 | , protected virtual EntityReaderInterface 12 | , protected virtual BuilderReaderInterface 13 | { 14 | public: 15 | using BaseQuery::BaseQuery; 16 | 17 | protected: 18 | void buildSqlStatement(); 19 | }; 20 | 21 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/selectimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class FromBuilder; 10 | class SelectImpl 11 | : protected BaseQuery 12 | , protected virtual EntityReaderInterface 13 | , protected virtual BuilderReaderInterface 14 | { 15 | public: 16 | using BaseQuery::BaseQuery; 17 | 18 | protected: 19 | void buildFilterSqlStatement(); 20 | 21 | QString getBindColumns(QVariantList& values); 22 | 23 | QString readExplainStatement(); 24 | 25 | //----- executors ----- 26 | typedef std::function EntityBinder; 27 | 28 | typedef std::function RecordBinder; 29 | 30 | static void recordBind(const QSqlRecord& record, const EntityBinder& entityBinder); 31 | 32 | void uniqueExec(const EntityBinder& entityBinder, const RecordBinder& recordHandler = nullptr); 33 | 34 | void oneExec(const EntityBinder& entityBinder, const RecordBinder& recordHandler = nullptr); 35 | 36 | void listExec(const RecordBinder& recordHandler); 37 | 38 | //----- caster ----- 39 | template 40 | static T readFromRecord(const QSqlRecord& record, const EntityField& field) { 41 | return record.value(field()).template value(); 42 | } 43 | 44 | template 45 | static QPair readFromRecord(const QSqlRecord& record, 46 | const EntityField& field1, 47 | const EntityField& field2) { 48 | return qMakePair(readFromRecord(record, field1), readFromRecord(record, field2)); 49 | } 50 | 51 | template 52 | static std::tuple readFromRecords(const QSqlRecord& record, 53 | const EntityField& field, 54 | const Args&... args) { 55 | auto d = readFromRecord(record, field); 56 | return std::tuple_cat(std::tie(d), readFromRecords(record, args...)); 57 | } 58 | 59 | template 60 | static std::tuple readFromRecords(const QSqlRecord& record, const EntityField& field) { 61 | return std::make_tuple(readFromRecord(record, field)); 62 | } 63 | 64 | protected: 65 | int topSize = 0; 66 | bool topPercent = false; 67 | 68 | friend class FromBuilder; 69 | friend class UnionBuilderImpl; 70 | }; 71 | 72 | QTDAO_END_NAMESPACE 73 | -------------------------------------------------------------------------------- /include/query/update.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "updateimpl.h" 4 | 5 | #include "../macro/macro.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class UpdateBuilder; 11 | 12 | template 13 | class Update 14 | : EntityReaderProvider 15 | , BuilderReaderProvider 16 | , UpdateImpl 17 | { 18 | public: 19 | /** 20 | * using the SET condition to update a record 21 | * @return effect rows 22 | */ 23 | int update(); 24 | 25 | /** 26 | * using the SET condition to update a record in batches 27 | * @return effect rows 28 | */ 29 | int updateBatch(); 30 | 31 | /** 32 | * update by object's primary key 33 | * @param entity 34 | * @return effect rows 35 | */ 36 | int update(const E& entity); 37 | 38 | /** 39 | * update by object's primary key in batches 40 | * @param entities 41 | * @return effect rows 42 | */ 43 | int updateBatch(const QList& entities); 44 | 45 | private: 46 | BASE_QUERY_CONSTRUCTOR_DECLARE(Update) 47 | }; 48 | 49 | template 50 | inline int Update::update() { 51 | buildUpdateBySetSqlStatement(); 52 | setDebug(this->builder); 53 | auto query = exec(getSessionId()); 54 | return query.numRowsAffected(); 55 | } 56 | 57 | template 58 | inline int Update::updateBatch() { 59 | buildUpdateBySetSqlStatement(); 60 | setDebug(this->builder); 61 | auto query = execBatch(getSessionId()); 62 | return query.numRowsAffected(); 63 | } 64 | 65 | template 66 | inline int Update::update(const E& entity) { 67 | bindUpdateEntitiesCondition(QList() << entity); 68 | return update(); 69 | } 70 | 71 | template 72 | inline int Update::updateBatch(const QList& entities) { 73 | if (entities.isEmpty()) { 74 | return 0; 75 | } 76 | bindUpdateEntitiesCondition(entities); 77 | return updateBatch(); 78 | } 79 | 80 | QTDAO_END_NAMESPACE 81 | -------------------------------------------------------------------------------- /include/query/updateimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class UpdateImpl 10 | : protected BaseQuery 11 | , protected virtual EntityReaderInterface 12 | , protected virtual BuilderReaderInterface 13 | { 14 | public: 15 | using BaseQuery::BaseQuery; 16 | 17 | protected: 18 | void buildUpdateBySetSqlStatement(); 19 | 20 | void bindUpdateEntitiesCondition(const std::function& fieldColValuesReader); 21 | 22 | template 23 | void bindUpdateEntitiesCondition(const QList& entities); 24 | }; 25 | 26 | template 27 | inline void UpdateImpl::bindUpdateEntitiesCondition(const QList &entities) { 28 | bindUpdateEntitiesCondition([&](const QString& fieldName) { 29 | return listMap(entities, [&](const E& entity) { 30 | return E::Tool::getValueByName(entity, fieldName); 31 | }); 32 | }); 33 | } 34 | 35 | 36 | QTDAO_END_NAMESPACE 37 | -------------------------------------------------------------------------------- /include/query/upsert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "upsertimpl.h" 4 | 5 | #include "../macro/macro.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | class UpsertBuilder; 11 | 12 | template 13 | class Upsert 14 | : EntityReaderProvider 15 | , BuilderReaderProvider 16 | , UpsertImpl 17 | { 18 | public: 19 | /** 20 | * using the SET condition to insert a record, can be inserted in batches 21 | */ 22 | void insert(); 23 | 24 | /** 25 | * insert an object instance and set the ID back to the object after successful insertion 26 | * @param entity 27 | */ 28 | void insert(E& entity); 29 | 30 | /** 31 | * insert objects in batches, use 'execbatch' 32 | * @param entities 33 | */ 34 | void insert(const QList& entities); 35 | 36 | private: 37 | BASE_QUERY_CONSTRUCTOR_DECLARE(Upsert) 38 | }; 39 | 40 | template 41 | void Upsert::insert() { 42 | bool operateBatch = buildInsertBySetSqlStatement(); 43 | setDebug(this->builder); 44 | 45 | operateBatch ? execBatch(getSessionId()) : exec(getSessionId()); 46 | } 47 | 48 | template 49 | void Upsert::insert(E &entity) { 50 | 51 | auto values = EntityReaderProvider::getValueWithoutAutoIncrement(entity); 52 | auto fields = getFieldsWithoutAutoIncrement(); 53 | auto sqlStatement = buildInsertStatement(fields, [&](const QString& field) { 54 | return values.at(fields.indexOf(field)); 55 | }); 56 | values.append(this->values); 57 | setSqlQueryStatement(sqlStatement, values); 58 | setDebug(this->builder); 59 | 60 | QSqlQuery query = exec(getSessionId()); 61 | EntityReaderProvider::bindAutoIncrementId(entity, query.lastInsertId()); 62 | } 63 | 64 | template 65 | void Upsert::insert(const QList &entities) { 66 | 67 | if (entities.isEmpty()) { 68 | return; 69 | } 70 | 71 | QVector values(fieldSize()); 72 | int usedValueSize = 0; 73 | for (const auto& entity : entities) { 74 | auto v = EntityReaderProvider::getValueWithoutAutoIncrement(entity); 75 | usedValueSize = v.size(); 76 | for (int i = 0; i < v.size(); i++) { 77 | values[i] << v.at(i); 78 | } 79 | } 80 | QVariantList tagValues; 81 | for (int i = 0; i < usedValueSize; i++) { 82 | tagValues << QVariant(values.at(i)); 83 | } 84 | 85 | auto fields = getFieldsWithoutAutoIncrement(); 86 | auto sqlStatement = buildInsertStatement(fields, [&](const QString& field) { 87 | return tagValues.at(fields.indexOf(field)); 88 | }); 89 | 90 | tagValues.append(this->values); 91 | setSqlQueryStatement(sqlStatement, tagValues); 92 | setDebug(this->builder); 93 | 94 | execBatch(getSessionId()); 95 | } 96 | 97 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/query/upsertimpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "basequery.h" 4 | #include "reader/entityreaderinterface.h" 5 | #include "reader/builderreaderinterface.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class UpsertImpl 10 | : protected BaseQuery 11 | , protected virtual EntityReaderInterface 12 | , protected virtual BuilderReaderInterface 13 | { 14 | public: 15 | using BaseQuery::BaseQuery; 16 | 17 | protected: 18 | bool buildInsertBySetSqlStatement(); 19 | 20 | QString buildInsertStatement(const QStringList& fields, const std::function& fieldToValue); 21 | }; 22 | 23 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/utils/dbupgrader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | #include "../query/reader/entityreaderinterface.h" 5 | 6 | #include 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | class AbstractClient; 11 | class ConfigBuilder; 12 | 13 | class DatabaseUpgrader { 14 | public: 15 | DatabaseUpgrader(); 16 | 17 | void setEntityReader(EntityReaderInterface* reader); 18 | 19 | void setCurClient(AbstractClient* curClient); 20 | 21 | void setCurConfig(ConfigBuilder* curConfig); 22 | 23 | virtual void onUpgrade(int oldVersion, int curVersion); 24 | 25 | protected: 26 | void upgradeWithDataRecovery(); 27 | 28 | protected: 29 | EntityReaderInterface* entityReader; 30 | 31 | AbstractClient* client = nullptr; 32 | ConfigBuilder* config = nullptr; 33 | }; 34 | 35 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/utils/listutils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | #include 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | template 10 | static QList listMap(const QList& src, const std::function& transfer) { 11 | QList data; 12 | for (const auto& s : src) { 13 | data << transfer(s); 14 | } 15 | return data; 16 | } 17 | 18 | template 19 | static QList listMap(const QList& src, L* context, T(L::*transfer)(const K&)) { 20 | QList data; 21 | for (const auto& s : src) { 22 | data << (context->*transfer)(s); 23 | } 24 | return data; 25 | } 26 | 27 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/utils/logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | typedef const QLoggingCategory& (*LoggingCategoryPtr)(); 10 | 11 | QTDAO_END_NAMESPACE 12 | -------------------------------------------------------------------------------- /include/utils/serializing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include 6 | #include 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | template 11 | static QByteArray serializeCustomTypeToBinary(const T& data) { 12 | QByteArray serializedData; 13 | QDataStream load(&serializedData, QIODevice::WriteOnly); 14 | load << data; 15 | return serializedData; 16 | } 17 | 18 | template 19 | static T deserializeBinaryToCustomType(const QByteArray& data) { 20 | T t; 21 | QDataStream load(data); 22 | load >> t; 23 | return t; 24 | } 25 | 26 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/utils/variantcast.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | QTDAO_BEGIN_NAMESPACE 6 | 7 | struct VariantCastUtil { 8 | template 9 | static QVariant getSupportedValue(const typename std::enable_if::value, E>::type& v) { 10 | return v; 11 | } 12 | 13 | template 14 | static QVariant getSupportedValue(const typename std::enable_if::value, E>::type& v) { 15 | qFatal("used error type!"); 16 | return {}; 17 | } 18 | 19 | template 20 | static QVariant getSupportedValue(const typename std::enable_if::value, QList>::type& v) { 21 | return v; 22 | } 23 | 24 | template 25 | static QVariant getSupportedValue(const typename std::enable_if::value, QList>::type& v) { 26 | qFatal("used error type!"); 27 | return {}; 28 | } 29 | 30 | template 31 | static const QList& getSupportedValues(const typename std::enable_if::value, QList>::type& v) { 32 | return v; 33 | } 34 | 35 | template 36 | static QList getSupportedValues(const typename std::enable_if::value, QList>::type& v) { 37 | qFatal("used error type!"); 38 | return {}; 39 | } 40 | }; 41 | 42 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /include/versionctl/version_table.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /include/versionctl/versioncontrol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../global.h" 4 | 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | class VersionControl { 10 | public: 11 | static void checkLocalVersion(qint64 sessionId); 12 | 13 | static int getLocalVersion(qint64 sessionId); 14 | 15 | private: 16 | static void updateLocalVersion(qint64 sessionId); 17 | 18 | static void invokeCreateTables(qint64 sessionId); 19 | 20 | static void invokeTableUpgrade(int oldVer, int newVer, qint64 sessionId); 21 | }; 22 | 23 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /qtdaolib/qtdaolib.pro: -------------------------------------------------------------------------------- 1 | QT -= gui 2 | QT += sql 3 | 4 | TEMPLATE = lib 5 | CONFIG += staticlib 6 | 7 | CONFIG += c++11 8 | 9 | CONFIG += debug_and_release build_all 10 | 11 | CONFIG(debug, debug|release){ 12 | contains(DEFINES, WIN64){ 13 | DESTDIR = $$PWD/../lib/x64 14 | } else { 15 | DESTDIR = $$PWD/../lib/x86 16 | } 17 | TARGET = qtdao_d 18 | } else { 19 | contains(DEFINES, WIN64){ 20 | DESTDIR = $$PWD/../lib/x64 21 | } else { 22 | DESTDIR = $$PWD/../lib/x86 23 | } 24 | TARGET = qtdao 25 | } 26 | 27 | # The following define makes your compiler emit warnings if you use 28 | # any Qt feature that has been marked deprecated (the exact warnings 29 | # depend on your compiler). Please consult the documentation of the 30 | # deprecated API in order to know how to port your code away from it. 31 | DEFINES += QT_DEPRECATED_WARNINGS 32 | 33 | # You can also make your code fail to compile if it uses deprecated APIs. 34 | # In order to do so, uncomment the following line. 35 | # You can also select to disable deprecated APIs only up to a certain version of Qt. 36 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 37 | 38 | include(qtdaolib.pri) 39 | 40 | INCLUDEPATH += ../include 41 | 42 | # Default rules for deployment. 43 | unix { 44 | target.path = $$[QT_INSTALL_PLUGINS]/generic 45 | } 46 | !isEmpty(target.path): INSTALLS += target 47 | 48 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## qt database object library 2 | 3 | 这是一个数据库查询与对象转换的操作库,支持基本增删改查操作,它能简单的将查询结果转换为定义好的类实例,基本原理是通过代码生成器和模板配合进行转换,下面是一个简单的示例展示了如何查询一个结果 4 | ```c++ 5 | Test1::Fields sf1; 6 | Test1 d1 = dao::_select() 7 | .filter(sf1.name == "client", _or(sf1.number == 12, sf1.name == "bob")) 8 | .build().one(); 9 | ``` 10 | 等价于下面的sql语句: 11 | ```sql 12 | select *from test1 where name='client' and (number=12 or name='bob') 13 | ``` 14 | 15 | 下面是当前受支持的数据库 16 | - [x] sqlite 17 | - [x] mysql 18 | - [x] sqlserver 19 | - [x] postgresql 20 | 21 | ## 如何使用 22 | [https://daonvshu.github.io/QtDao/](https://daonvshu.github.io/QtDao/) -------------------------------------------------------------------------------- /src/QtDaoConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | @_find_dependency_calls@ 5 | 6 | include("${CMAKE_CURRENT_LIST_DIR}/QtDaoTargets.cmake") -------------------------------------------------------------------------------- /src/builder/frombuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "builder/option/frombuilder.h" 2 | 3 | #include "query/selectimpl.h" 4 | #include "query/joinimpl.h" 5 | #include "builder/recursivequerybuilder.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | void FromBuilder::fromSelect(SelectImpl &select) { 10 | select.buildFilterSqlStatement(); 11 | fromData.statement = select.statement; 12 | fromData.values = select.values; 13 | 14 | auto& selectFromData = select.fromBuildData(); 15 | if (selectFromData.asName.isEmpty()) { 16 | fromData.asName = "sel_" + select.getTableName(); 17 | } else { 18 | fromData.asName = "sel_" + selectFromData.asName; 19 | } 20 | } 21 | 22 | void FromBuilder::fromJoin(JoinImpl &join) { 23 | join.buildJoinSqlStatement(); 24 | fromData.statement = join.statement; 25 | fromData.values = join.values; 26 | 27 | auto& mainFromData = join.fromBuildData(); 28 | if (mainFromData.asName.isEmpty()) { 29 | fromData.asName = "join_" + join.mainTable; 30 | } else { 31 | fromData.asName = "join_" + mainFromData.asName; 32 | } 33 | } 34 | 35 | void FromBuilder::fromBuilder(RecursiveQueryBuilder &builder) { 36 | Q_ASSERT(!builder.initialQueryStatement.isEmpty()); 37 | Q_ASSERT(!builder.recursiveQueryStatement.isEmpty()); 38 | Q_ASSERT(!builder.tmpTableName.isEmpty()); 39 | 40 | fromData.asName = builder.tmpTableName; 41 | fromData.statement = QString("with %1 as (%2 %3 %4) ") 42 | .arg(fromData.asName, 43 | builder.initialQueryStatement, 44 | builder.unionAll ? "union all" : "union", 45 | builder.recursiveQueryStatement 46 | ); 47 | fromData.values.append(builder.initialQueryValue); 48 | fromData.values.append(builder.recursiveQueryValue); 49 | fromData.recursiveQuery = true; 50 | } 51 | 52 | QTDAO_END_NAMESPACE 53 | 54 | -------------------------------------------------------------------------------- /src/builder/unionbuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "builder/option/unionbuilder.h" 2 | 3 | #include "query/selectimpl.h" 4 | #include "query/joinimpl.h" 5 | 6 | #if QT_VERSION_MAJOR >= 6 7 | #include "config/configbuilder.h" 8 | #include "config/configmanager.h" 9 | 10 | QTDAO_BEGIN_NAMESPACE 11 | 12 | void UnionBuilderImpl::unionWithSelect(SelectImpl &select, bool unionAll) { 13 | auto config = ConfigManager::getConfig(); 14 | if (config->isSqlServer()) { 15 | qFatal("The current version of the union query in Qt6 fails the test case when using SQLServer."); 16 | } 17 | select.buildFilterSqlStatement(); 18 | unionData.statement = select.statement; 19 | unionData.values = select.values; 20 | unionData.unionAll = unionAll; 21 | } 22 | 23 | void UnionBuilderImpl::unionWithJoin(JoinImpl &join, bool unionAll) { 24 | auto config = ConfigManager::getConfig(); 25 | if (config->isSqlServer()) { 26 | qFatal("The current version of the union query in Qt6 fails the test case when using SQLServer."); 27 | } 28 | join.buildJoinSqlStatement(); 29 | unionData.statement = join.statement; 30 | unionData.values = join.values; 31 | unionData.unionAll = unionAll; 32 | } 33 | #else 34 | 35 | QTDAO_BEGIN_NAMESPACE 36 | 37 | void UnionBuilderImpl::unionWithSelect(SelectImpl &select, bool unionAll) { 38 | select.buildFilterSqlStatement(); 39 | unionData.statement = select.statement; 40 | unionData.values = select.values; 41 | unionData.unionAll = unionAll; 42 | } 43 | 44 | void UnionBuilderImpl::unionWithJoin(JoinImpl &join, bool unionAll) { 45 | join.buildJoinSqlStatement(); 46 | unionData.statement = join.statement; 47 | unionData.values = join.values; 48 | unionData.unionAll = unionAll; 49 | } 50 | #endif 51 | 52 | QTDAO_END_NAMESPACE 53 | 54 | -------------------------------------------------------------------------------- /src/condition/conditionconstraint.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/conditionconstraint.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | LimitConstraintConnector::LimitConstraintConnector(int rows) { 6 | d->values << rows; 7 | } 8 | 9 | LimitConstraintConnector::LimitConstraintConnector(int offset, int rows) { 10 | d->values << offset << rows; 11 | } 12 | 13 | void LimitConstraintConnector::combine() { 14 | d->connectedStr = "limit ?"; 15 | if (d->values.size() > 1) { 16 | d->connectedStr += ",?"; 17 | } 18 | } 19 | 20 | bool LimitConstraintConnector::isEmpty() { 21 | return d->values.isEmpty(); 22 | } 23 | 24 | QVariantList LimitConstraintConnector::getValueList() { 25 | return d->values; 26 | } 27 | 28 | void OrderByConstraintConnector::combine() { 29 | d->connectedStr = "order by "; 30 | for (int i = 0; i < d->fields.size(); i++) { 31 | d->connectedStr.append(getField(i)).append(','); 32 | } 33 | d->connectedStr.chop(1); 34 | } 35 | 36 | void GroupByConstraintConnector::combine() { 37 | d->connectedStr = "group by "; 38 | for (int i = 0; i < d->fields.size(); i++) { 39 | d->connectedStr.append(getField(i)).append(','); 40 | } 41 | d->connectedStr.chop(1); 42 | } 43 | 44 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/condition/connector/connectable.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/connector/connectable.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | QList Connectable::getUsedFields() { 6 | return d->fields; 7 | } 8 | 9 | QVariantList Connectable::getValueList() { 10 | return d->values; 11 | } 12 | 13 | QString Connectable::getConditionSegment() { 14 | return d->connectedStr; 15 | } 16 | 17 | bool Connectable::isEmpty() { 18 | return d->fields.isEmpty(); 19 | } 20 | 21 | QString Connectable::getField(int index) const { 22 | if (d->fieldPrefixGetter == nullptr) { 23 | return d->fields.at(index).name; 24 | } 25 | return d->fieldPrefixGetter(d->fields.at(index).bindTable) + d->fields.at(index).name; 26 | } 27 | 28 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/condition/connector/entityconnector.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/connector/entityconnector.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void EntityConnector::addField(const FieldInfo& field) { 6 | d->fields << field; 7 | } 8 | 9 | void EntityConnector::addValue(const QVariant& value) { 10 | d->values << value; 11 | } 12 | 13 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/condition/connector/groupconnector.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/connector/groupconnector.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void GroupConnector::combine() { 6 | d->clear(); 7 | auto symbol = connectSymbol(); 8 | for (auto* connector : p->connectors) { 9 | connector->setFieldPrefixGetter(d->fieldPrefixGetter); 10 | connector->combine(); 11 | d->fields << connector->getUsedFields(); 12 | d->values << connector->getValueList(); 13 | auto segment = connector->getConditionSegment(); 14 | if (dynamic_cast(connector) != nullptr || 15 | dynamic_cast(connector) != nullptr) { 16 | d->connectedStr += '(' + segment + ')'; 17 | } else { 18 | d->connectedStr += segment; 19 | } 20 | 21 | d->connectedStr += symbol; 22 | } 23 | d->connectedStr = d->connectedStr.left(d->connectedStr.length() - symbol.length()); 24 | } 25 | 26 | bool GroupConnector::isEmpty() { 27 | bool isAllEmpty = Connectable::isEmpty(); 28 | if (!isAllEmpty) { 29 | return isAllEmpty; 30 | } 31 | 32 | for (auto* connector : p->connectors) { 33 | isAllEmpty = connector->isEmpty() && isAllEmpty; 34 | } 35 | 36 | return isAllEmpty; 37 | } 38 | 39 | void HavingGroupConnector::combine() { 40 | GroupConnector::combine(); 41 | d->connectedStr.prepend("having "); 42 | } 43 | 44 | QTDAO_END_NAMESPACE 45 | -------------------------------------------------------------------------------- /src/condition/entitycondition.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/entitycondition.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void OperatorEntityConnector::combine() { 6 | //same as a>=1 7 | d->connectedStr = getField(0) + connectorOp + "?"; 8 | } 9 | 10 | void SelfOperatorEntityConnector::combine() { 11 | //same as a=a+1 12 | d->connectedStr = getField(0) + "=" + getField(0) + connectorOp + "?"; 13 | } 14 | 15 | void FieldOperatorEntityConnector::combine() { 16 | //same as a>=b 17 | d->connectedStr = getField(0) + connectorOp + getField(1); 18 | } 19 | 20 | void SelfFieldOperatorEntityConnector::combine() { 21 | //same as a=a+b 22 | d->connectedStr = getField(0) + "=" + getField(0) + connectorOp + getField(1); 23 | } 24 | 25 | void InEntityConnector::combine() { 26 | QString str = "%1 in (%2)"; 27 | d->connectedStr = str.arg(getField(0), QString("?,").repeated(d->values.size()).chopped(1)); 28 | } 29 | 30 | void BetweenConnector::combine() { 31 | d->connectedStr = getField(0) + " between ? and ?"; 32 | } 33 | 34 | void IsNullConnector::combine() { 35 | d->connectedStr = getField(0) + " is " + (checkIsNull ? "null" : "not null"); 36 | } 37 | 38 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/condition/functioncondition.cpp: -------------------------------------------------------------------------------- 1 | #include "condition/functioncondition.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | QList FunctionConnector::getUsedFields() { 6 | int asIndex = expressions.indexOf(" as "); 7 | if (asIndex != -1) { 8 | if (d->fields.isEmpty()) { 9 | return QList() << FieldInfo{ expressions.mid(asIndex + 4), "" }; //empty tablename 10 | } else { 11 | return QList() << FieldInfo{ expressions.mid(asIndex + 4), d->fields.at(0).bindTable }; //use first bind table 12 | } 13 | } 14 | if (d->fields.isEmpty()) { 15 | return QList() << FieldInfo{ expressions, "" }; //empty tablename 16 | } 17 | QString str = expressions; 18 | for (int i = 0; i < d->fields.size(); i++) { 19 | str = str.arg(getField(i)); 20 | } 21 | return QList() << FieldInfo{ str, d->fields.at(0).bindTable }; //use first bind table 22 | } 23 | 24 | void FunctionConnector::combine() { 25 | QString str = expressions; 26 | for (int i = 0; i < d->fields.size(); i++) { 27 | str = str.arg(getField(i)); 28 | } 29 | d->connectedStr = str; 30 | } 31 | 32 | void FunctionConnector::fromSelect(SelectImpl& select) { 33 | FromBuilder::fromSelect(select); 34 | solveFromQueryBuildResult(); 35 | } 36 | 37 | void FunctionConnector::fromJoin(JoinImpl& join) { 38 | FromBuilder::fromJoin(join); 39 | solveFromQueryBuildResult(); 40 | } 41 | 42 | void FunctionConnector::fromBuilder(RecursiveQueryBuilder& builder) { 43 | FromBuilder::fromBuilder(builder); 44 | solveFromQueryBuildResult(); 45 | } 46 | 47 | void FunctionConnector::solveFromQueryBuildResult() { 48 | d->fields << FieldInfo{ fromData.statement.prepend('(').append(')'), "" }; 49 | d->values << fromData.values; 50 | fromDataClear(); 51 | } 52 | 53 | bool FunctionConnector::isEmpty() { 54 | return expressions.isEmpty() && Connectable::isEmpty(); 55 | } 56 | 57 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/config/configbuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configbuilder.h" 2 | #include "config/configmanager.h" 3 | 4 | #include "dbclients/mysqlclient.h" 5 | #include "dbclients/sqliteclient.h" 6 | #include "dbclients/sqlserverclient.h" 7 | #include "dbclients/psqlclient.h" 8 | 9 | #include "dbexception.h" 10 | #include "query/basequery.h" 11 | #include "versionctl/versioncontrol.h" 12 | 13 | #include "connectionpool.h" 14 | 15 | QTDAO_BEGIN_NAMESPACE 16 | 17 | ConfigBuilder::ConfigBuilder(ConfigType type) 18 | : configType(type) 19 | { 20 | switch (type) { 21 | case ConfigType::Sqlite: 22 | mDriver = "QSQLITE"; 23 | dbClient = QSharedPointer(new SqliteClient); 24 | break; 25 | case ConfigType::Mysql: 26 | mDriver = "QMYSQL"; 27 | dbClient = QSharedPointer(new MysqlClient); 28 | break; 29 | case ConfigType::SqlServer: 30 | mDriver = "QODBC"; 31 | dbClient = QSharedPointer(new SqlServerClient); 32 | break; 33 | case ConfigType::PSql: 34 | mDriver = "QPSQL"; 35 | dbClient = QSharedPointer(new PSqlClient); 36 | break; 37 | } 38 | } 39 | 40 | void ConfigBuilder::setupDatabase() { 41 | dbClient->config = this; 42 | dbClient->testConnect(); 43 | 44 | if (dbUpgrader.isNull()) { 45 | dbUpgrader = QSharedPointer(new DatabaseUpgrader); 46 | } 47 | dbUpgrader->setCurClient(dbClient.get()); 48 | dbUpgrader->setCurConfig(this); 49 | 50 | if (createDbEnabled) { 51 | dbClient->createDatabase(); 52 | } 53 | 54 | if (createTableEnabled) { 55 | if (mSessionId == -1) { 56 | VersionControl::checkLocalVersion(mSessionId); 57 | } else { 58 | DAO_SCOPED_SESSION_BEGIN(mSessionId); 59 | VersionControl::checkLocalVersion(mSessionId); 60 | } 61 | } 62 | } 63 | 64 | int ConfigBuilder::getLocalVersion(qint64 sessionId) { 65 | return VersionControl::getLocalVersion(sessionId); 66 | } 67 | 68 | ConfigBuilder &ConfigBuilder::setDatabaseUpgrader(DatabaseUpgrader *databaseUpgrader) { 69 | dbUpgrader = QSharedPointer(databaseUpgrader); 70 | return *this; 71 | } 72 | 73 | QSqlDatabase ConfigBuilder::getConnection(const QString &connectionName) { 74 | return getConnection(connectionName, mDatabaseName); 75 | } 76 | 77 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/config/configmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configmanager.h" 2 | #include "config/configbuilder.h" 3 | 4 | #include "dbexception.h" 5 | 6 | #include "connectionpool.h" 7 | 8 | QTDAO_BEGIN_NAMESPACE 9 | 10 | static QHash> configs; 11 | static QMutex configAccessLocker; 12 | 13 | void ConfigManager::registerConfig(ConfigBuilder *config) { 14 | QMutexLocker locker(&configAccessLocker); 15 | if (configs.contains(config->mSessionId)) { 16 | ConnectionPool::closeConnection(config->mSessionId); 17 | } 18 | configs.insert(config->mSessionId, QSharedPointer(config)); 19 | } 20 | 21 | QSharedPointer ConfigManager::getConfig(qint64 sessionId) { 22 | QMutexLocker locker(&configAccessLocker); 23 | if (!configs.contains(sessionId)) { 24 | sessionId = ConnectionPool::scopeCurrentSessionId(); 25 | if (!configs.contains(sessionId)) { 26 | throw DaoException("session is not register:" + QString::number(sessionId)); 27 | } 28 | } 29 | return configs[sessionId]; 30 | } 31 | 32 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/config/configmysql.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configmysql.h" 2 | #include "config/configmanager.h" 3 | 4 | #include "dao.h" 5 | 6 | QTDAO_BEGIN_NAMESPACE 7 | ConfigMysqlBuilder::ConfigMysqlBuilder() 8 | : ConfigBuilder(ConfigType::Mysql) 9 | , mHost("localhost") 10 | , mUser("root") 11 | , mPort(3306) 12 | , mCharacter("utf8mb4") 13 | , mCollate("utf8mb4_general_ci") 14 | { 15 | 16 | } 17 | 18 | ConfigMysqlBuilder& ConfigMysqlBuilder::version(int ver) { 19 | mVersion = ver; 20 | return *this; 21 | } 22 | 23 | ConfigMysqlBuilder& ConfigMysqlBuilder::driver(const QString& driver) { 24 | mDriver = driver; 25 | return *this; 26 | } 27 | 28 | ConfigMysqlBuilder& ConfigMysqlBuilder::databaseName(const QString& name) { 29 | mDatabaseName = name; 30 | return *this; 31 | } 32 | 33 | ConfigBuilder &ConfigMysqlBuilder::configAlias(const QString &alias) { 34 | mAlias = alias; 35 | return *this; 36 | } 37 | 38 | ConfigBuilder &ConfigMysqlBuilder::session(qint64 sessionId) { 39 | mSessionId = sessionId; 40 | return *this; 41 | } 42 | 43 | ConfigMysqlBuilder& ConfigMysqlBuilder::password(const QString& password) { 44 | mPassword = password; 45 | return *this; 46 | } 47 | 48 | ConfigMysqlBuilder& ConfigMysqlBuilder::options(const QString& options) { 49 | mOptions = options; 50 | return *this; 51 | } 52 | 53 | ConfigMysqlBuilder& ConfigMysqlBuilder::host(const QString& host) { 54 | mHost = host; 55 | return *this; 56 | } 57 | 58 | ConfigMysqlBuilder& ConfigMysqlBuilder::user(const QString& user) { 59 | mUser = user; 60 | return *this; 61 | } 62 | 63 | ConfigMysqlBuilder& ConfigMysqlBuilder::port(int port) { 64 | mPort = port; 65 | return *this; 66 | } 67 | 68 | ConfigMysqlBuilder & ConfigMysqlBuilder::character(const QString &character) { 69 | mCharacter = character; 70 | return *this; 71 | } 72 | 73 | ConfigMysqlBuilder & ConfigMysqlBuilder::collate(const QString &collate) { 74 | mCollate = collate; 75 | return *this; 76 | } 77 | 78 | QSqlDatabase ConfigMysqlBuilder::getConnection(const QString& connectionName, const QString& databaseName) { 79 | auto db = QSqlDatabase::addDatabase(mDriver, connectionName); 80 | db.setDatabaseName(databaseName); 81 | db.setUserName(mUser); 82 | db.setPassword(mPassword); 83 | db.setHostName(mHost); 84 | db.setPort(mPort); 85 | 86 | if (!mOptions.isEmpty()) { 87 | db.setConnectOptions(mOptions); 88 | } 89 | 90 | return db; 91 | } 92 | 93 | void ConfigMysqlBuilder::initializeDatabase() { 94 | auto config = new ConfigMysqlBuilder(*this); 95 | ConfigManager::registerConfig(config); 96 | config->setupDatabase(); 97 | } 98 | 99 | QTDAO_END_NAMESPACE 100 | -------------------------------------------------------------------------------- /src/config/configpsql.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configpsql.h" 2 | #include "config/configmanager.h" 3 | 4 | #include "dao.h" 5 | 6 | QTDAO_BEGIN_NAMESPACE 7 | ConfigPSqlBuilder::ConfigPSqlBuilder() 8 | : ConfigBuilder(ConfigType::PSql) 9 | , mHost("localhost") 10 | , mUser("postgres") 11 | , mPort(5432) 12 | , mEncoding("UTF8") 13 | {} 14 | 15 | ConfigPSqlBuilder & ConfigPSqlBuilder::version(int ver) { 16 | mVersion = ver; 17 | return *this; 18 | } 19 | 20 | ConfigPSqlBuilder & ConfigPSqlBuilder::driver(const QString &driver) { 21 | mDriver = driver; 22 | return *this; 23 | } 24 | 25 | ConfigPSqlBuilder & ConfigPSqlBuilder::databaseName(const QString &name) { 26 | mDatabaseName = name; 27 | return *this; 28 | } 29 | 30 | ConfigBuilder & ConfigPSqlBuilder::configAlias(const QString &alias) { 31 | mAlias = alias; 32 | return *this; 33 | } 34 | 35 | ConfigBuilder & ConfigPSqlBuilder::session(qint64 sessionId) { 36 | mSessionId = sessionId; 37 | return *this; 38 | } 39 | 40 | ConfigPSqlBuilder & ConfigPSqlBuilder::password(const QString &password) { 41 | mPassword = password; 42 | return *this; 43 | } 44 | 45 | ConfigPSqlBuilder & ConfigPSqlBuilder::options(const QString &options) { 46 | mOptions = options; 47 | return *this; 48 | } 49 | 50 | ConfigPSqlBuilder & ConfigPSqlBuilder::host(const QString &host) { 51 | mHost = host; 52 | return *this; 53 | } 54 | 55 | ConfigPSqlBuilder & ConfigPSqlBuilder::user(const QString &user) { 56 | mUser = user; 57 | return *this; 58 | } 59 | 60 | ConfigPSqlBuilder & ConfigPSqlBuilder::port(int port) { 61 | mPort = port; 62 | return *this; 63 | } 64 | 65 | ConfigPSqlBuilder & ConfigPSqlBuilder::owner(const QString &owner) { 66 | mOwner = owner; 67 | return *this; 68 | } 69 | 70 | ConfigPSqlBuilder & ConfigPSqlBuilder::encoding(const QString &encoding) { 71 | mEncoding = encoding; 72 | return *this; 73 | } 74 | 75 | ConfigPSqlBuilder & ConfigPSqlBuilder::collate(const QString &collate) { 76 | mCollate = collate; 77 | return *this; 78 | } 79 | 80 | ConfigPSqlBuilder & ConfigPSqlBuilder::ctype(const QString &ctype) { 81 | mCType = ctype; 82 | return *this; 83 | } 84 | 85 | ConfigPSqlBuilder & ConfigPSqlBuilder::tableSpace(const QString &tableSpace) { 86 | mTableSpace = tableSpace; 87 | return *this; 88 | } 89 | 90 | QSqlDatabase ConfigPSqlBuilder::getConnection(const QString &connectionName, const QString &databaseName) { 91 | auto db = QSqlDatabase::addDatabase(mDriver, connectionName); 92 | db.setDatabaseName(databaseName); 93 | db.setUserName(mUser); 94 | db.setPassword(mPassword); 95 | db.setHostName(mHost); 96 | db.setPort(mPort); 97 | 98 | if (!mOptions.isEmpty()) { 99 | db.setConnectOptions(mOptions); 100 | } 101 | 102 | return db; 103 | } 104 | 105 | void ConfigPSqlBuilder::initializeDatabase() { 106 | auto config = new ConfigPSqlBuilder(*this); 107 | ConfigManager::registerConfig(config); 108 | config->setupDatabase(); 109 | } 110 | 111 | 112 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/config/configsqlite.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configsqlite.h" 2 | #include "config/configmanager.h" 3 | 4 | #include 5 | #include 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | ConfigSqliteBuilder::ConfigSqliteBuilder() 9 | : ConfigBuilder(ConfigType::Sqlite) 10 | { 11 | 12 | } 13 | 14 | ConfigSqliteBuilder& ConfigSqliteBuilder::version(int ver) { 15 | mVersion = ver; 16 | return *this; 17 | } 18 | 19 | ConfigSqliteBuilder& ConfigSqliteBuilder::driver(const QString& driver) { 20 | mDriver = driver; 21 | return *this; 22 | } 23 | 24 | ConfigSqliteBuilder& ConfigSqliteBuilder::databaseName(const QString& name) { 25 | mDatabaseName = name; 26 | return *this; 27 | } 28 | 29 | ConfigBuilder &ConfigSqliteBuilder::configAlias(const QString &alias) { 30 | mAlias = alias; 31 | return *this; 32 | } 33 | 34 | ConfigBuilder &ConfigSqliteBuilder::session(qint64 sessionId) { 35 | mSessionId = sessionId; 36 | return *this; 37 | } 38 | 39 | ConfigSqliteBuilder& ConfigSqliteBuilder::password(const QString& password) { 40 | mPassword = password; 41 | return *this; 42 | } 43 | 44 | ConfigSqliteBuilder& ConfigSqliteBuilder::options(const QString& options) { 45 | mOptions = options; 46 | return *this; 47 | } 48 | 49 | ConfigSqliteBuilder& ConfigSqliteBuilder::saveDir(const QString& path) { 50 | mSaveDir = path; 51 | return *this; 52 | } 53 | 54 | QSqlDatabase ConfigSqliteBuilder::getConnection(const QString& connectionName, const QString&) { 55 | auto db = QSqlDatabase::addDatabase(mDriver, connectionName); 56 | db.setDatabaseName(getDbStorePath()); 57 | 58 | if (!mPassword.isEmpty()) { 59 | db.setPassword(mPassword); 60 | } 61 | 62 | if (!mOptions.isEmpty()) { 63 | db.setConnectOptions(mOptions); 64 | } 65 | 66 | if (db.open()) { 67 | QSqlQuery query(db); 68 | query.exec("PRAGMA foreign_keys = ON"); 69 | } 70 | 71 | return db; 72 | } 73 | 74 | QString ConfigSqliteBuilder::getDbStoreDirectory() const { 75 | auto savePath = mSaveDir; 76 | if (savePath.isEmpty()) { 77 | savePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 78 | } 79 | return savePath; 80 | } 81 | 82 | QString ConfigSqliteBuilder::getDbStorePath() const { 83 | return getDbStoreDirectory() + "/" + mDatabaseName + ".db"; 84 | } 85 | 86 | void ConfigSqliteBuilder::initializeDatabase() { 87 | auto config = new ConfigSqliteBuilder(*this); 88 | ConfigManager::registerConfig(config); 89 | config->setupDatabase(); 90 | } 91 | 92 | QTDAO_END_NAMESPACE 93 | -------------------------------------------------------------------------------- /src/config/configsqlserver.cpp: -------------------------------------------------------------------------------- 1 | #include "config/configsqlserver.h" 2 | #include "config/configmanager.h" 3 | 4 | QTDAO_BEGIN_NAMESPACE 5 | ConfigSqlServerBuilder::ConfigSqlServerBuilder() 6 | : ConfigBuilder(ConfigType::SqlServer) 7 | , mHost("localhost") 8 | , mUser("sa") 9 | , mPort(1433) 10 | { 11 | 12 | } 13 | 14 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::version(int ver) { 15 | mVersion = ver; 16 | return *this; 17 | } 18 | 19 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::driver(const QString& driver) { 20 | mDriver = driver; 21 | return *this; 22 | } 23 | 24 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::databaseName(const QString& name) { 25 | mDatabaseName = name; 26 | return *this; 27 | } 28 | 29 | ConfigBuilder &ConfigSqlServerBuilder::configAlias(const QString &alias) { 30 | mAlias = alias; 31 | return *this; 32 | } 33 | 34 | ConfigBuilder &ConfigSqlServerBuilder::session(qint64 sessionId) { 35 | mSessionId = sessionId; 36 | return *this; 37 | } 38 | 39 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::password(const QString& password) { 40 | mPassword = password; 41 | return *this; 42 | } 43 | 44 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::options(const QString& options) { 45 | mOptions = options; 46 | return *this; 47 | } 48 | 49 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::host(const QString& host) { 50 | mHost = host; 51 | return *this; 52 | } 53 | 54 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::user(const QString& user) { 55 | mUser = user; 56 | return *this; 57 | } 58 | 59 | ConfigSqlServerBuilder& ConfigSqlServerBuilder::port(int port) { 60 | mPort = port; 61 | return *this; 62 | } 63 | 64 | QSqlDatabase ConfigSqlServerBuilder::getConnection(const QString& connectionName, const QString& databaseName) { 65 | auto db = QSqlDatabase::addDatabase(mDriver, connectionName); 66 | db.setDatabaseName(QString("DRIVER={SQL SERVER};" 67 | "SERVER=%1,%2;" 68 | "DATABASE=%3;" 69 | "UID=%4;" 70 | "PWD=%5;" 71 | ) 72 | .arg(mHost) 73 | .arg(mPort) 74 | .arg(databaseName, mUser, mPassword) 75 | ); 76 | 77 | if (!mOptions.isEmpty()) { 78 | db.setConnectOptions(mOptions); 79 | } 80 | 81 | return db; 82 | } 83 | 84 | void ConfigSqlServerBuilder::initializeDatabase() { 85 | auto config = new ConfigSqlServerBuilder(*this); 86 | ConfigManager::registerConfig(config); 87 | config->setupDatabase(); 88 | } 89 | 90 | QTDAO_END_NAMESPACE 91 | -------------------------------------------------------------------------------- /src/configselector.cpp: -------------------------------------------------------------------------------- 1 | #include "configselector.h" 2 | #include "dbexception.h" 3 | 4 | #include 5 | 6 | QTDAO_BEGIN_NAMESPACE 7 | 8 | typedef QHash> TypeEntityConfig; 9 | 10 | TypeEntityConfig& getEntityConfigs() { 11 | static TypeEntityConfig entityConfigs; 12 | return entityConfigs; 13 | } 14 | 15 | int ConfigSelector::registerConfig(const QString& alias, EntityConfigDelegate *delegate) { 16 | getEntityConfigs().insert(alias, QSharedPointer(delegate)); 17 | return 0; 18 | } 19 | 20 | QSharedPointer ConfigSelector::getConfig(const QString &alias) { 21 | if (!getEntityConfigs().contains(alias)) { 22 | if (alias.isEmpty()) { 23 | throw DaoException("cannot find default config to setup database!"); 24 | } else { 25 | throw DaoException("cannot find config: '" + alias + "' to setup database!"); 26 | } 27 | } 28 | return getEntityConfigs()[alias]; 29 | } 30 | 31 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/dao.version.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define QTDAO_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ 4 | #define QTDAO_VERSION_MINOR @PROJECT_VERSION_MINOR@ 5 | #define QTDAO_VERSION_PATCH @PROJECT_VERSION_PATCH@ -------------------------------------------------------------------------------- /src/qtdao.cpp: -------------------------------------------------------------------------------- 1 | #include "dbexception.h" 2 | #include "dao.h" 3 | 4 | QTDAO_BEGIN_NAMESPACE 5 | 6 | RecursiveQueryBuilder _recursive(bool unionAll, qint64 sessionId) { 7 | auto config = ConfigManager::getConfig(sessionId); 8 | Q_ASSERT_X(!config->isMysql(), "RecursiveQuery", "mysql recursive query unsupported!"); 9 | return RecursiveQueryBuilder(unionAll); 10 | } 11 | 12 | void _truncate(const QString& tbName, qint64 sessionId) { 13 | auto config = ConfigManager::getConfig(sessionId); 14 | config->getClient()->truncateTable(tbName); 15 | } 16 | 17 | void transaction(qint64 sessionId, LoggingCategoryPtr logging) { 18 | auto config = ConfigManager::getConfig(sessionId); 19 | if (config->isSqlServer()) { 20 | BaseQuery::queryPrimitive("begin tran", {}, sessionId, logging); 21 | } else { 22 | BaseQuery::queryPrimitive("begin", {}, sessionId, logging); 23 | } 24 | } 25 | 26 | void commit(qint64 sessionId, LoggingCategoryPtr logging) { 27 | BaseQuery::queryPrimitive("commit", {}, sessionId, logging); 28 | } 29 | 30 | void transaction_save(const QString& savePoint, qint64 sessionId, LoggingCategoryPtr logging) { 31 | auto config = ConfigManager::getConfig(sessionId); 32 | if (config->isSqlServer()) { 33 | BaseQuery::queryPrimitive(QString("save tran %1").arg(savePoint), {}, sessionId, logging); 34 | } else { 35 | BaseQuery::queryPrimitive(QString("savepoint %1").arg(savePoint), {}, sessionId, logging); 36 | } 37 | } 38 | 39 | void rollback(const QString& savePoint, qint64 sessionId, LoggingCategoryPtr logging) { 40 | auto config = ConfigManager::getConfig(sessionId); 41 | if (config->isSqlServer()) { 42 | BaseQuery::queryPrimitive( 43 | savePoint.isEmpty() ? QString("rollback tran") : QString("rollback tran %1").arg(savePoint), 44 | {}, sessionId, logging 45 | ); 46 | } else { 47 | BaseQuery::queryPrimitive( 48 | savePoint.isEmpty() ? QString("rollback") : QString("rollback to %1").arg(savePoint), 49 | {}, sessionId, logging 50 | ); 51 | } 52 | } 53 | 54 | void loggingUseDefault(bool useDefault) { 55 | BaseQuery::useDefaultLoggingIfNull(useDefault); 56 | } 57 | 58 | void _beginSession(qint64 sessionId) { 59 | ConnectionPool::scopeSessionBegin(sessionId); 60 | } 61 | 62 | void _endSession() { 63 | ConnectionPool::scopeSessionEnd(); 64 | } 65 | 66 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/query/deleteimpl.cpp: -------------------------------------------------------------------------------- 1 | #include "query/deleteimpl.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void DeleteImpl::buildDeleteByFilterSqlStatement() { 6 | 7 | QString sql = "delete from "; 8 | sql.append(getTableName()); 9 | 10 | QVariantList value; 11 | auto& fc = filterConnector(); 12 | if (!fc.isEmpty()) { 13 | fc.combine(); 14 | sql.append(" where ").append(fc.getConditionSegment()); 15 | value << fc.getValueList(); 16 | } 17 | setSqlQueryStatement(sql, value); 18 | } 19 | 20 | void DeleteImpl::buildDeleteEntitiesCondition(const std::function& fieldColValuesReader) { 21 | QStringList primaryKeys = getPrimaryKeys(); 22 | Q_ASSERT(!primaryKeys.isEmpty()); 23 | 24 | auto& fc = filterConnector(); 25 | for (const auto& field : primaryKeys) { 26 | auto fieldValue = fieldColValuesReader(field); 27 | auto condition = new OperatorEntityConnector; 28 | condition->setOperator("="); 29 | condition->addField(FieldInfo{ field, getTableName() }); 30 | condition->addValue(fieldValue.size() == 1 ? fieldValue.at(0) : fieldValue); 31 | fc.append(condition->ptr()); 32 | } 33 | } 34 | 35 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/query/insertintoselectimpl.cpp: -------------------------------------------------------------------------------- 1 | #include "query/insertintoselectimpl.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void InsertIntoSelectImpl::buildSqlStatement() { 6 | 7 | QString sql = "insert into "; 8 | sql.append(getTableName()); 9 | 10 | QVariantList values; 11 | 12 | auto& cc = columnConnector(); 13 | if (!cc.isEmpty()) { 14 | cc.combine(); 15 | sql.append(" (").append(cc.getConditionSegment()).append(")"); 16 | values << cc.getValueList(); 17 | } 18 | 19 | auto& fd = fromBuildData(); 20 | sql.append(" ").append(fd.statement); 21 | values << fd.values; 22 | 23 | setSqlQueryStatement(sql, values); 24 | } 25 | 26 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/query/updateimpl.cpp: -------------------------------------------------------------------------------- 1 | #include "query/updateimpl.h" 2 | 3 | QTDAO_BEGIN_NAMESPACE 4 | 5 | void UpdateImpl::buildUpdateBySetSqlStatement() { 6 | QString sql = "update "; 7 | sql.append(getTableName()); 8 | 9 | QVariantList value; 10 | 11 | auto& sc = setConnector(); 12 | sc.combine(); 13 | Q_ASSERT(!sc.getConditionSegment().isEmpty()); 14 | sql.append(" set "); 15 | sql.append(sc.getConditionSegment()); 16 | value << sc.getValueList(); 17 | 18 | auto& fc = filterConnector(); 19 | if (!fc.isEmpty()) { 20 | fc.combine(); 21 | sql.append(" where ").append(fc.getConditionSegment()); 22 | value << fc.getValueList(); 23 | } 24 | setSqlQueryStatement(sql, value); 25 | } 26 | 27 | void UpdateImpl::bindUpdateEntitiesCondition(const std::function &fieldColValuesReader) { 28 | auto& sc = setConnector(); 29 | auto& fc = filterConnector(); 30 | Q_ASSERT(sc.isEmpty()); 31 | Q_ASSERT(fc.isEmpty()); 32 | 33 | QStringList primaryKeys = getPrimaryKeys(); 34 | Q_ASSERT(!primaryKeys.isEmpty()); 35 | 36 | QStringList fields = getFields(); 37 | for (const auto& field : fields) { 38 | auto fieldValue = fieldColValuesReader(field); 39 | 40 | auto condition = new OperatorEntityConnector; 41 | condition->setOperator("="); 42 | condition->addField(FieldInfo{ field, getTableName() }); 43 | condition->addValue(fieldValue.size() == 1 ? fieldValue.at(0) : fieldValue); 44 | 45 | if (primaryKeys.contains(field)) { 46 | fc.append(condition->ptr()); 47 | } else { 48 | sc.append(condition->ptr()); 49 | } 50 | } 51 | } 52 | 53 | QTDAO_END_NAMESPACE 54 | -------------------------------------------------------------------------------- /src/utils/dbupgrader.cpp: -------------------------------------------------------------------------------- 1 | #include "utils/dbupgrader.h" 2 | 3 | #include "dao.h" 4 | 5 | #include "config/configbuilder.h" 6 | 7 | QTDAO_BEGIN_NAMESPACE 8 | 9 | DatabaseUpgrader::DatabaseUpgrader() 10 | : entityReader(nullptr) 11 | { 12 | 13 | } 14 | 15 | void DatabaseUpgrader::setEntityReader(EntityReaderInterface *reader) { 16 | entityReader = reader; 17 | } 18 | 19 | void DatabaseUpgrader::setCurClient(dao::AbstractClient *curClient) { 20 | client = curClient; 21 | } 22 | 23 | void DatabaseUpgrader::setCurConfig(dao::ConfigBuilder *curConfig) { 24 | config = curConfig; 25 | } 26 | 27 | void DatabaseUpgrader::onUpgrade(int oldVersion, int curVersion) { 28 | //default upgrade strategy 29 | client->enableForeignKey(QString(), false); 30 | upgradeWithDataRecovery(); 31 | client->enableForeignKey(QString(), true); 32 | } 33 | 34 | void DatabaseUpgrader::upgradeWithDataRecovery() { 35 | QString tmpTableName = "tmp_" + client->removeEscapeCharsForName(entityReader->getTableName()); 36 | 37 | dao::transaction(); 38 | try { 39 | //drop the child foreign key referencing this table, they will be recreated in the future 40 | client->dropReferencedForeignKey(entityReader->getTableName()); 41 | //drop tmp table if exist 42 | client->dropTable(tmpTableName); 43 | //create a tmp table 44 | client->createTableIfNotExist(tmpTableName, 45 | entityReader->getFieldsType(), 46 | entityReader->getPrimaryKeys(), 47 | entityReader->getForeignKeys(), 48 | entityReader->getTableEngine()); 49 | //drop old table all index 50 | client->dropAllIndexOnTable(entityReader->getTableName()); 51 | //create index for new table 52 | auto proxyReader = new TableProxyEntityReader(tmpTableName, entityReader); 53 | client->createIndex(proxyReader); 54 | delete proxyReader; 55 | //copy data 56 | client->transferData(entityReader->getTableName(), tmpTableName); 57 | //remove old table 58 | client->dropTable(entityReader->getTableName()); 59 | //rename tmp table into target table 60 | client->renameTable(tmpTableName, entityReader->getTableName()); 61 | 62 | dao::commit(); 63 | } catch (DaoException& e) { 64 | dao::rollback(); 65 | throw e; 66 | } 67 | } 68 | 69 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /src/versionctl/versioncontrol.cpp: -------------------------------------------------------------------------------- 1 | #include "versionctl/versioncontrol.h" 2 | #include "versionctl/version.h" 3 | 4 | #include "config/configbuilder.h" 5 | #include "config/configmanager.h" 6 | 7 | #include "dbexception.h" 8 | #include "dao.h" 9 | 10 | QTDAO_BEGIN_NAMESPACE 11 | 12 | void VersionControl::checkLocalVersion(qint64 sessionId) { 13 | 14 | auto config = ConfigManager::getConfig(sessionId); 15 | auto versionTbReader = new SqliteEntityReaderProvider; //same suitable for mysql/sqlserver 16 | config->dbClient->createTableIfNotExist(versionTbReader); 17 | delete versionTbReader; 18 | 19 | int localVersion = getLocalVersion(sessionId); 20 | if (localVersion > config->mVersion) { 21 | throw DaoException("The config version is smaller than the local version!"); 22 | } 23 | 24 | if (localVersion == config->mVersion) { 25 | return; 26 | } 27 | 28 | invokeCreateTables(sessionId); 29 | if (localVersion != -1) { 30 | invokeTableUpgrade(localVersion, config->mVersion, sessionId); 31 | } 32 | updateLocalVersion(sessionId); 33 | } 34 | 35 | int VersionControl::getLocalVersion(qint64 sessionId) { 36 | auto d = dao::_select(sessionId).build().one(); 37 | return d.getVer(); 38 | } 39 | 40 | void VersionControl::updateLocalVersion(qint64 sessionId) { 41 | 42 | dao::_delete(sessionId).build().deleteBy(); 43 | 44 | auto config = ConfigManager::getConfig(sessionId); 45 | auto v = Version(config->mVersion); 46 | dao::_insert(sessionId).build().insert(v); 47 | } 48 | 49 | QString getAliasKeyPrefix(ConfigType configType) { 50 | switch (configType) { 51 | case ConfigType::Sqlite: 52 | return "sqlite_"; 53 | case ConfigType::Mysql: 54 | return "mysql_"; 55 | case ConfigType::SqlServer: 56 | return "sqlserver_"; 57 | case ConfigType::PSql: 58 | return "psql_"; 59 | } 60 | return {}; 61 | } 62 | 63 | void VersionControl::invokeCreateTables(qint64 sessionId) { 64 | auto config = ConfigManager::getConfig(sessionId); 65 | ConfigSelector::getConfig(getAliasKeyPrefix(config->configType) + config->mAlias)->createEntityTables(config.data()); 66 | } 67 | 68 | void VersionControl::invokeTableUpgrade(int oldVer, int newVer, qint64 sessionId) { 69 | auto config = ConfigManager::getConfig(sessionId); 70 | ConfigSelector::getConfig(getAliasKeyPrefix(config->configType) + config->mAlias)->entityTablesUpgrade(config.data(), oldVer, newVer); 71 | } 72 | 73 | QTDAO_END_NAMESPACE -------------------------------------------------------------------------------- /test/acommontestutil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(common-test-util) 2 | 3 | set(CMAKE_AUTOMOC ON) 4 | 5 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 6 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Test REQUIRED) 7 | 8 | add_compile_definitions(TEST_CONFIG_PATH="${CMAKE_CURRENT_SOURCE_DIR}/test-config.json") 9 | 10 | if (WIN32) 11 | add_definitions(-DUNICODE) 12 | add_definitions(-D_UNICODE) 13 | endif() 14 | 15 | add_library(${PROJECT_NAME} 16 | multitestrunner.h 17 | 18 | utils/testutils.h 19 | utils/testutils.cpp 20 | utils/testconfigloader.h 21 | utils/testconfigloader.cpp 22 | ) 23 | 24 | target_link_libraries(${PROJECT_NAME} 25 | Qt${QT_VERSION_MAJOR}::Core 26 | Qt${QT_VERSION_MAJOR}::Test 27 | 28 | libpq 29 | ) 30 | 31 | target_link_directories(${PROJECT_NAME} PUBLIC ${PSQL_DRIVER_DIR}) 32 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 33 | -------------------------------------------------------------------------------- /test/acommontestutil/multitestrunner.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utils/testutils.h" 6 | 7 | #include 8 | 9 | template struct MultiTestRunner; 10 | template 11 | struct MultiTestRunner : MultiTestRunner { 12 | 13 | template 14 | static int run(const QString& target, Params... params) { 15 | T t(params...); 16 | int result; 17 | try { 18 | result = QTest::qExec(&t, QStringList() << target << "-o" << "test.txt"); 19 | TestUtils::printTestLog("test.txt"); 20 | } catch (dao::DaoException& e) { 21 | Q_UNUSED(e) 22 | auto validDrivers = QSqlDatabase::drivers(); 23 | Q_UNUSED(validDrivers) 24 | qFatal("run testcase fail!"); 25 | } 26 | 27 | result += MultiTestRunner::run(target, params...); 28 | return result; 29 | } 30 | }; 31 | 32 | template<> struct MultiTestRunner<> { 33 | 34 | template 35 | static int run(const QString&, Params...) { return 0; } 36 | }; -------------------------------------------------------------------------------- /test/acommontestutil/test-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "printTarget": "std", 3 | "systemCodePage": true, 4 | "targetDb": "psql", 5 | "optionSqlite": { 6 | "version": 1, 7 | "options": "QSQLITE_BUSY_TIMEOUT=100", 8 | "saveDir": "current" 9 | }, 10 | "optionMysql": { 11 | "version": 1, 12 | "host": "localhost", 13 | "port": 3306, 14 | "user": "root", 15 | "password": "root", 16 | "options": "MYSQL_OPT_CONNECT_TIMEOUT=3;MYSQL_OPT_READ_TIMEOUT=3;MYSQL_OPT_WRITE_TIMEOUT=3" 17 | }, 18 | "optionSqlServer": { 19 | "version": 1, 20 | "host": "localhost", 21 | "user": "sa", 22 | "password": "12345678Root+" 23 | }, 24 | "optionPSql": { 25 | "version": 1, 26 | "host": "localhost", 27 | "port": 5432, 28 | "user": "postgres", 29 | "password": "root" 30 | } 31 | } -------------------------------------------------------------------------------- /test/acommontestutil/utils/testconfigloader.cpp: -------------------------------------------------------------------------------- 1 | #include "testconfigloader.h" 2 | 3 | #include 4 | 5 | TestConfigLoader &TestConfigLoader::instance() { 6 | static TestConfigLoader configLoader; 7 | return configLoader; 8 | } 9 | 10 | TestConfigLoader::TestConfigLoader() { 11 | QFile file(TEST_CONFIG_PATH); 12 | if (!file.open(QIODevice::ReadOnly)) { 13 | return; 14 | } 15 | auto data = file.readAll(); 16 | file.close(); 17 | 18 | auto doc = QJsonDocument::fromJson(data); 19 | if (doc.isNull()) { 20 | return; 21 | } 22 | 23 | configData.fromJson(doc.object()); 24 | } 25 | -------------------------------------------------------------------------------- /test/acommontestutil/utils/testconfigloader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "datakey.h" 6 | 7 | using namespace QDataUtil; 8 | 9 | enum class PrintOutputTarget { 10 | Target_Std, 11 | Target_Debug_Console, 12 | }; 13 | 14 | enum class TestTargetDb { 15 | Target_Sqlite, 16 | Target_Mysql, 17 | Target_SqlServer, 18 | Target_PSql, 19 | }; 20 | 21 | struct TestOptionCommon : DataDumpInterface { 22 | DATA_KEY(int, version); 23 | DATA_KEY(QString, driver); 24 | DATA_KEY(QString, password); 25 | DATA_KEY(QString, options); 26 | }; 27 | 28 | struct TestOptionSqlite : TestOptionCommon { 29 | DATA_KEY(QString, saveDir); 30 | 31 | QList prop() override { 32 | return { &version, &driver, &password, &options, 33 | &saveDir 34 | }; 35 | } 36 | }; 37 | 38 | struct TestOptionMySql : TestOptionCommon { 39 | DATA_KEY(QString, host); 40 | DATA_KEY(QString, user); 41 | DATA_KEY(int, port); 42 | 43 | QList prop() override { 44 | return { &version, &driver, &password, &options, 45 | &host, &user, &port 46 | }; 47 | } 48 | }; 49 | 50 | struct TestOptionSqlServer : TestOptionMySql { 51 | 52 | }; 53 | 54 | struct TestOptionPSql : TestOptionMySql { 55 | DATA_KEY(QString, host); 56 | DATA_KEY(QString, user); 57 | DATA_KEY(int, port); 58 | 59 | QList prop() override { 60 | return {&version, &driver, &password, &options, 61 | &host, &user, &port 62 | }; 63 | } 64 | }; 65 | 66 | struct TestConfigData : DataDumpInterface { 67 | 68 | DATA_KEY(QString, printTaget); 69 | DATA_KEY(bool, systemCodePage); 70 | 71 | DATA_KEY(QString, targetDb); 72 | 73 | DATA_KEY(TestOptionSqlite, optionSqlite); 74 | DATA_KEY(TestOptionMySql, optionMysql); 75 | DATA_KEY(TestOptionSqlServer, optionSqlServer); 76 | DATA_KEY(TestOptionPSql, optionPSql); 77 | 78 | PrintOutputTarget getOutputTarget() const { 79 | if (printTaget() == "debugConsole") { 80 | return PrintOutputTarget::Target_Debug_Console; 81 | } 82 | return PrintOutputTarget::Target_Std; 83 | } 84 | 85 | TestTargetDb getTestTargetDb() const { 86 | auto configStr = targetDb().toLower(); 87 | if (configStr == "mysql") { 88 | return TestTargetDb::Target_Mysql; 89 | } 90 | if (configStr == "sqlserver") { 91 | return TestTargetDb::Target_SqlServer; 92 | } 93 | if (configStr == "psql") { 94 | return TestTargetDb::Target_PSql; 95 | } 96 | return TestTargetDb::Target_Sqlite; 97 | } 98 | 99 | QList prop() override { 100 | return { &printTaget, &systemCodePage, &targetDb, 101 | &optionSqlite, &optionMysql, &optionSqlServer, &optionPSql 102 | }; 103 | } 104 | }; 105 | 106 | class TestConfigLoader { 107 | public: 108 | static TestConfigLoader& instance(); 109 | 110 | const TestConfigData& config() const { 111 | return configData; 112 | } 113 | 114 | private: 115 | TestConfigLoader(); 116 | 117 | private: 118 | TestConfigData configData; 119 | }; 120 | -------------------------------------------------------------------------------- /test/acommontestutil/utils/testutils.cpp: -------------------------------------------------------------------------------- 1 | #include "testutils.h" 2 | 3 | #include 4 | #include 5 | 6 | #ifdef Q_OS_WIN 7 | #include 8 | #endif 9 | 10 | #include "testconfigloader.h" 11 | 12 | void TestUtils::printTestLog(const QString &filePath) { 13 | QFile file(filePath); 14 | Q_ASSERT(file.open(QIODevice::ReadOnly)); 15 | while (true) { 16 | auto line = file.readLine(); 17 | if (line.isEmpty()) break; 18 | if (line.startsWith("PASS")) { 19 | printWithColor(line, TestOutputColorAttr::Green, false); 20 | } else if (line.startsWith("FAIL")) { 21 | printWithColor(line, TestOutputColorAttr::Red, false); 22 | } else if (line.startsWith("Totals")) { 23 | printWithColor(line, TestOutputColorAttr::Yellow, false); 24 | } else if (line.startsWith("*********")) { 25 | printWithColor(line, TestOutputColorAttr::White, false); 26 | } else if (line.startsWith("QWARN")) { 27 | printWithColor(line, TestOutputColorAttr::Yellow, false); 28 | } else if (line.startsWith("QDEBUG")) { 29 | printWithColor(line, TestOutputColorAttr::Blue, false); 30 | } else { 31 | printWithColor(line, TestOutputColorAttr::Unset, false); 32 | } 33 | } 34 | printWithColor(QString(), TestOutputColorAttr::Unset); 35 | file.close(); 36 | } 37 | 38 | //linux console color attribute 39 | enum class StdColorAttr { 40 | LR = 31, 41 | LG = 32, 42 | LY = 33, 43 | LB = 34, 44 | LP = 35, 45 | LC = 36, 46 | LW = 37, 47 | 48 | //background 49 | LBK = 10, // x += LBK 50 | 51 | //lighter 52 | LL = 60, // x += LL 53 | 54 | //underline 55 | LU = 4, 56 | 57 | //blink 58 | LBlink = 5, 59 | }; 60 | 61 | void TestUtils::printWithColor(const QString &data, TestOutputColorAttr colorStyle, bool end) { 62 | 63 | const auto& wrapLog = [&] { 64 | if (colorStyle == TestOutputColorAttr::Unset) { 65 | return data; 66 | } 67 | QString styled = "\033["; 68 | int v = 30 + (int)colorStyle + (int)StdColorAttr::LL; 69 | styled += QString::number(v) + "m"; 70 | return styled + data + "\033[0m"; 71 | }; 72 | 73 | auto wrapped = wrapLog(); 74 | const auto& printTarget = TestConfigLoader::instance().config().getOutputTarget(); 75 | switch (printTarget) { 76 | case PrintOutputTarget::Target_Std: { 77 | if (TestConfigLoader::instance().config().systemCodePage()) { 78 | std::cout << wrapped.toLocal8Bit().data(); 79 | } else { 80 | std::cout << wrapped.toStdString(); 81 | } 82 | if (end) { 83 | std::cout << std::endl; 84 | } 85 | } 86 | break; 87 | case PrintOutputTarget::Target_Debug_Console: { 88 | #ifdef Q_OS_WIN 89 | OutputDebugString(reinterpret_cast(wrapped.utf16())); 90 | if (end) { 91 | OutputDebugString(L"\n"); 92 | } 93 | #endif 94 | } 95 | break; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /test/acommontestutil/utils/testutils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum class TestOutputColorAttr { 6 | Unset = 0, 7 | Red, 8 | Green, 9 | Yellow, 10 | Blue, 11 | Purple, 12 | Cyan, 13 | White, 14 | }; 15 | 16 | class TestUtils { 17 | public: 18 | static void printTestLog(const QString& filePath); 19 | 20 | static void printWithColor(const QString& data, TestOutputColorAttr colorStyle = TestOutputColorAttr::Unset, bool end = true); 21 | }; 22 | -------------------------------------------------------------------------------- /test/clienttest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaoclienttest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlite/entity.cmake) 12 | include(${CMAKE_CURRENT_SOURCE_DIR}/mysql/entity.cmake) 13 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlserver/entity.cmake) 14 | include(${CMAKE_CURRENT_SOURCE_DIR}/psql/entity.cmake) 15 | 16 | add_executable(${PROJECT_NAME} 17 | main.cpp 18 | ${ENTITY_FILE_LIST} 19 | 20 | clientsqlitetest.h 21 | clientsqlitetest.cpp 22 | clientmysqltest.h 23 | clientmysqltest.cpp 24 | clientsqlservertest.h 25 | clientsqlservertest.cpp 26 | clientpsqltest.h 27 | clientpsqltest.cpp 28 | ) 29 | 30 | target_link_libraries(${PROJECT_NAME} 31 | Qt${QT_VERSION_MAJOR}::Core 32 | Qt${QT_VERSION_MAJOR}::Sql 33 | Qt${QT_VERSION_MAJOR}::Test 34 | 35 | qtdao 36 | common-test-util 37 | ) -------------------------------------------------------------------------------- /test/clienttest/clientmysqltest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dao { 7 | class AbstractClient; 8 | } 9 | 10 | class ClientMysqlTest : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | using QObject::QObject; 15 | 16 | private slots: 17 | void initTestCase(); 18 | 19 | void databaseProcessTest(); 20 | 21 | void tableProcessTest(); 22 | 23 | void indexProcessTest(); 24 | 25 | void fieldProcessTest(); 26 | 27 | void dataTransTest(); 28 | 29 | void cleanup(); 30 | 31 | void cleanupTestCase(); 32 | 33 | private: 34 | QSharedPointer client; 35 | }; 36 | -------------------------------------------------------------------------------- /test/clienttest/clientpsqltest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dao { 7 | class AbstractClient; 8 | } 9 | 10 | class ClientPSqlTest : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | using QObject::QObject; 15 | 16 | private slots: 17 | void initTestCase(); 18 | 19 | void databaseProcessTest(); 20 | 21 | void tableProcessTest(); 22 | 23 | void indexProcessTest(); 24 | 25 | void fieldProcessTest(); 26 | 27 | void dataTransTest(); 28 | 29 | void cleanup(); 30 | 31 | void cleanupTestCase(); 32 | 33 | private: 34 | QSharedPointer client; 35 | }; 36 | -------------------------------------------------------------------------------- /test/clienttest/clientsqlitetest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dao { 7 | class AbstractClient; 8 | } 9 | 10 | class ClientSqliteTest : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | using QObject::QObject; 15 | 16 | private slots: 17 | void initTestCase(); 18 | 19 | void databaseProcessTest(); 20 | 21 | void tableProcessTest(); 22 | 23 | void indexProcessTest(); 24 | 25 | void fieldProcessTest(); 26 | 27 | void dataTransTest(); 28 | 29 | void cleanup(); 30 | 31 | void cleanupTestCase(); 32 | 33 | private: 34 | QSharedPointer client; 35 | }; 36 | -------------------------------------------------------------------------------- /test/clienttest/clientsqlservertest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace dao { 7 | class AbstractClient; 8 | } 9 | 10 | class ClientSqlServerTest : public QObject { 11 | Q_OBJECT 12 | 13 | public: 14 | using QObject::QObject; 15 | 16 | private slots: 17 | void initTestCase(); 18 | 19 | void databaseProcessTest(); 20 | 21 | void tableProcessTest(); 22 | 23 | void indexProcessTest(); 24 | 25 | void fieldProcessTest(); 26 | 27 | void dataTransTest(); 28 | 29 | void cleanup(); 30 | 31 | void cleanupTestCase(); 32 | 33 | private: 34 | QSharedPointer client; 35 | }; 36 | -------------------------------------------------------------------------------- /test/clienttest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "clientsqlitetest.h" 4 | #include "clientmysqltest.h" 5 | #include "clientsqlservertest.h" 6 | #include "clientpsqltest.h" 7 | 8 | #include "utils/testconfigloader.h" 9 | #include "multitestrunner.h" 10 | 11 | int main(int argc, char** argv) { 12 | QCoreApplication a(argc, argv); 13 | 14 | int result = 0; 15 | auto testDbType = TestConfigLoader::instance().config().getTestTargetDb(); 16 | switch (testDbType) { 17 | case TestTargetDb::Target_Sqlite: 18 | TestUtils::printWithColor("------------------------------ Test Sqlite ------------------------------", TestOutputColorAttr::Yellow); 19 | result = MultiTestRunner::run("qtdaoclienttest.exe"); 20 | break; 21 | case TestTargetDb::Target_Mysql: 22 | TestUtils::printWithColor("------------------------------ Test Mysql ------------------------------", TestOutputColorAttr::Yellow); 23 | result = MultiTestRunner::run("qtdaoclienttest.exe"); 24 | break; 25 | case TestTargetDb::Target_SqlServer: 26 | TestUtils::printWithColor("------------------------------ Test SqlServer ------------------------------", TestOutputColorAttr::Yellow); 27 | result = MultiTestRunner::run("qtdaoclienttest.exe"); 28 | break; 29 | case TestTargetDb::Target_PSql: 30 | TestUtils::printWithColor("------------------------------ Test PSql ------------------------------", TestOutputColorAttr::Yellow); 31 | result = MultiTestRunner::run("qtdaoclienttest.exe"); 32 | break; 33 | } 34 | 35 | if (result != 0) { 36 | TestUtils::printWithColor("Not all tests are successful!", TestOutputColorAttr::Yellow); 37 | } else { 38 | TestUtils::printWithColor("All tests passed!", TestOutputColorAttr::Green); 39 | } 40 | return result; 41 | } -------------------------------------------------------------------------------- /test/clienttest/mysql/mysql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | field2 11 | 12 | 13 | field3 14 | field4 15 | 16 | 17 | field2 18 | field4 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | field3 28 | field4 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/clienttest/psql/psql_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | field2 11 | 12 | 13 | field3 14 | field4 15 | 16 | 17 | field2 18 | field4 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | field3 28 | field4 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/clienttest/sqlite/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | field2 12 | 13 | 14 | field3 15 | field4 16 | 17 | 18 | field2 19 | field6 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | field3 29 | field4 30 | 31 | 32 | -------------------------------------------------------------------------------- /test/clienttest/sqlserver/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | field2 11 | 12 | 13 | field3 14 | field4 15 | 16 | 17 | field2 18 | field4 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | field3 28 | field4 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/corelibtest/BaseTest.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseTest.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef Q_CC_MSVC 8 | #include 9 | #endif 10 | 11 | QList> BaseTest::cachedSqlLog; 12 | 13 | void SqlLogPrinter(const QString& sql, const QVariantList& values) { 14 | BaseTest::cachedSqlLog << qMakePair(sql, values); 15 | } 16 | 17 | BaseTest::BaseTest(TestTargetDb targetDb) : DatabaseSelector(targetDb) { 18 | cachedSqlLog.clear(); 19 | } 20 | 21 | void BaseTest::clearCacheAndPrintIfTestFail() { 22 | if (QTest::currentTestFailed()) { 23 | #ifdef Q_CC_MSVC 24 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED); 25 | #endif 26 | for (const auto& log : cachedSqlLog) { 27 | std::cout << "----TEST FAIL SQL: " << log.first.toStdString() << std::endl; 28 | QString values; 29 | QDebug(&values) << log.second; 30 | std::cout << "----TEST FAIL VALUES: " << values.toStdString() << std::endl; 31 | } 32 | #ifdef Q_CC_MSVC 33 | SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); 34 | #endif 35 | } 36 | cachedSqlLog.clear(); 37 | } 38 | 39 | void BaseTest::clearCache() { 40 | cachedSqlLog.clear(); 41 | } 42 | -------------------------------------------------------------------------------- /test/corelibtest/BaseTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | QTDAO_USING_NAMESPACE 8 | 9 | class BaseTest : public QObject , public DatabaseSelector { 10 | public: 11 | explicit BaseTest(TestTargetDb targetDb); 12 | 13 | private: 14 | static QList> cachedSqlLog; 15 | 16 | friend void SqlLogPrinter(const QString& sql, const QVariantList& values); 17 | 18 | protected: 19 | void clearCacheAndPrintIfTestFail(); 20 | void clearCache(); 21 | 22 | void configDb() { 23 | setupDatabase("corelib_test"); 24 | clearCacheAndPrintIfTestFail(); 25 | } 26 | }; -------------------------------------------------------------------------------- /test/corelibtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaocoretest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | file(GLOB OTHER_TEST other/*.h other/*.cpp) 12 | file(GLOB QUERY_TEST query/*.h query/*.cpp) 13 | file(GLOB ENTITY_SQLITE entity/sqliteentity/*.h entity/sqliteentity/*.cpp) 14 | file(GLOB ENTITY_MYSQL entity/mysqlentity/*.h entity/mysqlentity/*.cpp) 15 | file(GLOB ENTITY_SQLSERVER entity/sqlserverentity/*.h entity/sqlserverentity/*.cpp) 16 | file(GLOB ENTITY_PSQL entity/psqlentity/*.h entity/psqlentity/*.cpp) 17 | 18 | add_executable(${PROJECT_NAME} 19 | BaseTest.h 20 | BaseTest.cpp 21 | ../acommontestutil/databaseselector.h 22 | main.cpp 23 | 24 | ${OTHER_TEST} 25 | ${QUERY_TEST} 26 | ${ENTITY_SQLITE} 27 | ${ENTITY_MYSQL} 28 | ${ENTITY_SQLSERVER} 29 | ${ENTITY_PSQL} 30 | ) 31 | 32 | target_link_libraries(${PROJECT_NAME} 33 | Qt${QT_VERSION_MAJOR}::Core 34 | Qt${QT_VERSION_MAJOR}::Sql 35 | Qt${QT_VERSION_MAJOR}::Test 36 | 37 | qtdao 38 | common-test-util 39 | ) -------------------------------------------------------------------------------- /test/corelibtest/entity/sqliteentity/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | name 18 | number 19 | 20 | 21 | number2 22 | 23 | 24 | number 25 | number2 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /test/corelibtest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "other/ConnectionPoolTest.h" 4 | #include "other/ConnectorTest.h" 5 | #include "other/DbLoaderTest.h" 6 | #include "query/BaseQueryTest.h" 7 | #include "query/DeleteTest.h" 8 | #include "query/InsertIntoSelectTest.h" 9 | #include "query/InsertTest.h" 10 | #include "query/JoinTest.h" 11 | #include "query/LoggingTest.h" 12 | #include "query/SelectTest.h" 13 | #include "query/UpdateTest.h" 14 | #include "query/UpsertTest.h" 15 | 16 | #include "multitestrunner.h" 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | QCoreApplication a(argc, argv); 21 | 22 | auto testDbType = TestConfigLoader::instance().config().getTestTargetDb(); 23 | switch (testDbType) { 24 | case TestTargetDb::Target_Sqlite: 25 | TestUtils::printWithColor("------------------------------ Test Sqlite ------------------------------", TestOutputColorAttr::Yellow); 26 | break; 27 | case TestTargetDb::Target_Mysql: 28 | TestUtils::printWithColor("------------------------------ Test Mysql ------------------------------", TestOutputColorAttr::Yellow); 29 | break; 30 | case TestTargetDb::Target_SqlServer: 31 | TestUtils::printWithColor("------------------------------ Test SqlServer ------------------------------", TestOutputColorAttr::Yellow); 32 | break; 33 | case TestTargetDb::Target_PSql: 34 | TestUtils::printWithColor("------------------------------ Test PSql ------------------------------", TestOutputColorAttr::Yellow); 35 | break; 36 | } 37 | 38 | int result = MultiTestRunner< 39 | DbLoaderTest, 40 | ConnectionPoolTest, 41 | BaseQueryTest, 42 | ConnectorTest, 43 | InsertTest, 44 | SelectTest, 45 | UpdateTest, 46 | DeleteTest, 47 | JoinTest, 48 | InsertIntoSelectTest, 49 | LoggingTest, 50 | UpsertTest 51 | >::run("qtdaocoretest.exe", testDbType); 52 | 53 | if (result != 0) { 54 | TestUtils::printWithColor("Not all tests are successful!", TestOutputColorAttr::Yellow); 55 | } else { 56 | TestUtils::printWithColor("All tests passed!", TestOutputColorAttr::Green); 57 | } 58 | return result; 59 | } 60 | -------------------------------------------------------------------------------- /test/corelibtest/other/ConnectionPoolTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | class ConnectionPoolTest : public QObject, public DatabaseSelector { 8 | Q_OBJECT 9 | 10 | public: 11 | using DatabaseSelector::DatabaseSelector; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void testConnect(); 17 | void testReuseConnection(); 18 | void testSerialThread(); 19 | void testParallelThread(); 20 | void testSerialThreadPool(); 21 | void testParallelThreadPool(); 22 | 23 | void testGoneAway(); 24 | 25 | void cleanup(); 26 | 27 | void cleanupTestCase(); 28 | }; 29 | -------------------------------------------------------------------------------- /test/corelibtest/other/ConnectorTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | class ConnectorTest : public QObject, public DatabaseSelector { 8 | Q_OBJECT 9 | 10 | public: 11 | using DatabaseSelector::DatabaseSelector; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void cleanup(); 17 | 18 | void conditionConnectortest(); 19 | void constraintConditionTest(); 20 | void functionConnectorTest(); 21 | void havingStatementTest(); 22 | 23 | void cleanupTestCase(); 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /test/corelibtest/other/DbLoaderTest.cpp: -------------------------------------------------------------------------------- 1 | #include "DbLoaderTest.h" 2 | 3 | #include "connectionpool.h" 4 | 5 | #include "entity/sqliteentity/sqlitetest1.h" 6 | #include "entity/sqliteentity/sqlitetest2.h" 7 | 8 | #include "entity/mysqlentity/mysqltest1.h" 9 | #include "entity/mysqlentity/mysqltest2.h" 10 | 11 | #include "entity/sqlserverentity/sqlservertest1.h" 12 | #include "entity/sqlserverentity/sqlservertest2.h" 13 | 14 | #include "entity/psqlentity/psqltest1.h" 15 | #include "entity/psqlentity/psqltest2.h" 16 | 17 | #include 18 | 19 | QTDAO_USING_NAMESPACE 20 | 21 | void DbLoaderTest::initTestCase() { 22 | 23 | } 24 | 25 | void DbLoaderTest::loadConfigTest() { 26 | setupDatabase("corelib_test"); 27 | auto config = ConfigManager::getConfig(); 28 | if (targetDb == TestTargetDb::Target_Sqlite) { 29 | QVERIFY(config->getClient()->checkTableExist(SqliteTest1::Info::getTableName())); 30 | QVERIFY(config->getClient()->checkTableExist(SqliteTest2::Info::getTableName())); 31 | } else if (targetDb == TestTargetDb::Target_Mysql) { 32 | QVERIFY(config->getClient()->checkTableExist(MysqlTest1::Info::getTableName())); 33 | QVERIFY(config->getClient()->checkTableExist(MysqlTest2::Info::getTableName())); 34 | } else if (targetDb == TestTargetDb::Target_SqlServer) { 35 | QVERIFY(config->getClient()->checkTableExist(SqlServerTest1::Info::getTableName())); 36 | QVERIFY(config->getClient()->checkTableExist(SqlServerTest2::Info::getTableName())); 37 | } else if (targetDb == TestTargetDb::Target_PSql) { 38 | QVERIFY(config->getClient()->checkTableExist(PSqlTest1::Info::getTableName())); 39 | QVERIFY(config->getClient()->checkTableExist(PSqlTest2::Info::getTableName())); 40 | } 41 | QCOMPARE(config->getLocalVersion(), 1); 42 | } 43 | 44 | void DbLoaderTest::upgradeTest() { 45 | //reinit 46 | setupDatabase("corelib_test", 3); 47 | auto config = ConfigManager::getConfig(); 48 | if (targetDb == TestTargetDb::Target_Sqlite) { 49 | QVERIFY(config->getClient()->checkTableExist(SqliteTest1::Info::getTableName())); 50 | QVERIFY(config->getClient()->checkTableExist(SqliteTest2::Info::getTableName())); 51 | } else if (targetDb == TestTargetDb::Target_Mysql) { 52 | QVERIFY(config->getClient()->checkTableExist(MysqlTest1::Info::getTableName())); 53 | QVERIFY(config->getClient()->checkTableExist(MysqlTest2::Info::getTableName())); 54 | } else if (targetDb == TestTargetDb::Target_SqlServer) { 55 | QVERIFY(config->getClient()->checkTableExist(SqlServerTest1::Info::getTableName())); 56 | QVERIFY(config->getClient()->checkTableExist(SqlServerTest2::Info::getTableName())); 57 | } else if (targetDb == TestTargetDb::Target_PSql) { 58 | QVERIFY(config->getClient()->checkTableExist(PSqlTest1::Info::getTableName())); 59 | QVERIFY(config->getClient()->checkTableExist(PSqlTest2::Info::getTableName())); 60 | } 61 | //test version 62 | QCOMPARE(config->getLocalVersion(), 3); 63 | } 64 | 65 | void DbLoaderTest::cleanup() { 66 | 67 | } 68 | 69 | void DbLoaderTest::cleanupTestCase() { 70 | ConfigManager::getConfig()->getClient()->dropDatabase(); 71 | } 72 | -------------------------------------------------------------------------------- /test/corelibtest/other/DbLoaderTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | class DbLoaderTest : public QObject, public DatabaseSelector { 8 | Q_OBJECT 9 | 10 | public: 11 | using DatabaseSelector::DatabaseSelector; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void loadConfigTest(); 17 | void upgradeTest(); 18 | 19 | void cleanup(); 20 | 21 | void cleanupTestCase(); 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /test/corelibtest/query/BaseQueryTest.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseQueryTest.h" 2 | 3 | #include "connectionpool.h" 4 | #include "dbexception.h" 5 | 6 | #include 7 | 8 | void BaseQueryTest::initTestCase() { 9 | configDb(); 10 | ConfigManager::getConfig()->getClient()->testConnect(); 11 | } 12 | 13 | void BaseQueryTest::testPrimitiveQuery() { 14 | try { 15 | auto query = BaseQuery::queryPrimitive("select 10 + 20"); 16 | if (query.next()) { 17 | int result = query.value(0).toInt(); 18 | QCOMPARE(result, 30); 19 | } else { 20 | QFAIL("primitive query fail!"); 21 | } 22 | } 23 | catch (DaoException& e) { 24 | QFAIL(e.reason.toLatin1()); 25 | } 26 | } 27 | 28 | void BaseQueryTest::testPrimitiveQueryWithValue() { 29 | try { 30 | auto query = BaseQuery::queryPrimitive([&] () -> QString { 31 | if (targetDb == TestTargetDb::Target_PSql) { 32 | return "select ?::integer + ?::integer"; 33 | } 34 | return "select ? + ?"; 35 | } (), QVariantList() << 10 << 20); 36 | if (query.next()) { 37 | int result = query.value(0).toInt(); 38 | QCOMPARE(result, 30); 39 | } else { 40 | QFAIL("primitive query fail!"); 41 | } 42 | } 43 | catch (DaoException& e) { 44 | QFAIL(e.reason.toLatin1()); 45 | } 46 | } 47 | 48 | void BaseQueryTest::testPrimitiveQueryFail() { 49 | try { 50 | BaseQuery::queryPrimitive("select?+?", QVariantList(), -1, nullptr); 51 | QFAIL("primitive query should fail!"); 52 | } 53 | catch (DaoException&) { 54 | } 55 | } 56 | 57 | void BaseQueryTest::cleanup() { 58 | clearCacheAndPrintIfTestFail(); 59 | } 60 | 61 | void BaseQueryTest::cleanupTestCase() { 62 | ConfigManager::getConfig()->getClient()->dropDatabase(); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /test/corelibtest/query/BaseQueryTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | class BaseQueryTest : public BaseTest { 8 | Q_OBJECT 9 | 10 | public: 11 | using BaseTest::BaseTest; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void testPrimitiveQuery(); 17 | void testPrimitiveQueryWithValue(); 18 | void testPrimitiveQueryFail(); 19 | 20 | void cleanup(); 21 | 22 | void cleanupTestCase(); 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /test/corelibtest/query/DeleteTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | class DeleteTest : public BaseTest { 8 | Q_OBJECT 9 | 10 | public: 11 | using BaseTest::BaseTest; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void filterDeleteTest(); 17 | void objectDeleteTest(); 18 | 19 | void truncateTest_data(); 20 | void truncateTest(); 21 | 22 | void cleanup(); 23 | 24 | void cleanupTestCase(); 25 | 26 | }; -------------------------------------------------------------------------------- /test/corelibtest/query/InsertIntoSelectTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | #include "entity/sqliteentity/sqlitetest1.h" 8 | #include "entity/sqliteentity/sqlitetest2.h" 9 | 10 | #include "entity/mysqlentity/mysqltest1.h" 11 | #include "entity/mysqlentity/mysqltest2.h" 12 | 13 | #include "entity/sqlserverentity/sqlservertest1.h" 14 | #include "entity/sqlserverentity/sqlservertest2.h" 15 | 16 | #include "entity/psqlentity/psqltest1.h" 17 | #include "entity/psqlentity/psqltest2.h" 18 | 19 | class InsertIntoSelectTest : public BaseTest { 20 | Q_OBJECT 21 | 22 | public: 23 | using BaseTest::BaseTest; 24 | 25 | private slots: 26 | void initTestCase(); 27 | 28 | void testInsertIntoSelect_data(); 29 | void testInsertIntoSelect(); 30 | 31 | void testInsertIntoJoin_data(); 32 | void testInsertIntoJoin(); 33 | 34 | void cleanup(); 35 | 36 | void cleanupTestCase(); 37 | 38 | private: 39 | SqliteTest1List sqliteData1; 40 | MysqlTest1List mysqlData1; 41 | SqlServerTest1List sqlserverData1; 42 | PSqlTest1List psqlData1; 43 | }; -------------------------------------------------------------------------------- /test/corelibtest/query/InsertTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | class InsertTest : public BaseTest { 8 | Q_OBJECT 9 | 10 | public: 11 | using BaseTest::BaseTest; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void setInsertTest(); 17 | void setInsertBatchTest(); 18 | 19 | void insertObjectTest_data(); 20 | void insertObjectTest(); 21 | 22 | void insertObjectsTest_data(); 23 | void insertObjectsTest(); 24 | 25 | void insertObjects2Test_data(); 26 | void insertObjects2Test(); 27 | 28 | void insertOrReplaceTest_data(); 29 | void insertOrReplaceTest(); 30 | 31 | void insertOrIgnoreTest_data(); 32 | void insertOrIgnoreTest(); 33 | 34 | void testTransaction_data(); 35 | void testTransaction(); 36 | 37 | void testMysqlMyISAMTransaction_data(); 38 | void testMysqlMyISAMTransaction(); 39 | 40 | void cleanup(); 41 | 42 | void cleanupTestCase(); 43 | }; -------------------------------------------------------------------------------- /test/corelibtest/query/JoinTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | #include "entity/sqliteentity/sqlitetest1.h" 8 | #include "entity/sqliteentity/sqlitetest2.h" 9 | #include "entity/sqliteentity/sqlitetest3.h" 10 | 11 | #include "entity/mysqlentity/mysqltest1.h" 12 | #include "entity/mysqlentity/mysqltest2.h" 13 | #include "entity/mysqlentity/mysqltest3.h" 14 | 15 | #include "entity/sqlserverentity/sqlservertest1.h" 16 | #include "entity/sqlserverentity/sqlservertest2.h" 17 | #include "entity/sqlserverentity/sqlservertest3.h" 18 | 19 | #include "entity/psqlentity/psqltest1.h" 20 | #include "entity/psqlentity/psqltest2.h" 21 | #include "entity/psqlentity/psqltest3.h" 22 | 23 | class JoinTest : public BaseTest { 24 | Q_OBJECT 25 | 26 | public: 27 | using BaseTest::BaseTest; 28 | 29 | private slots: 30 | void initTestCase(); 31 | 32 | void testJoinTable(); 33 | void testJoinTableUseWith(); 34 | void testJoinTableFilterOn(); 35 | 36 | void testJoinSelfTable(); 37 | 38 | void testSelectFromJoin(); 39 | 40 | void testJoinFromSelect(); 41 | 42 | void testJoinOnSelect(); 43 | 44 | void testSelectUnionJoin(); 45 | 46 | void testJoinUnionSelect(); 47 | 48 | void testJoinUnionJoin(); 49 | 50 | void recursiveQueryTest(); 51 | 52 | void functionSubJoinTest_data(); 53 | void functionSubJoinTest(); 54 | 55 | void explainTest(); 56 | 57 | void cleanup(); 58 | 59 | void cleanupTestCase(); 60 | 61 | private: 62 | SqliteTest1List sqliteData1; 63 | SqliteTest2List sqliteData2; 64 | SqliteTest3List sqliteData3; 65 | 66 | MysqlTest1List mysqlData1; 67 | MysqlTest2List mysqlData2; 68 | MysqlTest3List mysqlData3; 69 | 70 | SqlServerTest1List sqlserverData1; 71 | SqlServerTest2List sqlserverData2; 72 | SqlServerTest3List sqlserverData3; 73 | 74 | PSqlTest1List psqlData1; 75 | PSqlTest2List psqlData2; 76 | PSqlTest3List psqlData3; 77 | }; 78 | -------------------------------------------------------------------------------- /test/corelibtest/query/LoggingTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BaseTest.h" 4 | 5 | class LoggingTest : public BaseTest { 6 | Q_OBJECT 7 | 8 | public: 9 | using BaseTest::BaseTest; 10 | 11 | private slots: 12 | void initTestCase(); 13 | 14 | void singleStatementTest(); 15 | 16 | void statementValueTest(); 17 | 18 | void batchQueryTest(); 19 | 20 | void rulerTest(); 21 | 22 | void defaultLoggingTest(); 23 | 24 | void cleanup(); 25 | 26 | void cleanupTestCase(); 27 | }; 28 | -------------------------------------------------------------------------------- /test/corelibtest/query/SelectTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | #include "entity/sqliteentity/sqlitetest1.h" 8 | #include "entity/sqliteentity/sqlitetest2.h" 9 | 10 | #include "entity/mysqlentity/mysqltest1.h" 11 | #include "entity/mysqlentity/mysqltest2.h" 12 | #include "entity/mysqlentity/mysqltest3.h" 13 | 14 | #include "entity/sqlserverentity/sqlservertest1.h" 15 | #include "entity/sqlserverentity/sqlservertest2.h" 16 | #include "entity/sqlserverentity/sqlservertest3.h" 17 | 18 | #include "entity/psqlentity/psqltest1.h" 19 | #include "entity/psqlentity/psqltest2.h" 20 | #include "entity/psqlentity/psqltest3.h" 21 | 22 | class SelectTest : public BaseTest { 23 | Q_OBJECT 24 | 25 | public: 26 | using BaseTest::BaseTest; 27 | 28 | private slots: 29 | void initTestCase(); 30 | 31 | void uniqueSelectTest_data(); 32 | void uniqueSelectTest(); 33 | 34 | void listSelectTest_data(); 35 | void listSelectTest(); 36 | 37 | void rawSelectTest_data(); 38 | void rawSelectTest(); 39 | 40 | void functionSelectTest(); 41 | 42 | void countSelectTest(); 43 | 44 | void selectFromSelectTest_data(); 45 | void selectFromSelectTest(); 46 | 47 | void unionSelectTest_data(); 48 | void unionSelectTest(); 49 | 50 | void funtionSubSelectTest_data(); 51 | void funtionSubSelectTest(); 52 | 53 | void explainTest(); 54 | 55 | void cleanup(); 56 | 57 | void cleanupTestCase(); 58 | 59 | private: 60 | SqliteTest1List sqliteData1; 61 | SqliteTest2List sqliteData2; 62 | MysqlTest1List mysqlData1; 63 | MysqlTest2List mysqlData2; 64 | SqlServerTest1List sqlserverData1; 65 | SqlServerTest2List sqlserverData2; 66 | PSqlTest1List psqlData1; 67 | PSqlTest2List psqlData2; 68 | }; -------------------------------------------------------------------------------- /test/corelibtest/query/UpdateTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "BaseTest.h" 6 | 7 | class UpdateTest : public BaseTest { 8 | Q_OBJECT 9 | 10 | public: 11 | using BaseTest::BaseTest; 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void setUpdateTest(); 17 | void objectUpdateTest(); 18 | 19 | void cleanup(); 20 | 21 | void cleanupTestCase(); 22 | 23 | }; -------------------------------------------------------------------------------- /test/corelibtest/query/UpsertTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BaseTest.h" 4 | 5 | class UpsertTest : public BaseTest { 6 | Q_OBJECT 7 | 8 | public: 9 | using BaseTest::BaseTest; 10 | 11 | private slots: 12 | void initTestCase(); 13 | 14 | void setUpsertTest(); 15 | 16 | void setUpsertBatchTest(); 17 | 18 | void upsertObjectTest_data(); 19 | void upsertObjectTest(); 20 | 21 | void upsertObjectsTest_data(); 22 | void upsertObjectsTest(); 23 | 24 | void upsertFilterTest(); 25 | 26 | void cleanup(); 27 | 28 | void cleanupTestCase(); 29 | }; 30 | -------------------------------------------------------------------------------- /test/customtypetest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaocustomtypetest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | include(${CMAKE_CURRENT_SOURCE_DIR}/entity/entity.cmake) 12 | add_executable(${PROJECT_NAME} 13 | main.cpp 14 | customtypetest.h 15 | customtypetest.cpp 16 | ${ENTITY_FILE_LIST} 17 | ) 18 | 19 | target_link_libraries(${PROJECT_NAME} 20 | Qt${QT_VERSION_MAJOR}::Core 21 | Qt${QT_VERSION_MAJOR}::Sql 22 | Qt${QT_VERSION_MAJOR}::Test 23 | 24 | qtdao 25 | common-test-util 26 | ) -------------------------------------------------------------------------------- /test/customtypetest/customtypetest.cpp: -------------------------------------------------------------------------------- 1 | #include "customtypetest.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "entity/customtypes.h" 7 | 8 | void CustomTypeTest::initTestCase() { 9 | try { 10 | dao::_config() 11 | .version(1) 12 | .databaseName("sqlite_customtype_test") 13 | .initializeDatabase(); 14 | 15 | } catch (dao::DaoException& e) { 16 | Q_UNUSED(e) 17 | auto validDrivers = QSqlDatabase::drivers(); 18 | Q_UNUSED(validDrivers) 19 | qFatal("setup database fail!"); 20 | } 21 | 22 | dao::_truncate(); 23 | } 24 | 25 | void CustomTypeTest::testInsert() { 26 | 27 | CustomTypes typeInstance("test1", 0x8000, QDate::fromString("2022-02-22", "yyyy-MM-dd"), 28 | {QRect(1, 1, 10, 10), QRect(10, 10, 100, 100)}, 29 | { 30 | {"key1", {MyStruct{"name1", 10, QDateTime::fromString("2022-02-23 12:22:23", "yyyy-MM-dd HH:mm:dd")}}}, 31 | {"key2", {MyStruct{"name2", 20, QDateTime::fromString("2022-02-24 12:22:24", "yyyy-MM-dd HH:mm:dd")}}}, 32 | }, 33 | MyStruct{"name3", 30, QDateTime::fromString("2022-02-25 12:22:25", "yyyy-MM-dd HH:mm:dd")} 34 | ); 35 | 36 | dao::_insert().build().insert(typeInstance); 37 | 38 | CustomTypes::Fields cf; 39 | auto instance = dao::_select().filter(cf.testName == "test1").build().unique(); 40 | QCOMPARE(instance, typeInstance); 41 | } 42 | 43 | void CustomTypeTest::testSelect() { 44 | auto customData = MyStruct{"name3", 30, QDateTime::fromString("2022-02-25 12:22:25", "yyyy-MM-dd HH:mm:dd")}; 45 | CustomTypes::Fields cf; 46 | auto data = dao::_select().filter(cf.myStruct == customData).build().one(); 47 | QCOMPARE(data.testName, "test1"); 48 | } 49 | 50 | void CustomTypeTest::testConditionIn() { 51 | auto customData = MyStruct{"name3", 30, QDateTime::fromString("2022-02-25 12:22:25", "yyyy-MM-dd HH:mm:dd")}; 52 | CustomTypes::Fields cf; 53 | auto data = dao::_select().filter(cf.myStruct.in({customData})).build().one(); 54 | QCOMPARE(data.testName, "test1"); 55 | } 56 | 57 | void CustomTypeTest::cleanup() { 58 | 59 | } 60 | 61 | void CustomTypeTest::cleanupTestCase() { 62 | dao::ConfigManager::getConfig()->getClient()->dropDatabase(); 63 | } -------------------------------------------------------------------------------- /test/customtypetest/customtypetest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class CustomTypeTest : public QObject { 6 | Q_OBJECT 7 | 8 | public: 9 | using QObject::QObject; 10 | 11 | private slots: 12 | void initTestCase(); 13 | 14 | void testInsert(); 15 | 16 | void testSelect(); 17 | 18 | void testConditionIn(); 19 | 20 | void cleanup(); 21 | 22 | void cleanupTestCase(); 23 | }; 24 | -------------------------------------------------------------------------------- /test/customtypetest/entity/custom_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/customtypetest/entity/mystruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct MyStruct { 7 | QString name; 8 | int id; 9 | QDateTime dateTime; 10 | 11 | bool operator==(const MyStruct& other) const { 12 | return other.name == this->name; 13 | } 14 | }; 15 | 16 | inline QDataStream& operator<<(QDataStream& out, const MyStruct& data) { 17 | out << data.name << data.id << data.dateTime; 18 | return out; 19 | } 20 | 21 | inline QDataStream& operator>>(QDataStream& in, MyStruct& data) { 22 | in >> data.name >> data.id >> data.dateTime; 23 | return in; 24 | } -------------------------------------------------------------------------------- /test/customtypetest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "customtypetest.h" 4 | #include "multitestrunner.h" 5 | 6 | int main(int argc, char** argv) { 7 | QCoreApplication a(argc, argv); 8 | 9 | return MultiTestRunner::run("qtdaocustomtypetest.exe"); 10 | } -------------------------------------------------------------------------------- /test/foreignkeytest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaoforeignkeytest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlite/entity.cmake) 12 | include(${CMAKE_CURRENT_SOURCE_DIR}/mysql/entity.cmake) 13 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlserver/entity.cmake) 14 | include(${CMAKE_CURRENT_SOURCE_DIR}/psql/entity.cmake) 15 | 16 | add_executable(${PROJECT_NAME} 17 | main.cpp 18 | ${ENTITY_FILE_LIST} 19 | foreignkeytest.h 20 | foreignkeytest.cpp 21 | ) 22 | 23 | target_link_libraries(${PROJECT_NAME} 24 | Qt${QT_VERSION_MAJOR}::Core 25 | Qt${QT_VERSION_MAJOR}::Sql 26 | Qt${QT_VERSION_MAJOR}::Test 27 | 28 | qtdao 29 | common-test-util 30 | ) -------------------------------------------------------------------------------- /test/foreignkeytest/foreignkeytest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | class ForeignKeyTest : public QObject, public DatabaseSelector { 8 | Q_OBJECT 9 | 10 | public: 11 | ForeignKeyTest(); 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void testInsert(); 17 | 18 | void testUpdate(); 19 | 20 | void testDelete(); 21 | 22 | void testTransaction(); 23 | 24 | void testVersionUpgrade(); 25 | 26 | void testRunInThread(); 27 | 28 | void cleanup(); 29 | 30 | void cleanupTestCase(); 31 | }; 32 | -------------------------------------------------------------------------------- /test/foreignkeytest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "foreignkeytest.h" 4 | #include "multitestrunner.h" 5 | 6 | int main(int argc, char** argv) { 7 | QCoreApplication a(argc, argv); 8 | 9 | return MultiTestRunner::run("qtdaoforeignkeytest.exe"); 10 | } -------------------------------------------------------------------------------- /test/foreignkeytest/mysql/mysql_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/foreignkeytest/psql/psql_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/foreignkeytest/sqlite/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/foreignkeytest/sqlserver/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/keywordstest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaokeywordtest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlite/entity.cmake) 12 | include(${CMAKE_CURRENT_SOURCE_DIR}/mysql/entity.cmake) 13 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlserver/entity.cmake) 14 | include(${CMAKE_CURRENT_SOURCE_DIR}/psql/entity.cmake) 15 | 16 | add_executable(${PROJECT_NAME} 17 | main.cpp 18 | ${ENTITY_FILE_LIST} 19 | keywordstest.h 20 | keywordstest.cpp 21 | ) 22 | 23 | target_link_libraries(${PROJECT_NAME} 24 | Qt${QT_VERSION_MAJOR}::Core 25 | Qt${QT_VERSION_MAJOR}::Sql 26 | Qt${QT_VERSION_MAJOR}::Test 27 | 28 | qtdao 29 | common-test-util 30 | ) -------------------------------------------------------------------------------- /test/keywordstest/keywordstest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "databaseselector.h" 6 | 7 | class KeywordsTest : public QObject, public DatabaseSelector { 8 | Q_OBJECT 9 | 10 | public: 11 | KeywordsTest(); 12 | 13 | private slots: 14 | void initTestCase(); 15 | 16 | void testStep(); 17 | 18 | void testInsert(); 19 | 20 | void testSelect(); 21 | 22 | void testUpdate(); 23 | 24 | void testJoin(); 25 | 26 | void upgradeTest(); 27 | 28 | void cleanup(); 29 | 30 | void cleanupTestCase(); 31 | }; 32 | -------------------------------------------------------------------------------- /test/keywordstest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "keywordstest.h" 4 | #include "multitestrunner.h" 5 | 6 | int main(int argc, char** argv) { 7 | QCoreApplication a(argc, argv); 8 | 9 | return MultiTestRunner::run("qtdaokeywordtest.exe"); 10 | } -------------------------------------------------------------------------------- /test/keywordstest/mysql/keywords_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | column 9 | 10 | 11 | group 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/keywordstest/psql/keywords_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | column 9 | 10 | 11 | group 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/keywordstest/sqlite/keywords_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | column 9 | 10 | 11 | group 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/keywordstest/sqlserver/keywords_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | column 9 | 10 | 11 | group 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/multidatabasetest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaomultidatabasetest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlite/v1/entity.cmake) 12 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlite/v2/entity.cmake) 13 | include(${CMAKE_CURRENT_SOURCE_DIR}/mysql/entity.cmake) 14 | include(${CMAKE_CURRENT_SOURCE_DIR}/sqlserver/entity.cmake) 15 | include(${CMAKE_CURRENT_SOURCE_DIR}/psql/entity.cmake) 16 | 17 | add_executable(${PROJECT_NAME} 18 | main.cpp 19 | multidbtest.h 20 | multidbtest.cpp 21 | ${ENTITY_FILE_LIST} 22 | ) 23 | 24 | target_link_libraries(${PROJECT_NAME} 25 | Qt${QT_VERSION_MAJOR}::Core 26 | Qt${QT_VERSION_MAJOR}::Sql 27 | Qt${QT_VERSION_MAJOR}::Test 28 | 29 | qtdao 30 | common-test-util 31 | ) -------------------------------------------------------------------------------- /test/multidatabasetest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "multidbtest.h" 4 | #include "multitestrunner.h" 5 | 6 | int main(int argc, char** argv) { 7 | QCoreApplication a(argc, argv); 8 | 9 | return MultiTestRunner::run("qtdaomultidatabasetest.exe"); 10 | } -------------------------------------------------------------------------------- /test/multidatabasetest/multidbtest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class MultiDbTest : public QObject { 6 | Q_OBJECT 7 | 8 | public: 9 | using QObject::QObject; 10 | 11 | private slots: 12 | void initTestCase(); 13 | 14 | void cleanup(); 15 | 16 | void cleanupTestCase(); 17 | 18 | void setupTest(); 19 | 20 | void sqliteNormalQueryTest(); 21 | 22 | void differentDbQueryTest(); 23 | 24 | void multiThreadTest(); 25 | }; 26 | -------------------------------------------------------------------------------- /test/multidatabasetest/mysql/mysql_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/multidatabasetest/psql/psql_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/multidatabasetest/sqlite/v1/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/multidatabasetest/sqlite/v2/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/multidatabasetest/sqlserver/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | id 10 | size 11 | 12 | 13 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/upgradetest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(qtdaoupgradetest) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_AUTOMOC ON) 6 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 7 | 8 | find_package(QT NAMES Qt6 Qt5 REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Sql Test REQUIRED) 10 | 11 | set(TEST_TYPE "sqlite" CACHE STRING "test type string") 12 | set(TEST_VER "v1" CACHE STRING "test version") 13 | message("upgrade test -> test type: ${TEST_TYPE}, version: ${TEST_VER}") 14 | 15 | add_compile_definitions(TEST_DB="${TEST_TYPE}") 16 | 17 | if (${TEST_VER} STREQUAL "v0") 18 | add_definitions(-DTEST_DB_CLEAR) 19 | elseif (${TEST_VER} STREQUAL "v1") 20 | add_compile_definitions(TARGET_VER=1) 21 | elseif (${TEST_VER} STREQUAL "v2") 22 | add_compile_definitions(TARGET_VER=2) 23 | elseif (${TEST_VER} STREQUAL "v3") 24 | add_compile_definitions(TARGET_VER=3) 25 | elseif (${TEST_VER} STREQUAL "v4") 26 | add_compile_definitions(TARGET_VER=4) 27 | else () 28 | message(FATAL_ERROR "upgrade test out of test version!") 29 | endif () 30 | 31 | if (NOT ${TEST_VER} STREQUAL "v0") 32 | include(${CMAKE_CURRENT_SOURCE_DIR}/${TEST_TYPE}/${TEST_VER}/entity.cmake) 33 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/${TEST_TYPE}/${TEST_VER}) 34 | endif () 35 | 36 | add_executable(${PROJECT_NAME} 37 | main.cpp 38 | ${ENTITY_FILE_LIST} 39 | upgradetest.h 40 | upgradetest.cpp 41 | mydbupgrader.h 42 | mydbupgrader.cpp 43 | ) 44 | 45 | target_link_libraries(${PROJECT_NAME} 46 | Qt${QT_VERSION_MAJOR}::Core 47 | Qt${QT_VERSION_MAJOR}::Sql 48 | Qt${QT_VERSION_MAJOR}::Test 49 | 50 | qtdao 51 | common-test-util 52 | ) -------------------------------------------------------------------------------- /test/upgradetest/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "upgradetest.h" 4 | #include "multitestrunner.h" 5 | 6 | int main(int argc, char** argv) { 7 | QCoreApplication a(argc, argv); 8 | 9 | return MultiTestRunner::run("qtdaoupgradetest.exe"); 10 | } -------------------------------------------------------------------------------- /test/upgradetest/mydbupgrader.cpp: -------------------------------------------------------------------------------- 1 | #include "mydbupgrader.h" 2 | 3 | #ifndef TEST_DB_CLEAR 4 | #include "table1.h" 5 | 6 | void MyDbUpgrader::onUpgrade(int oldVersion, int curVersion) { 7 | if (entityReader->isTable()) { 8 | return; 9 | } 10 | if (oldVersion == 1 && curVersion == 2) { 11 | upgrade1To2(); 12 | } else if (oldVersion == 2 && curVersion == 3) { 13 | upgrade2To3(); 14 | } else { 15 | upgradeWithDataRecovery(); 16 | } 17 | } 18 | 19 | void MyDbUpgrader::upgrade1To2() { 20 | if (config->isSqlite()) { 21 | upgradeWithDataRecovery(); 22 | return; 23 | } 24 | dao::transaction(); 25 | try { 26 | //drop index 27 | client->dropIndex(entityReader->getTableName(), client->getIndexFromFields(entityReader->getTableName(), { "number2" })); 28 | client->dropIndex(entityReader->getTableName(), client->getIndexFromFields(entityReader->getTableName(), { "number", "number2"})); 29 | //remove unique index 30 | client->dropIndex(entityReader->getTableName(), client->getIndexFromFields(entityReader->getTableName(), {"name", "number"})); 31 | if (TEST_DB == QLatin1String("sqlserver")) { 32 | client->createIndex(entityReader->getTableName(), entityReader->getNonClusteredIndexFields()[0], dao::IndexType::INDEX_NORMAL); 33 | } else { 34 | client->createIndex(entityReader->getTableName(), entityReader->getIndexFields()[0], dao::IndexType::INDEX_NORMAL); 35 | } 36 | //drop column 37 | client->dropField(entityReader->getTableName(), "number2"); 38 | //add new column 'age' 39 | client->addField(entityReader->getTableName(), entityReader->getFieldsType()[4]); 40 | dao::commit(); 41 | } catch (dao::DaoException& e) { 42 | Q_UNUSED(e) 43 | dao::rollback(); 44 | qFatal("database upgrade fail!"); 45 | } 46 | } 47 | 48 | void MyDbUpgrader::upgrade2To3() { 49 | if (config->isSqlite()) { 50 | upgradeWithDataRecovery(); 51 | return; 52 | } 53 | dao::transaction(); 54 | try { 55 | //drop index 56 | client->dropIndex(entityReader->getTableName(), client->getIndexFromFields(entityReader->getTableName(), {"name", "number"})); 57 | //drop column 58 | client->dropField(entityReader->getTableName(), "name"); 59 | //add new column 'name' 60 | client->addField(entityReader->getTableName(), entityReader->getFieldsType()[2]); 61 | //rename 'number' to 'score' 62 | client->renameField(entityReader->getTableName(), "number", "score"); 63 | dao::commit(); 64 | } catch (dao::DaoException& e) { 65 | Q_UNUSED(e) 66 | dao::rollback(); 67 | qFatal("database upgrade fail!"); 68 | } 69 | } 70 | #else 71 | void MyDbUpgrader::onUpgrade(int oldVersion, int curVersion) { 72 | } 73 | 74 | void MyDbUpgrader::upgrade1To2() { 75 | } 76 | 77 | void MyDbUpgrader::upgrade2To3() { 78 | } 79 | #endif -------------------------------------------------------------------------------- /test/upgradetest/mydbupgrader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "dao.h" 6 | 7 | class MyDbUpgrader : public dao::DatabaseUpgrader { 8 | public: 9 | void onUpgrade(int oldVersion, int curVersion) override; 10 | 11 | private: 12 | void upgrade1To2(); 13 | void upgrade2To3(); 14 | }; 15 | -------------------------------------------------------------------------------- /test/upgradetest/mysql/v1/mysql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | number2 20 | 21 | 22 | number 23 | number2 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/upgradetest/mysql/v2/mysql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/upgradetest/mysql/v3/mysql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/upgradetest/psql/v1/psql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | name 17 | number 18 | 19 | 20 | number2 21 | 22 | 23 | number 24 | number2 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/upgradetest/psql/v2/psql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | name 17 | number 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/upgradetest/psql/v3/psql_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /test/upgradetest/sqlite/v1/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | number2 20 | 21 | 22 | number 23 | number2 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/upgradetest/sqlite/v2/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/upgradetest/sqlite/v3/sqlite_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/upgradetest/sqlserver/v1/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | number2 20 | 21 | 22 | number 23 | number2 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/upgradetest/sqlserver/v2/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | name 16 | number 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/upgradetest/sqlserver/v3/sqlserver_entity.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/upgradetest/upgradetest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class UpgradeTest : public QObject { 6 | Q_OBJECT 7 | 8 | public: 9 | using QObject::QObject; 10 | 11 | private slots: 12 | void initTestCase(); 13 | 14 | void upgradeTest(); 15 | 16 | void fieldTest(); 17 | 18 | void dataTest(); 19 | 20 | void cleanup(); 21 | 22 | void cleanupTestCase(); 23 | }; 24 | -------------------------------------------------------------------------------- /todo/readme.md: -------------------------------------------------------------------------------- 1 | ## QtDao2 2 | #### TODO List: 3 | - 虚拟表创建 4 | - union select/join test fail in Qt6 5 | - 字段混淆 6 | - 内置数据库管理工具 --------------------------------------------------------------------------------