Files
TinyORM/NOTES.txt
T
2022-07-30 17:18:02 +02:00

1119 lines
35 KiB
Plaintext

Increase/bump the release version:
----------------------------------
- increase in the following files
include/orm/version.hpp
tests/TinyUtils/src/version.hpp
tom/include/tom/version.hpp
- and also informational version in badges
README.md
Todos to check in TinyOrm:
--------------------------
- QueryBuilder::insertGetId() allows insert with empty attributes, also Model::performInsert()
when incrementing == true, but all other insert methods don't, it's big inconsistency, unify it
Documentation TinyOrm Todos:
----------------------------
- how to refer NULL in docs, for now I leave it NULL
TODOs which look bad in code:
-----------------------------
- future add onDelete (and similar) callback feature
/*! Delete records from the database. */
void deleteModel()
{
// TODO future add onDelete (and similar) callback feature silverqx
// if (isset($this->onDelete)) {
// return call_user_func($this->onDelete, $this);
// }
return toBase().deleteRow();
}
- add c++20 compiler check, something like:
#ifdef __cplusplus
# if __cplusplus < 201103L && !defined(Q_CC_MSVC)
# error Qt requires a C++11 compiler and yours does not seem to be that.
# endif
#endif
- check this in cmake build:
#include(GenerateExportHeader)
#_test_compiler_hidden_visibility()
Todo categories:
----------------
Common:
- api different : different api than Laravel's Eloquent
- check : something to find out 🤔
- concept : add concept or constraint
- docs : document code or update markdown documentation
- desirable : feature which is extremely wanted
- dilemma : some sort of a fuckup
- duplicate : duplicate code
- feature : some feature to implement, perpend before feature described below
- future : task which has lower priority, because still much to do
- mistake : bad decision during prototyping 😭
- move : c++ move semantics
- mystery : don't know why that stuff is happening, find out what's up
- now : do it before commit
- next : next thing in the row to do after commit
- overflow : add check code, eg when size_t to int conversion
- perf : performance
- production : check before deploy to production
- regex : mark regex-es, try to avoid them
- reliability : make things more robust and reliable
- repeat : tasks that should I make from time to time
- security : self explaining
- study : don't know how something works, need to check up
- sync : synchronization in multi thread environment silverqx
- test : tasks in auto tests
- types : juggling with c++ types
Features related/to implement:
- aggregates : aggregate values like count, max, min, avg and sum
- castable : attributes casting
- default attributes : Default Attribute Values
- dilemma primarykey : different types for primary keys
- expression : DB::raw() support in the query builder
- events : event system
- ga : github actions
- guarded : related to the mass assignable feature
- json columns : JSON support
- logging : logging related
- migrations : database migrations related
- multidriver : task related to adding support for another drivers PostgreSQL, SQLite and SQL Server
- pivot : pivot table in the many-to-many relationship
- postgres : specific to PostgreSQL server
- qt6 : related to Qt6 upgrade or compatibility
- read/write connection : read/write connection
- relations : relations related 🤓
- savepoints : database savepoints
- scopes : query scopes
- seeders : seeders related
- table prefix : table prefix in the query grammar
- tom : tom migrations related
Versions info:
--------------
This is laravel/framework version, not laravel/laravel version:
- I have cloned repository at - E:\htdocs\laravel-src-master
- based on Laravel v8.26.1
- upgrade to Laravel v8.41.0 ( 15.5.2021, but I didn't merged/reflected new changes to TinyORM )
- upgrade to Laravel v8.80.0 ( 19.1.2021, upgrade from v8.41.0 )
- compare URLs (remove after merge):
- https://github.com/laravel/framework/compare/v8.26.1...v8.41.0
- https://github.com/laravel/framework/compare/v8.41.0...v8.80.0
- close all expanded sections in diff:
document.querySelectorAll('.btn-octicon.js-details-target[aria-expanded=true]').forEach((value) => value.click())
Maintenance:
------------
- from time to time try:
- compile without PCH
- compile with Qt6, I have still problem with clazy
GitHub Actions:
---------------
- how to update the clazy-standalone (analyzers.yml):
- update the QtCreator to latest version, copy libexec/qtcreator/clang/ to some empty folder
- leave only the clazy-standalone executable in the bin/ folder and compress it:
tar cjvf ../clazy-standalone.tar.bz2 .
- then upload to the gdrive to the public/TinyORM folder and create shareble link to obtain ID
- paste this new URL to the GitHub secrets:
https://drive.google.com/uc?id=some_id
- prepend to the env. variables:
- name: Print env
run: |
echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
echo "LIBRARY_PATH: $LIBRARY_PATH"
echo "PATH: $PATH"
- name: TinyORM prepend to the system $PATH
working-directory: ..
run: |
echo "LD_LIBRARY_PATH=$PWD${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" >> $GITHUB_ENV
echo "LIBRARY_PATH=$GITHUB_WORKSPACE" >> $GITHUB_ENV
pwd >> $GITHUB_PATH
- name: Print env
working-directory: ..
run: |
pwd
echo "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
echo "LIBRARY_PATH: $LIBRARY_PATH"
echo "PATH: $PATH"
- run: exit 1
- vcpkg debug:
- name: TinyORM cmake configure (msvc-cmake-debug)
run: >-
echo $env:VCPKG_ROOT
echo $env:VCPKG_DEFAULT_TRIPLET
echo $env:VCPKG_MAX_CONCURRENCY
cmake
-S .
-B ../TinyORM-builds-cmake/build-msvc-cmake-debug
...
- ssh into runner:
- shortcuts:
ctrl-b c - new window
ctrl-b 0-9 - switch to window
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
- run: exit 1
- print all contexts:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJSON(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Dump job context
env:
JOB_CONTEXT: ${{ toJSON(job) }}
run: echo "$JOB_CONTEXT"
- name: Dump steps context
env:
STEPS_CONTEXT: ${{ toJSON(steps) }}
run: echo "$STEPS_CONTEXT"
- name: Dump runner context
env:
RUNNER_CONTEXT: ${{ toJSON(runner) }}
run: echo "$RUNNER_CONTEXT"
- name: Dump strategy context
env:
STRATEGY_CONTEXT: ${{ toJSON(strategy) }}
run: echo "$STRATEGY_CONTEXT"
- name: Dump matrix context
env:
MATRIX_CONTEXT: ${{ toJSON(matrix) }}
run: echo "$MATRIX_CONTEXT"
- name: Dump env context
env:
ENV_CONTEXT: ${{ toJSON(env) }}
run: echo "$ENV_CONTEXT"
- run: exit 1
- query caches using the gh api
# Print all caches usage summary
gh api -H "Accept: application/vnd.github+json" /repos/silverqx/TinyORM/actions/cache/usage
# List caches
gh api -H "Accept: application/vnd.github+json" /repos/silverqx/TinyORM/actions/caches
# Delete all caches for TinyORM repo
gh api --method DELETE -H "Accept: application/vnd.github+json" /repos/silverqx/TinyORM/actions/caches
# Delete a cache by ID for TinyORM repo
gh api --method DELETE -H "Accept: application/vnd.github+json" /repos/silverqx/TinyORM/actions/caches/CACHE_ID
- cache build folder:
- name: Build folder restore 🕺
id: cache-build-msvc2022-qt63
uses: actions/cache@v3
env:
cache-name: msvc2022-qt63
with:
path: ${{ runner.workspace }}/TinyORM-builds-cmake/build-msvc-cmake-debug
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
RegExs:
-------
- const data members:
(?<![\(\)])(const) +.* +\bm_.*\b( +.*)?;$
(?<![\(\)])(const) +.* +\bm_.*\b +=
(?<![\(\)])(const) +.* +\bm_.*\b +{
- const data member references:
(?<![\(\)])(const) +.* +&\bm_.*\b( +.*)?;$
- all exceptions:
throw (.*::)?\w+(E|_error)
Powershell commands:
--------------------
- export todos to csv:
Get-ChildItem -Path *.cpp,*.hpp -Recurse | sls -Pattern ' (TODO|NOTE|FIXME|BUG|WARNING|CUR|FEATURE|TEST|FUTURE) ' -CaseSensitive | % { $_.Line = $_.Line.Trim().TrimStart('// '); return $_; } | select Line,LineNumber,Path | Export-Csv todos.csv -Delimiter ';' -NoTypeInformation
- search in todos:
Get-ChildItem -Path *.cpp,*.hpp -Recurse | sls -Pattern ' (TODO|NOTE|FIXME|BUG|WARNING|CUR|FEATURE|TEST|FUTURE) ' -CaseSensitive | % { $_.Line = $_.Line.Trim().TrimStart('// '); return $_; } | where Line -Match 'pch' | select Line,LineNumber,Path | ft -AutoSize
- filter out executed queries:
Get-Content .\tmp.sql | sls -Pattern '^(Executed prepared query)' | Set-Content executed_queries.sql
- TinyOrmPlayground - run InvokeXTimes.ps1 on Linux:
stp && sq5
export LD_LIBRARY_PATH=../../../TinyOrm/TinyOrm-builds-qmake/build-TinyOrm-Desktop_Qt_5_15_2_GCC_64bit_ccache-Debug/src
pwsh -NoLogo -NoProfile -File InvokeXTimes.ps1 2 ../../../TinyOrmPlayground/TinyOrmPlayground-builds-qmake/build-TinyOrmPlayground-Desktop_Qt_5_15_2_GCC_64bit_ccache-Debug/TinyOrmPlayground
- TinyORM - run InvokeXTimes.ps1 on Linux:
stp && sq5 && cdtq && cd build-TinyOrm-Desktop_Qt_5_15_2_GCC_64bit_ccache-Debug
export LD_LIBRARY_PATH=./src:./tests/TinyUtils${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH
export PATH=$HOME/Code/c/TinyORM/tools:$PATH
InvokeXTimes.ps1
pwsh -NoLogo -NoProfile -File InvokeXTimes.ps1 100
Powershell Clang analyzers:
---------------------------
qa-lint-tinyorm-qt5.ps1 is tailor-made for TinyORM project.
qa-clang-tidy.ps1, qa-clazy-standalone.ps1, qa-clazy-standalone-st.ps1 are more general, they can be used with any project, "-st" script calls raw clazy-standalone.exe.
run-clang-tidy.ps1, run-clazy-standalone.ps1 are raw Powershell wrappers around python run-clang-tidy/run-clazy-standalone.py python scripts.
cmake build commands:
---------------------
vcvars64.ps1
cd E:\c\qMedia\TinyOrm\TinyOrm-builds-cmake\build-cmake\
cmake.exe -S E:/c/qMedia/TinyOrm/TinyOrm -B E:/c/qMedia/TinyOrm/TinyOrm-builds-cmake/build-cmake -GNinja `
-DCMAKE_BUILD_TYPE:STRING=Debug `
-DCMAKE_TOOLCHAIN_FILE:PATH=E:/c_libs/vcpkg/scripts/buildsystems/vcpkg.cmake
cmake --build . --target all
- generate Graphviz dependency image:
cmake.exe -S E:/c/qMedia/TinyOrm/TinyOrm -B E:/c/qMedia/TinyOrm/TinyOrm-builds-cmake/build-cmake -GNinja `
-DCMAKE_BUILD_TYPE:STRING=Debug `
-DCMAKE_TOOLCHAIN_FILE:PATH=E:/c_libs/vcpkg/scripts/buildsystems/vcpkg.cmake `
--graphviz=E:/c/qMedia/TinyOrm/TinyOrm-builds-cmake/build-cmake/graph/graph.dot; `
`
dot -Tpng -o .\graph\graph.png .\graph\graph.dot; `
.\graph\graph.png
- running ctest
E:\c\qMedia\TinyOrm\TinyOrm\tests\auto\utils\testdata\dotenv.ps1
$env:Path = "E:\c\qMedia\TinyOrm\TinyOrm-builds-cmake\build-TinyOrm-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug-cmake;E:\c\qMedia\TinyOrm\TinyOrm-builds-cmake\build-TinyOrm-Desktop_Qt_5_15_2_MSVC2019_64bit-Debug-cmake\tests\auto\utils;" + $env:Path
ctest
ctest --progress
- some debug output:
cmake --trace-expand --trace-source=tests/auto/unit/orm/query/mysql_querybuilder/CMakeLists.txt -LA ..
cmake -LA .
- full build command, not needed, I leave it here as a shortcut:
cmake.exe -S E:/c/qMedia/TinyOrm/TinyOrm -B E:/c/qMedia/TinyOrm/TinyOrm-builds-cmake/build-cmake -GNinja `
"-DCMAKE_BUILD_TYPE:STRING=Debug" `
"-DCMAKE_PROJECT_INCLUDE_BEFORE:PATH=E:/Qt/Tools/QtCreator/share/qtcreator/package-manager/auto-setup.cmake" `
"-DQT_QMAKE_EXECUTABLE:STRING=E:/Qt/5.15.2/msvc2019_64/bin/qmake.exe" `
"-DCMAKE_PREFIX_PATH:STRING=E:/Qt/5.15.2/msvc2019_64" `
"-DCMAKE_C_COMPILER:STRING=C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/HostX64/x64/cl.exe" `
"-DCMAKE_CXX_COMPILER:STRING=C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30037/bin/HostX64/x64/cl.exe" ` "-DCMAKE_TOOLCHAIN_FILE:PATH=E:/c_libs/vcpkg/scripts/buildsystems/vcpkg.cmake"
- put TinyOrm and TinyUtils libraries on the system path:
$env:Path = "E:\c\qMedia\TinyOrm\TinyOrm-builds-cmake\build-cmake;E:\c\qMedia\TinyOrm\TinyOrm-builds-cmake\build-cmake\tests\auto\utils;" + $env:Path
TinyORM docs github pages:
--------------------------
tags: docusaurus
---
- npm run clear
Clear a Docusaurus site's generated assets, caches, build artifacts.
We recommend running this command before reporting bugs, after upgrading versions, or anytime you have issues with your Docusaurus site.
- deploy:
.\dotenv.ps1
npm run deploy; echo "Algolia Rebuild"; sleep 30; .\algolia_rebuild.ps1
- local development:
npm start
npm start -- --no-open
- update Algolia index by DocSearch:
.\dotenv.ps1
.\algolia_rebuild.ps1
- upgrade Docusaurus npm:
npm install @docusaurus/core@latest @docusaurus/plugin-client-redirects@latest @docusaurus/plugin-ideal-image@latest @docusaurus/preset-classic@latest
- upgrade Docusaurus yarn:
yarn upgrade @docusaurus/core@latest @docusaurus/preset-classic@latest
CMake Guidelines:
-----------------
All are snake-case unless otherwise specified.
- variable names:
- global variables: tiny_
- local variables: preferred camelCase or snake-case
- function parameters: lowercase and optional tiny_ prefix
- cmake_parse_arguments: TINY_
- option variables: upper case without prefix
- cached variables: TINY_
- function names has the tiny_ prefix
- compile definitions prefix by project eg. TINYORM_, TINYUTILS_
Drop all PostgreSQL tables:
---------------------------
DROP TABLE IF EXISTS "tag_properties" CASCADE;
DROP TABLE IF EXISTS "tag_torrent" CASCADE;
DROP TABLE IF EXISTS "torrent_tags" CASCADE;
DROP TABLE IF EXISTS "roles" CASCADE;
DROP TABLE IF EXISTS "role_user" CASCADE;
DROP TABLE IF EXISTS "users" CASCADE;
DROP TABLE IF EXISTS "user_phones" CASCADE;
DROP TABLE IF EXISTS "settings" CASCADE;
DROP TABLE IF EXISTS "torrents" CASCADE;
DROP TABLE IF EXISTS "torrent_peers" CASCADE;
DROP TABLE IF EXISTS "torrent_previewable_files" CASCADE;
DROP TABLE IF EXISTS "torrent_previewable_file_properties" CASCADE;
DROP TABLE IF EXISTS "file_property_properties" CASCADE;
DROP TABLE IF EXISTS "migrations" CASCADE;
DROP TABLE IF EXISTS "migrations_example" CASCADE;
DROP TABLE IF EXISTS "migrations_unit_testing" CASCADE;
UBSan:
------
Has to be invoked on Linux clang and errors are detected at runtime.
This enable the undefined group:
QMAKE_CXXFLAGS += -O1 -fsanitize=undefined
QMAKE_LFLAGS += -fsanitize=undefined
This with the above one! enables all the possible sanitizers:
QMAKE_CXXFLAGS += -O1 -fsanitize=nullability -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds
QMAKE_LFLAGS += -fsanitize=nullability -fsanitize=float-divide-by-zero -fsanitize=unsigned-integer-overflow -fsanitize=implicit-conversion -fsanitize=local-bounds
Set in the QtCreator env. before execution, it suspends some errors detected in the Qt library:
UBSAN_OPTIONS=suppressions=/home/silverqx/Code/c/TinyOrm/TinyORM/tools/configs/UBSan.supp:print_stacktrace=0
inline constants:
-----------------
- for static archive build only inline constants are allowed, this is the default for all scenarios, any ify
- cmake
- normal behavior is that user can switch between inline and extern constants using the INLINE_CONSTANTS cmake option
- default is to provide/show this INLINE_CONSTANTS cmake option with the default value OFF, so extern constants are enabled by default
- MinGW clang shared build crashes with inline constants
- so don't show INLINE_CONSTANTS cmake option and value is NOT DEFINED in this case so the default will be used and it's extern constants
- MinGW clang static build is not supported, problem with inline constants :/
- this is different than qmake build, it compiles (qmake has problem with duplicit symbols) but it crashes
- so throw cmake message(FATAL_ERROR) with a nice message in TinyHelpers tiny_check_unsupported_build()
- clang-cl shared build crashes with extern constants, so force to inline constants 😕🤔
- don't show INLINE_CONSTANTS cmake option and provide the default value ON using feature_option_dependent(INLINE_CONSTANTS) depends option, so inline constants is the default
- so inline constants are only one option with clang-cl
- qmake
- normal behavior is that user can switch between inline and extern constants using the inline_constants/extern_constants qmake CONFIG option
- default is when no qmake CONFIG option is set and in this case extern constants (extern_constants CONFIG option) is set/enabled
- MinGW clang shared build crashes with inline constants
- when user set inline_constants then qmake error() is thrown with nice message
- so the default is extern constants, if no CONFIG option was set or user can set the extern_constants qmake CONFIG option manually
- MinGW clang static build is not supported, contains a problem with duplicit symbols, this build type is disabled
- qmake error() is thrown with a nice message
- cmake compiles ok but crashes in this scenario
- clang-cl shared build crashes with extern constants, so force to inline constants 😕🤔
- when is shared build then inline_constants qmake CONFIG option is set (this is the default)
- when user set extern_constants then qmake error() is thrown with nice message
- so inline constants are only one option with clang-cl
The conclusion is that the funckin string constants 💥, it was bearable until I have added the clang-cl MSVC support.
constructor copy/move snippet:
------------------------------
Add code below to class you want to optimize and set breakpoints inside and you will see what cause what 😎:
Torrent(const Torrent &torrent)
: Model(torrent)
{
qDebug() << "Torrent copy ctor";
}
Torrent(Torrent &&torrent)
: Model(std::move(torrent))
{
qDebug() << "Torrent move ctor";
}
Torrent &operator=(const Torrent &torrent)
{
Model::operator=(torrent);
qDebug() << "Torrent copy assign";
return *this;
}
Torrent &operator=(Torrent &&torrent)
{
Model::operator=(std::move(torrent));
qDebug() << "Torrent move assign";
return *this;
}
conversions:
------------
Makes possible to assign QVector<AttributeItem> to the Model,
or implicitly converts a QVector<AttributeItem> to Model:
Model(const QVector<AttributeItem> &attributes);
Model(QVector<AttributeItem> &&attributes);
--
Allows initialize the Model with QVector<AttributeItem>:
Model(std::initializer_list<AttributeItem> attributes)
: Model(QVector<AttributeItem> {attributes.begin(), attributes.end()})
{}
--
Makes possible to assign the Model to the QVector<AttributeItem>,
or converts the Model to the QVector<AttributeItem>:
operator QVector<AttributeItem>() const;
Ranges transform:
-----------------
const auto relationToWithItem = [](const auto &relation) -> WithItem
{
return WithItem {relation};
};
builder->with(relations | ranges::views::transform(relationToWithItem)
| ranges::to<QVector<WithItem>>());
DatabaseConnection config:
--------------------------
QHash<QString, QVariant> config {
// {"driver", "mysql"},
// {"url", qEnvironmentVariable("DATABASE_URL")},
// {"url", qEnvironmentVariable("MYSQL_DATABASE_URL")},
{"host", qEnvironmentVariable("DB_MYSQL_HOST", "127.0.0.1")},
{"port", qEnvironmentVariable("DB_MYSQL_PORT", "3306")},
{"database", qEnvironmentVariable("DB_MYSQL_DATABASE", "")},
{"username", qEnvironmentVariable("DB_MYSQL_USERNAME", "root")},
{"password", qEnvironmentVariable("DB_MYSQL_PASSWORD", "")},
// {"unix_socket", qEnvironmentVariable("DB_MYSQL_SOCKET", "")},
{"charset", qEnvironmentVariable("DB_MYSQL_CHARSET", "utf8mb4")},
{"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_unicode_ci")},
// {"collation", qEnvironmentVariable("DB_MYSQL_COLLATION", "utf8mb4_0900_ai_ci")},
// {"timezone", "+00:00"},
// {"prefix", ""},
// {"prefix_indexes", true},
{"strict", true},
// {"engine", {}},
{"options", ""},
};
QHash<QString, QVariant> config {
{"driver", "QSQLITE"},
{"database", qEnvironmentVariable("DB_SQLITE_DATABASE", "")},
{"prefix", ""},
{"options", QVariantHash()},
{"foreign_key_constraints", qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS",
"true")},
{"check_database_exists", true},
};
QtCreator common CMake options:
-------------------------------
-G Ninja
-D CMAKE_BUILD_TYPE:STRING=Debug
-D BUILD_TESTS:BOOL=OFF
-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=ON
-D MYSQL_PING:BOOL=ON
-D ORM:BOOL=OFF
-D TOM:BOOL=ON
-D TOM_EXAMPLE:BOOL=ON
-D TOM_MIGRATIONS_DIR:PATH=database/migrations
-D VERBOSE_CONFIGURE:BOOL=OFF
-D CMAKE_VERBOSE_MAKEFILE:BOOL=OFF
-D CMAKE_DISABLE_PRECOMPILE_HEADERS:BOOL=OFF
-D CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=OFF
-D CMAKE_PROJECT_INCLUDE_BEFORE:PATH=%{IDE:ResourcePath}/package-manager/auto-setup.cmake
-D QT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-D CMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-D CMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-D CMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
- for QtCreator:
-D CMAKE_CXX_COMPILER_LAUNCHER:FILEPATH=C:/Users/<username>/scoop/shims/ccache.exe
-D CMAKE_VERBOSE_MAKEFILE:BOOL=OFF
-D VERBOSE_CONFIGURE:BOOL=ON
-D BUILD_TESTS:BOOL=ON
-D MATCH_EQUAL_EXPORTED_BUILDTREE:BOOL=OFF
-D MYSQL_PING:BOOL=ON
-D ORM:BOOL=ON
-D TOM:BOOL=ON
-D TOM_EXAMPLE:BOOL=ON
-D TOM_MIGRATIONS_DIR:PATH=database/migrations
DatabaseConnection debug code:
------------------------------
{
auto [ok, query] = select("select @@session.time_zone, @@global.time_zone");
while(query.next()) {
qDebug().nospace() << query.value(0).toString() << "\n"
<< query.value(1).toString();
}
}
{
auto [ok, query] = select("select @@session.character_set_client, @@session.character_set_connection, "
"@@session.character_set_results, @@session.collation_connection");
while(query.next()) {
qDebug().nospace() << query.value(0).toString() << "\n"
<< query.value(1).toString() << "\n"
<< query.value(2).toString() << "\n"
<< query.value(3).toString();
}
}
{
auto [ok, query] = select("select @@global.character_set_client, @@global.character_set_connection, "
"@@global.character_set_results, @@global.collation_connection");
while(query.next()) {
qDebug().nospace() << query.value(0).toString() << "\n"
<< query.value(1).toString() << "\n"
<< query.value(2).toString() << "\n"
<< query.value(3).toString();
}
}
{
auto [ok, query] = select("select @@global.sql_mode, @@session.sql_mode");
while(query.next()) {
qDebug().nospace() << query.value(0).toString() << "\n"
<< query.value(1).toString();
}
}
tmp notes:
----------
message(-------)
message(XXX config.pri)
message(PWD: $$PWD)
message(OUT_PWD: $$OUT_PWD)
message(_PRO_FILE_PWD_: $$_PRO_FILE_PWD_)
message(INCLUDEPATH: $$INCLUDEPATH)
message(-------)
tmp notes - Queryable columns:
------------------------------
template<SubQuery T>
struct Queryable
{
QString as;
// std::variant<std::function<void(Orm::QueryBuilder &)>> queryable;
T queryable;
};
Queryable(Orm::QueryBuilder &) -> Queryable<Orm::QueryBuilder &>;
/*! Set the columns to be selected. */
template<SubQuery T>
Builder &select(const QVector<Queryable<T>> &columns)
// Builder &select(const QVector<Queryable> &columns)
{
clearColumns();
for (const auto &q : columns)
selectSub(q.queryable, q.as);
return *this;
}
/*! Set the column to be selected. */
// template<SubQuery T>
// Builder &select(const Column &column);
// /*! Add new select columns to the query. */
// template<SubQuery T>
// Builder &addSelect(const QVector<Column> &columns);
// /*! Add a new select column to the query. */
// template<SubQuery T>
// Builder &addSelect(const Column &column);
/*! Makes "from" fetch from a subquery. */
// template<SubQuery T>
// Builder &whereSub(T &&query, const QVariant &value)
// {
// /* If the column is a Closure instance and there is an operator value, we will
// assume the developer wants to run a subquery and then compare the result
// of that subquery with the given value that was provided to the method. */
// auto [queryString, bindings] = createSub(std::forward<T>(query));
// addBinding(bindings, BindingType::WHERE);
// return where(Expression(QStringLiteral("(%1)").arg(queryString)),
// QStringLiteral("="), value);
// }
Model copy ctor:
----------------
template<typename Derived, AllRelationsConcept ...AllRelations>
Model<Derived, AllRelations...>::Model(const Model &model)
: exists(model.exists)
, u_table(model.u_table)
, u_connection(model.u_connection)
, u_incrementing(model.u_incrementing)
, u_primaryKey(model.u_primaryKey)
, u_relations(model.u_relations)
, u_with(model.u_with)
, m_attributes(model.m_attributes)
, m_original(model.m_original)
, m_changes(model.m_changes)
, m_attributesHash(model.m_attributesHash)
, m_originalHash(model.m_originalHash)
, m_changesHash(model.m_changesHash)
, m_relations(model.m_relations)
, u_touches(model.u_touches)
, m_pivots(model.m_pivots)
, u_timestamps(model.u_timestamps)
{}
AssignmentList:
---------------
I want to save this pattern:
struct AssignmentListItem
{
QString column;
QVariant value;
};
class AssignmentList final : public QVector<AssignmentListItem>
{
// Inherit all the base class constructors, wow 😲✨
using QVector<AssignmentListItem>::QVector;
public:
AssignmentList(const QVariantHash &variantHash)
{
auto itHash = variantHash.constBegin();
while (itHash != variantHash.constEnd()) {
*this << AssignmentListItem({itHash.key(), itHash.value()});
++itHash;
}
}
};
EntityManager.hpp:
------------------
#ifndef ENTITYMANAGER_H
#define ENTITYMANAGER_H
#include "orm/databaseconnection.hpp"
#include "orm/repositoryfactory.hpp"
#ifdef TINYORM_COMMON_NAMESPACE
namespace TINYORM_COMMON_NAMESPACE
{
#endif
namespace Orm
{
/*! The EntityManager is the central access point to ORM functionality. */
class SHAREDLIB_EXPORT EntityManager final
{
Q_DISABLE_COPY(EntityManager)
public:
EntityManager(const QVariantHash &config);
EntityManager(DatabaseConnection &connection);
~EntityManager();
/*! Factory method to create EntityManager instances. */
static EntityManager create(const QVariantHash &config);
/*! Gets the repository for an entity class. */
template<typename Repository>
QSharedPointer<Repository> getRepository() const;
/*! Create a new QSqlQuery. */
QSqlQuery query() const;
/*! Get a new query builder instance. */
QSharedPointer<QueryBuilder> queryBuilder() const;
/*! Check database connection and show warnings when the state changed. */
bool pingDatabase();
/*! Start a new database transaction. */
bool transaction();
/*! Commit the active database transaction. */
bool commit();
/*! Rollback the active database transaction. */
bool rollback();
/*! Start a new named transaction savepoint. */
bool savepoint(const QString &id);
/*! Rollback to a named transaction savepoint. */
bool rollbackToSavepoint(const QString &id);
/*! Get underlying database connection. */
inline DatabaseConnection &connection() const
{ return m_db; }
protected:
/*! Factory method to create DatabaseConnection instances. */
static DatabaseConnection &
createConnection(const QVariantHash &config);
private:
/*! The database connection used by the EntityManager. */
DatabaseConnection &m_db;
/*! The repository factory used to create dynamic repositories. */
RepositoryFactory m_repositoryFactory;
};
template<typename Repository>
QSharedPointer<Repository> EntityManager::getRepository() const
{
return m_repositoryFactory.getRepository<Repository>();
}
} // namespace Orm
#ifdef TINYORM_COMMON_NAMESPACE
} // namespace TINYORM_COMMON_NAMESPACE
#endif
#endif // ENTITYMANAGER_H
EntityManager.cpp:
------------------
#include "orm/entitymanager.hpp"
#include <QtSql/QSqlQuery>
#ifdef TINYORM_COMMON_NAMESPACE
namespace TINYORM_COMMON_NAMESPACE
{
#endif
namespace Orm
{
/*!
\class EntityManager
\brief The EntityManager class manages repositories and a connection
to the database.
\ingroup database
\inmodule Export
EntityManager is the base class to work with the database, it creates
and manages repository classes by helping with the RepositoryFactory
class.
Creates the database connection which is represented by
DatabaseConnection class.
EntityManager should be used in controllers ( currently TorrentExporter
is like a controller class ), services, and repository classes to access
the database. There is no need to use the QSqlDatabase or the
DatabaseConnection classes directly.
EntityManager is also injected into a repository and a service
classes constructors.
The circular dependency problem is solved by including entitymanager.hpp
in the baserepository.hpp file.
*/
EntityManager::EntityManager(const QVariantHash &config)
: m_db(createConnection(config))
, m_repositoryFactory(*this)
{}
EntityManager::EntityManager(DatabaseConnection &connection)
: m_db(connection)
, m_repositoryFactory(*this)
{}
EntityManager::~EntityManager()
{
DatabaseConnection::freeInstance();
}
EntityManager EntityManager::create(const QVariantHash &config)
{
return EntityManager(createConnection(config));
}
QSqlQuery EntityManager::query() const
{
return m_db.query();
}
QSharedPointer<QueryBuilder> EntityManager::queryBuilder() const
{
return m_db.query();
}
bool EntityManager::pingDatabase()
{
return m_db.pingDatabase();
}
bool EntityManager::transaction()
{
return m_db.transaction();
}
bool EntityManager::commit()
{
return m_db.commit();
}
bool EntityManager::rollback()
{
return m_db.rollback();
}
bool EntityManager::savepoint(const QString &id)
{
return m_db.savepoint(id);
}
bool EntityManager::rollbackToSavepoint(const QString &id)
{
return m_db.rollbackToSavepoint(id);
}
DatabaseConnection &
EntityManager::createConnection(const QVariantHash &config)
{
return DatabaseConnection::create(config.find("database").value().toString(),
config.find("prefix").value().toString(),
config);
}
} // namespace Orm
#ifdef TINYORM_COMMON_NAMESPACE
} // namespace TINYORM_COMMON_NAMESPACE
#endif
Check whether first data member in BaseCommand is QString (unsuccessful):
---
struct CommandDefinition
{};
struct BaseCommand : CommandDefinition
{
QString name;
};
struct Idx1 : CommandDefinition
{
int i = 0;
QString name;
};
template<typename T>
concept IsQString = requires(T t)
{
// requires std::same_as<decltype (std::declval<T>().name), QString>;
{t.name} -> std::same_as<QString &>;
};
BaseCommand i {.name = "h i"};
Idx1 i1 {.i = 10, .name = "h i1"};
CommandDefinition &bi = i;
CommandDefinition &bi1 = i1;
if constexpr (IsQString<decltype (reinterpret_cast<BaseCommand &>(bi))>)
qDebug() << "y";
else
qDebug() << "n";
Test Column expressions code, just swap groupBy
-----
auto q1 = Torrent::find(1)->torrentFiles()->groupBy({"xyz", "abc"}).toSql();
qDebug() << q1;
auto q2 = Torrent::find(1)->torrentFiles()->groupBy("xyz").toSql();
qDebug() << q2;
auto q = Torrent::find(1)->torrentFiles()->groupBy("abc", "def").toSql();
qDebug() << q;
auto t1 = Torrent::find(1)->torrentFiles()->groupBy({DB::raw("xyz"), "abc"}).toSql();
qDebug() << t1;
auto t2 = Torrent::find(1)->torrentFiles()->groupBy(DB::raw("xyz")).toSql();
qDebug() << t2;
auto t = Torrent::find(1)->torrentFiles()->groupBy("abc", DB::raw("def")).toSql();
qDebug() << t;
QString s1("abc");
const QString s2("fgh");
auto q3 = Torrent::find(1)->torrentFiles()->groupBy(s1, s2).toSql();
qDebug() << q3;
auto q4 = Torrent::find(1)->torrentFiles()->groupBy(std::move(s1), s2).toSql();
qDebug() << q4;
const QString s3("jkl");
auto t3 = Torrent::find(1)->torrentFiles()->groupBy(s3, DB::raw(s2)).toSql();
qDebug() << t3;
auto t4 = Torrent::find(1)->torrentFiles()->groupBy(std::move(s3), DB::raw(s2)).toSql();
qDebug() << t4;
Performance measure timer:
--------------------------
#include <QElapsedTimer>
QElapsedTimer timer;
timer.start();
qDebug().noquote() << QStringLiteral("Elapsed in XX : %1ms").arg(timer.elapsed());
$startTime = microtime(true);
printf("Elapsed in %s : %sms\n", $connection,
number_format((microtime(true) - $startTime) * 1000, 2));
Fastly write to the file:
-------------------------
#include <fstream>
std::ofstream("E:/tmp/aa.txt", std::ios::out | std::ios::app) << "first\nsecond\n";
std::ofstream("E:/tmp/aa.txt", std::ios::out | std::ios::app) << "another line\n";
Invoke-Tests.ps1:
-----------------
- 100 times run
- 28. dec 2021
- Windows 10:
- Qt 5.15.2 ; msvc 16.11.8 x64
- debug build
All AutoTests Execution time : 792519ms
All AutoTests Average Execution time : 7925ms
- Qt 6.2.1 ; msvc 16.11.8 x64
- debug build
All AutoTests Execution time : 986531ms
All AutoTests Average Execution time : 9865ms
- Gentoo:
- Qt 5.15.2 ; GCC 11.2 x64 ccache
- debug build
All AutoTests Execution time : 519138ms
All AutoTests Average Execution time : 5191ms
- Qt 6.2.2 ; GCC 11.2 x64 ccache
- debug build
All AutoTests Execution time : 546585ms
All AutoTests Average Execution time : 5466ms
Compilation time and Memory usage:
----------------------------------
- 04. jun 2022 qmake ("CONFIG+=mysql_ping tom_example build_tests")
- Qt 6.2.4
MSVC2019 9.9GB 1:27
MSVC2022 8.0GB 1:25
clang-cl MSVC2022 5.5GB 1:35
bugs:
-----
- BUG std::unordered_map can not be instantiated with the incomplete value type, reproducible only on the Linux GCC/Clang, MSYS2 and msvc don't have any problem with the incomplete type ✨🚀
add this to the testforplay.cpp
#include <filesystem>
#include <iostream>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
namespace Models {
class Torrent;
}
struct Test1
{
std::unordered_map<QString, Models::Torrent> m_a {};
};
#include <range/v3/all.hpp>
#include <orm/db.hpp>