Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Re-do the infrastructure in preparation for the MySQL Interface #2

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/actions/setup_cache/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ runs:
using: "composite"
steps:
- name: Cache
uses: actions/cache@v2
uses: actions/cache@v4.0.2
with:
# You might want to add .ccache to your cache configuration?
path: |
Expand Down
36 changes: 19 additions & 17 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ env:
jobs:
Test:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.os == 'macos-13' }}
continue-on-error: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
strategy:
fail-fast: false
# Recommendations:
Expand All @@ -33,9 +33,9 @@ jobs:
os:
- ubuntu-20.04
- ubuntu-22.04
- macos-11
- macos-12
- macos-13
- macos-14
compiler:
# you can specify the version after `-` like "llvm-13.0.0".
- llvm-13.0.0
Expand All @@ -51,12 +51,12 @@ jobs:

exclude:
# mingw is determined by this author to be too buggy to support
- os: macos-11
compiler: gcc-11
- os: macos-12
compiler: gcc-11
- os: macos-13
compiler: gcc-11
- os: macos-14
compiler: gcc-11
- os: ubuntu-20.04
compiler: llvm-13.0.0
- os: ubuntu-22.04
Expand Down Expand Up @@ -121,25 +121,21 @@ jobs:
generator: ${{ matrix.generator }}

- name: Setup Cpp
uses: aminya/setup-cpp@v1
uses: aminya/setup-cpp@v0.37.0
with:
compiler: ${{ matrix.compiler }}
vcvarsall: ${{ contains(matrix.os, 'windows' )}}

cmake: true
ninja: true
conan: true
conan: false
vcpkg: false
ccache: true
clangtidy: ${{ env.CLANG_TIDY_VERSION }}
cppcheck: true
gcovr: true
opencppcoverage: true

- name: Cleanup Conan system packages (they are not properly cached)
run: |
conan remove -f '*/system'

# make sure coverage is only enabled for Debug builds, since it sets -O0 to make sure coverage
# has meaningful results
- name: Configure CMake
Expand All @@ -158,35 +154,41 @@ jobs:
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: |
ctest -C ${{matrix.build_type}} --output-on-failure
ctest -C ${{matrix.build_type}} --output-on-failure -O ../test-result.txt
gcovr -j ${{env.nproc}} --delete --root ../ --print-summary --xml-pretty --xml coverage.xml . --gcov-executable '${{ matrix.gcov_executable }}'

- name: Windows - Test and coverage
if: runner.os == 'Windows' && success()
continue-on-error: ${{ matrix.os == 'macos-13' }}
continue-on-error: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
working-directory: ./build
run: |
OpenCppCoverage.exe --export_type cobertura:coverage.xml --cover_children -- ctest -C ${{matrix.build_type}} --output-on-failure
OpenCppCoverage.exe --export_type cobertura:coverage.xml --cover_children -- ctest -C ${{matrix.build_type}} --output-on-failure -O ../test-result.txt

- name: Archive test results
uses: actions/upload-artifact@v4
with:
name: test-results-${{matrix.os}}-${{matrix.compiler}}-${{matrix.generator}}-${{matrix.build_type}}-${{matrix.developer_mode}}
path: test-result.txt

- name: CPack
if: matrix.package_generator != '' && success()
continue-on-error: ${{ matrix.os == 'macos-13' }}
continue-on-error: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
working-directory: ./build
run: |
cpack -C ${{matrix.build_type}} -G ${{matrix.package_generator}}

- name: Publish Tagged Release
uses: softprops/action-gh-release@v1
if: ${{ startsWith(github.ref, 'refs/tags/') && matrix.package_generator != '' && success() }}
continue-on-error: ${{ matrix.os == 'macos-13' }}
continue-on-error: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
with:
files: |
build/*-*${{ matrix.build_type }}*-*.*


- name: Publish to codecov
if: success()
continue-on-error: ${{ matrix.os == 'macos-13' }}
continue-on-error: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -195,7 +197,7 @@ jobs:
files: ./build/coverage.xml

- name: Raise warning
if: ${{ failure() && matrix.os == 'macos-13' }}
if: ${{ failure() && matrix.os == 'macos-13' || matrix.os == 'macos-14' }}
uses: actions/github-script@v7
with:
script: |
Expand Down
10 changes: 1 addition & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
.vscode/
*.exe
**/*.exe
cmake_install.cmake
CMakeCache.txt
CMakeFiles/
Makefile
mysql-connector-c++-1.1.13/
cmake/
out/
.vs/
.vscode/
WSL_Build/
lib/include/ORM/ORM-version.hpp
build*/
**/.DS_Store
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ endif()
if(RUN_TESTS)
include(CTest)
enable_testing()
add_subdirectory("tests/")

add_subdirectory("tests")
endif()

# Generate example source code
Expand Down
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,27 @@ Check [example/](https://github.com/WebFrame/ORM-Abstract/blob/main/example) for
[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/alex-tsvetanov/)

# ToDo
1. Limits fix
- ```sql
[LIMIT [offset_value] number_rows | LIMIT number_rows OFFSET offset_value]
```
1. Properties
- ``== nullptr``
- ``!= nullptr``
1. Result type
- Member pointers and standard types
- Get references by member pointer
- Get references by table class
- Get references by index
1. Rules
- EXISTS
- IN / NOT IN
1. CRUD operations
- ~~Create / insert~~
- Read / select
- ~~ALL~~
- ~~JOIN~~
- ~~WHERE~~
- ~~LIMIT~~
- DISTINCT / DISTINCTROW
- GROUP BY / HAVING
- ORDER BY
- COUNT(*) / COUNT(...)
```sql
SELECT [ ALL | DISTINCT | DISTINCTROW ]
Expand All @@ -172,16 +180,23 @@ Check [example/](https://github.com/WebFrame/ORM-Abstract/blob/main/example) for
[HAVING condition]
[ORDER BY expression [ ASC | DESC ]]
[LIMIT [offset_value] number_rows | LIMIT number_rows OFFSET offset_value]
INTO [ OUTFILE 'file_name' options
[INTO [ OUTFILE 'file_name' options
| DUMPFILE 'file_name'
| @variable1, @variable2, ... @variable_n]
[FOR UPDATE | LOCK IN SHARE MODE];
```
- Update / update
- ~~WHERE~~
- ORDER BY
- Delete / delete
- WHERE
- ORDER BY
- LIMIT
1. Transferring the abstract database implementation from v1.1 to v2 using the new SQL-free query style
1. Implement free MySQL driver
1. Implement free MongoDB driver
1. Auto-migrating on startup
- Keep track of latest migration done
- Apply new migrations if any
- C++ Migrations tool
1. Run tests with SQL and NoSQL databases
1. Run tests with SQL and NoSQL databases
72 changes: 20 additions & 52 deletions example/ORM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,64 +8,32 @@
using namespace std;
using namespace webframe::ORM::literals;

template <typename T, size_t i> constexpr void create_table_helper()
{
if constexpr (i >= pfr::tuple_size<T>::value)
{
return;
}
if constexpr (std::derived_from<decltype(pfr::get<i>(std::declval<T>())), webframe::ORM::details::property>)
{
constexpr std::string_view column_name = decltype(pfr::get<i>(std::declval<T>()))::_name();
using ColumnType = typename decltype(pfr::get<i>(std::declval<T>()))::var_t;

std::cout << MockDB::MockDB::delim << /*T::table_name << "." <<*/ column_name << " " << typeid(ColumnType).name();
}
if constexpr (i + 1 < pfr::tuple_size<T>::value)
{
std::cout << ",";
create_table_helper<T, i + 1>();
}
}

template <typename T> void create_table()
{
std::cout << "CREATE TABLE " << T::table_name << "(";
create_table_helper<T, 0>();
std::cout << "\n);";
}

#define my_assert(x) \
if (!(x)) \
{ \
std::cout << "\"" << #x << "\" failed." << std::endl; \
}

int main()
{
create_table<User>();
std::cout << std::endl << std::endl;

User alex = webframe::ORM::Table<User>::tuple_to_struct(webframe::ORM::Table<User>::to_tuple((INTEGER<>)(0), (TEXT<>)("Alex")));
my_assert(alex.id == 0);
my_assert(alex.username == "Alex");
User test;
std::cout << test.id.name() << std::endl;
test.id = 5;
std::cout << test.id << std::endl;
test.id += 10;
std::cout << test.id << std::endl;

MockDB::MockDB db;
std::cout << (db << Utils<User>::insert_new_user)("Name") << std::endl;
std::cout << std::endl;
std::cout << (db << Utils<User>::insert_new_user_with_id_placeholder)(5, "Name") << std::endl;
std::cout << std::endl;
std::cout << (db << Utils<User>::insert_new_user_with_id_placeholder)(5, "Name", 6, "alex") << std::endl;
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, decltype(User::insert_new_user_with_name)::parameters_type());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::insert_new_user_with_name.get_columns());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::insert_new_user_with_name.get_values());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::insert_new_user_with_name.get_update_statements());
std::cout << std::endl;
std::cout << (db << Utils<UserPost>::get_all_posts_with_their_assosiated_users)() << std::endl;
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, decltype(User::insert_into_select_test)::parameters_type());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::insert_into_select_test.get_columns());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::insert_into_select_test.get_update_statements());
std::cout << std::endl;
std::cout << (db << Utils<User>::get_all_users_with_id_above)(5) << std::endl;
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::update_test.get_orders());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::update_test.get_limits());
std::cout << std::endl;
std::cout << (db << Utils<User>::update_something)(5, 10) << std::endl;
std::cout << std::endl;
std::cout << (db << Utils<User>::update_with_optimized_rules)(5, 10) << std::endl;
std::cout << std::endl;
std::cout << (db << Utils<UserPost>::delete_all_posts)(5, 5) << std::endl;
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::update_test2.get_orders());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::update_test2.get_limits());
std::cout << std::endl;
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::delete_all.get_orders());
std::apply([](auto&&... args) { ((std::cout << typeid(args).name() << std::endl), ...); }, User::update_test.get_limits());

return 0;
}
74 changes: 74 additions & 0 deletions example/ORM_original.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// ORM.cpp : Defines the entry point for the testing application.
//

#include <iostream>
#include <ORM/ORM.hpp>
#include "users/users.hpp"

using namespace std;
using namespace webframe::ORM::literals;

template <typename T, size_t i> constexpr void create_table_helper()
{
if constexpr (i >= pfr::tuple_size<T>::value)
{
return;
}
if constexpr (std::derived_from<decltype(pfr::get<i>(std::declval<T>())), webframe::ORM::details::property>)
{
constexpr std::string_view column_name = decltype(pfr::get<i>(std::declval<T>()))::_name();
using ColumnType = typename decltype(pfr::get<i>(std::declval<T>()))::var_t;

std::cout << column_name << " " << typeid(ColumnType).name() << std::endl;
}
if constexpr (i + 1 < pfr::tuple_size<T>::value)
{
create_table_helper<T, i + 1>();
}
}

template <typename T> void create_table()
{
create_table_helper<T, 0>();
}

#define my_assert(x) \
if (!(x)) \
{ \
std::cout << "\"" << #x << "\" failed." << std::endl; \
}

int main()
{
std::cout << typeid(P<&UserPost::post> == P<&Post::id>).name();
User test;
std::cout << test.id._name() << std::endl;
test.id = 5;
std::cout << test.id << std::endl;
test.id += 10;
std::cout << test.id << std::endl;
create_table<User>();
my_assert(webframe::ORM::Table<User>::get_index_by_column("id"sv) == 0);
my_assert(webframe::ORM::Table<User>::get_index_by_column("username"sv) == 1);
my_assert(webframe::ORM::Table<User>::get_index_by_column(decltype(std::declval<User>().username)::_name()) == 1);
std::cout << webframe::ORM::Table<User>::get_index_by_column("id"sv) << std::endl;
std::cout << webframe::ORM::Table<User>::get_index_by_column("username"sv) << std::endl;
User alex = webframe::ORM::Table<User>::tuple_to_struct(webframe::ORM::Table<User>::to_tuple(0, "Alex"));
my_assert(alex.id == 0);
my_assert(alex.username == "Alex");
std::cout << alex.id << " " << std::string(alex.username) << std::endl;

webframe::ORM::relationship<webframe::ORM::RelationshipTypes::one2one, &User::id> y;

std::cout << typeid(!(P<&UserPost::author> == P<&User::id> && P<&UserPost::post> == P<&Post::id>)).name() << std::endl;
std::cout << typeid(!((P<&UserPost::author> == P<&User::id>)^(P<&UserPost::post> == P<&Post::id>))).name() << std::endl;
MockDB::MockDB db;
std::cout << (db << Utils<User>::insert_new_user)("Name") << std::endl;
std::cout << (db << Utils<User>::insert_new_user_with_id_placeholder)(5, "Name") << std::endl;
std::cout << (db << Utils<User>::insert_new_user_with_id_placeholder)(5, "Name", 6, "alex") << std::endl;
std::cout << (db << Utils<UserPost>::get_all_posts_with_their_assosiated_users)() << std::endl;
std::cout << (db << Utils<User>::get_all_users_with_id_above)(5) << std::endl;
std::cout << (db << Utils<User>::update_something)(5, 10) << std::endl;
std::cout << (db << Utils<User>::update_with_optimized_rules)(5, 10) << std::endl;
return 0;
}
Loading