From 02ae5a344d36bd05a4af45920425987dc7a8eeaa Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Mon, 17 Jul 2023 23:01:20 +0300 Subject: [PATCH 01/12] Conceptual checks for result value extraction * "row extractor" methods must be const-qualified * Some unit tests for "row extraction" * Replaced two levels of indirection (row extractor builder and "mapped" row extractor) with the simpler `is_mapped` trait. --- dev/arg_values.h | 8 +- dev/mapped_row_extractor.h | 35 --- dev/object_from_column_builder.h | 8 +- dev/pragma.h | 5 +- dev/row_extractor.h | 201 ++++++++----- dev/row_extractor_builder.h | 22 -- dev/storage.h | 39 ++- dev/storage_impl.h | 9 - dev/storage_lookup.h | 3 - dev/values_to_tuple.h | 6 +- examples/blob_binding.cpp | 2 +- examples/chrono_binding.cpp | 25 +- examples/enum_binding.cpp | 8 +- examples/nullable_enum_binding.cpp | 10 +- include/sqlite_orm/sqlite_orm.h | 425 +++++++++++++++------------ tests/CMakeLists.txt | 2 + tests/static_tests/row_extractor.cpp | 95 ++++++ 17 files changed, 532 insertions(+), 371 deletions(-) delete mode 100644 dev/mapped_row_extractor.h delete mode 100644 dev/row_extractor_builder.h create mode 100644 tests/static_tests/row_extractor.cpp diff --git a/dev/arg_values.h b/dev/arg_values.h index 9060460b0..338d2f28b 100644 --- a/dev/arg_values.h +++ b/dev/arg_values.h @@ -6,6 +6,8 @@ namespace sqlite_orm { + /** @short Wrapper around a dynamically typed value object. + */ struct arg_value { arg_value() : arg_value(nullptr) {} @@ -14,7 +16,11 @@ namespace sqlite_orm { template T get() const { - return row_extractor().extract(this->value); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_boxed_value_extractable); +#endif + const row_extractor rowExtractor{}; + return rowExtractor.extract(this->value); } bool is_null() const { diff --git a/dev/mapped_row_extractor.h b/dev/mapped_row_extractor.h deleted file mode 100644 index faf47ecdd..000000000 --- a/dev/mapped_row_extractor.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "object_from_column_builder.h" - -namespace sqlite_orm { - - namespace internal { - - /** - * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. - * Main difference from regular `row_extractor` is that this class takes table info which is required - * for constructing objects by member pointers. To construct please use `make_row_extractor()`. - * Type arguments: - * V is value type just like regular `row_extractor` has - * T is table info class `table_t` - */ - template - struct mapped_row_extractor { - using table_type = Table; - - V extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { - V res; - object_from_column_builder builder{res, stmt}; - this->tableInfo.for_each_column(builder); - return res; - } - - const table_type& tableInfo; - }; - - } - -} diff --git a/dev/object_from_column_builder.h b/dev/object_from_column_builder.h index a613262c6..d76a5910d 100644 --- a/dev/object_from_column_builder.h +++ b/dev/object_from_column_builder.h @@ -20,7 +20,7 @@ namespace sqlite_orm { }; /** - * This is a cute lambda replacement which is used in several places. + * Function object for building an object from a result row. */ template struct object_from_column_builder : object_from_column_builder_base { @@ -33,7 +33,11 @@ namespace sqlite_orm { template void operator()(const column_field& column) { - auto value = row_extractor>().extract(this->stmt, this->index++); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_row_value_extractable>); +#endif + const row_extractor> rowExtractor{}; + auto value = rowExtractor.extract(this->stmt, this->index++); static_if::value>( [&value, &object = this->object](const auto& column) { object.*column.member_pointer = std::move(value); diff --git a/dev/pragma.h b/dev/pragma.h index ba1b03e88..29150a889 100644 --- a/dev/pragma.h +++ b/dev/pragma.h @@ -28,8 +28,9 @@ namespace sqlite_orm { inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { auto& res = *(std::vector*)data; res.reserve(argc); - for(decltype(argc) i = 0; i < argc; ++i) { - auto rowString = row_extractor().extract(argv[i]); + const row_extractor rowExtractor{}; + for(int i = 0; i < argc; ++i) { + auto rowString = rowExtractor.extract(argv[i]); res.push_back(std::move(rowString)); } return 0; diff --git a/dev/row_extractor.h b/dev/row_extractor.h index ed60e596a..eb9344964 100644 --- a/dev/row_extractor.h +++ b/dev/row_extractor.h @@ -25,27 +25,57 @@ namespace sqlite_orm { /** - * Helper class used to cast values from argv to V class - * which depends from column type. - * + * Helper for casting values originating from SQL to C++ typed values, usually from rows of a result set. + * + * sqlite_orm provides specializations for known C++ types, users may define their custom specialization + * of this helper. */ template struct row_extractor { - // used in sqlite3_exec (select) - V extract(const char* row_value) const = delete; - - // used in sqlite_column (iteration, get_all) + /* + * Called during one-step query execution (one result row) for each column of a result row. + */ + V extract(const char* columnText) const = delete; + + /* + * Called during multi-step query execution (result set) for each column of a result row. + */ V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; - // used in user defined functions + /* + * Called before invocation of a user-defined scalar or aggregate functions, + * in order to unpack a boxed "dynamic" function value into a tuple of function arguments. + */ V extract(sqlite3_value* value) const = delete; }; +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + template + concept orm_column_text_extractable = requires(const row_extractor& extractor, const char* columnText) { + { extractor.extract(columnText) } -> std::same_as; + }; + + template + concept orm_row_value_extractable = + requires(const row_extractor& extractor, sqlite3_stmt* stmt, int columnIndex) { + { extractor.extract(stmt, columnIndex) } -> std::same_as; + }; + + template + concept orm_boxed_value_extractable = requires(const row_extractor& extractor, sqlite3_value* value) { + { extractor.extract(value) } -> std::same_as; + }; +#endif + template int extract_single_value(void* data, int argc, char** argv, char**) { auto& res = *(R*)data; if(argc) { - res = row_extractor{}.extract(argv[0]); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_column_text_extractable); +#endif + const row_extractor rowExtractor{}; + res = rowExtractor.extract(argv[0]); } return 0; } @@ -76,12 +106,12 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - V extract(const char* row_value) const { - return this->extract(row_value, tag()); + V extract(const char* colTxt) const { + return this->extract(colTxt, tag()); } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - return this->extract(stmt, columnIndex, tag()); + V extract(sqlite3_stmt* stmt, int colIdx) const { + return this->extract(stmt, colIdx, tag()); } V extract(sqlite3_value* value) const { @@ -91,36 +121,36 @@ namespace sqlite_orm { private: using tag = arithmetic_tag_t; - V extract(const char* row_value, const int_or_smaller_tag&) const { - return static_cast(atoi(row_value)); + V extract(const char* colTxt, const int_or_smaller_tag&) const { + return static_cast(atoi(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { - return static_cast(sqlite3_column_int(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const int_or_smaller_tag&) const { + return static_cast(sqlite3_column_int(stmt, colIdx)); } V extract(sqlite3_value* value, const int_or_smaller_tag&) const { return static_cast(sqlite3_value_int(value)); } - V extract(const char* row_value, const bigint_tag&) const { - return static_cast(atoll(row_value)); + V extract(const char* colTxt, const bigint_tag&) const { + return static_cast(atoll(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { - return static_cast(sqlite3_column_int64(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const bigint_tag&) const { + return static_cast(sqlite3_column_int64(stmt, colIdx)); } V extract(sqlite3_value* value, const bigint_tag&) const { return static_cast(sqlite3_value_int64(value)); } - V extract(const char* row_value, const real_tag&) const { - return static_cast(atof(row_value)); + V extract(const char* colTxt, const real_tag&) const { + return static_cast(atof(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { - return static_cast(sqlite3_column_double(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const real_tag&) const { + return static_cast(sqlite3_column_double(stmt, colIdx)); } V extract(sqlite3_value* value, const real_tag&) const { @@ -131,25 +161,25 @@ namespace sqlite_orm { /** * Specialization for std::string. */ - template<> - struct row_extractor { - std::string extract(const char* row_value) const { - if(row_value) { - return row_value; + template + struct row_extractor::value>> { + T extract(const char* colTxt) const { + if(colTxt) { + return colTxt; } else { return {}; } } - std::string extract(sqlite3_stmt* stmt, int columnIndex) const { - if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { + T extract(sqlite3_stmt* stmt, int colIdx) const { + if(auto cStr = (const char*)sqlite3_column_text(stmt, colIdx)) { return cStr; } else { return {}; } } - std::string extract(sqlite3_value* value) const { + T extract(sqlite3_value* value) const { if(auto cStr = (const char*)sqlite3_value_text(value)) { return cStr; } else { @@ -163,17 +193,17 @@ namespace sqlite_orm { */ template<> struct row_extractor { - std::wstring extract(const char* row_value) const { - if(row_value) { + std::wstring extract(const char* colTxt) const { + if(colTxt) { std::wstring_convert> converter; - return converter.from_bytes(row_value); + return converter.from_bytes(colTxt); } else { return {}; } } - std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { - auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + std::wstring extract(sqlite3_stmt* stmt, int colIdx) const { + auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); if(cStr) { std::wstring_convert> converter; return converter.from_bytes(cStr); @@ -196,27 +226,42 @@ namespace sqlite_orm { struct row_extractor::value>> { using unqualified_type = std::remove_cv_t; - V extract(const char* row_value) const { - if(row_value) { - return is_std_ptr::make(row_extractor().extract(row_value)); + V extract(const char* colTxt) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(colTxt) { + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(colTxt)); } else { return {}; } } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - auto type = sqlite3_column_type(stmt, columnIndex); + V extract(sqlite3_stmt* stmt, int colIdx) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { + auto type = sqlite3_column_type(stmt, colIdx); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(stmt, colIdx)); } else { return {}; } } - V extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(value)); } else { return {}; } @@ -228,27 +273,42 @@ namespace sqlite_orm { struct row_extractor>> { using unqualified_type = std::remove_cv_t; - V extract(const char* row_value) const { - if(row_value) { - return std::make_optional(row_extractor().extract(row_value)); + V extract(const char* colTxt) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(colTxt) { + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(colTxt)); } else { return std::nullopt; } } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - auto type = sqlite3_column_type(stmt, columnIndex); + V extract(sqlite3_stmt* stmt, int colIdx) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { + auto type = sqlite3_column_type(stmt, colIdx); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(stmt, colIdx)); } else { return std::nullopt; } } - V extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(value)); } else { return std::nullopt; } @@ -258,11 +318,11 @@ namespace sqlite_orm { template<> struct row_extractor { - nullptr_t extract(const char* /*row_value*/) const { + nullptr_t extract(const char* /*colTxt*/) const { return nullptr; } - nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { + nullptr_t extract(sqlite3_stmt*, int /*colIdx*/) const { return nullptr; } @@ -275,13 +335,13 @@ namespace sqlite_orm { */ template<> struct row_extractor> { - std::vector extract(const char* row_value) const { - return {row_value, row_value + (row_value ? ::strlen(row_value) : 0)}; + std::vector extract(const char* colTxt) const { + return {colTxt, colTxt + (colTxt ? ::strlen(colTxt) : 0)}; } - std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { - auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); - auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); + std::vector extract(sqlite3_stmt* stmt, int colIdx) const { + auto bytes = static_cast(sqlite3_column_blob(stmt, colIdx)); + auto len = static_cast(sqlite3_column_bytes(stmt, colIdx)); return {bytes, bytes + len}; } @@ -292,6 +352,9 @@ namespace sqlite_orm { } }; + /** + * Specialization for a tuple. + */ template struct row_extractor> { @@ -299,19 +362,19 @@ namespace sqlite_orm { return this->extract(argv, std::make_index_sequence{}); } - std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { + std::tuple extract(sqlite3_stmt* stmt, int /*colIdx*/) const { return this->extract(stmt, std::make_index_sequence{}); } protected: template std::tuple extract(sqlite3_stmt* stmt, std::index_sequence) const { - return std::tuple{row_extractor{}.extract(stmt, Idx)...}; + return {row_extractor{}.extract(stmt, Idx)...}; } template std::tuple extract(char** argv, std::index_sequence) const { - return std::tuple{row_extractor{}.extract(argv[Idx])...}; + return {row_extractor{}.extract(argv[Idx])...}; } }; @@ -320,9 +383,9 @@ namespace sqlite_orm { */ template<> struct row_extractor { - journal_mode extract(const char* row_value) const { - if(row_value) { - if(auto res = internal::journal_mode_from_string(row_value)) { + journal_mode extract(const char* colTxt) const { + if(colTxt) { + if(auto res = internal::journal_mode_from_string(colTxt)) { return std::move(*res); } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; @@ -332,8 +395,8 @@ namespace sqlite_orm { } } - journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { - auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + journal_mode extract(sqlite3_stmt* stmt, int colIdx) const { + auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); return this->extract(cStr); } }; diff --git a/dev/row_extractor_builder.h b/dev/row_extractor_builder.h deleted file mode 100644 index 8ebf796e6..000000000 --- a/dev/row_extractor_builder.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "functional/cxx_universal.h" -#include "row_extractor.h" -#include "mapped_row_extractor.h" - -namespace sqlite_orm { - - namespace internal { - - template - row_extractor make_row_extractor(nullptr_t) { - return {}; - } - - template - mapped_row_extractor make_row_extractor(const Table* table) { - return {*table}; - } - } - -} diff --git a/dev/storage.h b/dev/storage.h index 5cc45d24a..c42971ac2 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -23,7 +23,6 @@ #include "tuple_helper/tuple_iteration.h" #include "type_traits.h" #include "alias.h" -#include "row_extractor_builder.h" #include "error_code.h" #include "type_printer.h" #include "constraints.h" @@ -1358,18 +1357,44 @@ namespace sqlite_orm { perform_step(stmt); } - template> + template, + satisfies = true> + std::vector execute(const prepared_statement_t>& statement) { + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + + std::vector res; + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); + }); + res.shrink_to_fit(); + return res; + } + + template, + satisfies_not = true> std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); std::vector res; - perform_steps(stmt, - [rowExtractor = make_row_extractor(lookup_table(this->db_objects)), - &res](sqlite3_stmt* stmt) { - res.push_back(rowExtractor.extract(stmt, 0)); - }); + perform_steps(stmt, [rowExtractor = row_extractor{}, &res](sqlite3_stmt* stmt) { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_row_value_extractable); +#endif + // note: we always pass in the first index, even though a row extractor + // for a tuple ignores it and does its custom iteration of the result row + res.push_back(rowExtractor.extract(stmt, 0)); + }); res.shrink_to_fit(); return res; } diff --git a/dev/storage_impl.h b/dev/storage_impl.h index 0abbffa54..eb0d8ea07 100644 --- a/dev/storage_impl.h +++ b/dev/storage_impl.h @@ -26,15 +26,6 @@ namespace sqlite_orm { return res; } - template> - auto lookup_table(const DBOs& dbObjects) { - return static_if>( - [](const auto& dbObjects) { - return &pick_table(dbObjects); - }, - empty_callable())(dbObjects); - } - template> decltype(auto) lookup_table_name(const DBOs& dbObjects) { return static_if>( diff --git a/dev/storage_lookup.h b/dev/storage_lookup.h index 75daa650f..3dbe90e5e 100644 --- a/dev/storage_lookup.h +++ b/dev/storage_lookup.h @@ -134,9 +134,6 @@ namespace sqlite_orm { return std::get(dbObjects); } - template = true> - auto lookup_table(const DBOs& dbObjects); - template = true> decltype(auto) lookup_table_name(const DBOs& dbObjects); diff --git a/dev/values_to_tuple.h b/dev/values_to_tuple.h index a85201d9a..f355430ed 100644 --- a/dev/values_to_tuple.h +++ b/dev/values_to_tuple.h @@ -39,7 +39,11 @@ namespace sqlite_orm { #endif template void extract(sqlite3_value* value, T& t) const { - t = row_extractor{}.extract(value); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_boxed_value_extractable); +#endif + const row_extractor rowExtractor{}; + t = rowExtractor.extract(value); } }; } diff --git a/examples/blob_binding.cpp b/examples/blob_binding.cpp index 3979f1cff..2d7e7fffe 100644 --- a/examples/blob_binding.cpp +++ b/examples/blob_binding.cpp @@ -104,7 +104,7 @@ namespace sqlite_orm { template<> struct row_extractor { - Rect extract(sqlite3_stmt* stmt, int columnIndex) { + Rect extract(sqlite3_stmt* stmt, int columnIndex) const { auto blobPointer = sqlite3_column_blob(stmt, columnIndex); auto charPointer = (const char*)blobPointer; Rect value; diff --git a/examples/chrono_binding.cpp b/examples/chrono_binding.cpp index 5400f48d5..d887b8071 100644 --- a/examples/chrono_binding.cpp +++ b/examples/chrono_binding.cpp @@ -98,31 +98,28 @@ namespace sqlite_orm { * This is a reverse operation: here we have to specify a way to transform string received from * database to our sysdays object. Here we call `sysDaysFromString` and throw `std::runtime_error` if it returns null. * Every `row_extractor` specialization must have `extract(const char*)`, `extract(sqlite3_stmt *stmt, int columnIndex)` - * and `extract(sqlite3_value* value)` - * functions which return a mapped type value. + * and `extract(sqlite3_value* value)` functions which cast to a typed value. */ template<> struct row_extractor { - std::chrono::sys_days extract(const char* row_value) const { - if(row_value) { - auto sd = sysDaysFromString(row_value); - if(sd) { - return sd.value(); - } else { - throw std::runtime_error("incorrect date string (" + std::string(row_value) + ")"); - } - } else { - // ! row_value + std::chrono::sys_days extract(const char* columnText) const { + if(!columnText) { throw std::runtime_error("incorrect date string (nullptr)"); } + + if(auto sd = sysDaysFromString(columnText)) { + return sd.value(); + } else { + throw std::runtime_error("incorrect date string (" + std::string(columnText) + ")"); + } } std::chrono::sys_days extract(sqlite3_stmt* stmt, int columnIndex) const { auto str = sqlite3_column_text(stmt, columnIndex); return this->extract((const char*)str); } - std::chrono::sys_days extract(sqlite3_value* row_value) const { - auto characters = (const char*)(sqlite3_value_text(row_value)); + std::chrono::sys_days extract(sqlite3_value* value) const { + auto characters = (const char*)(sqlite3_value_text(value)); return extract(characters); } }; diff --git a/examples/enum_binding.cpp b/examples/enum_binding.cpp index e8164f730..0bee82ca8 100644 --- a/examples/enum_binding.cpp +++ b/examples/enum_binding.cpp @@ -108,15 +108,15 @@ namespace sqlite_orm { */ template<> struct row_extractor { - Gender extract(const char* row_value) { - if(auto gender = GenderFromString(row_value)) { + Gender extract(const char* columnText) const { + if(auto gender = GenderFromString(columnText)) { return *gender; } else { - throw std::runtime_error("incorrect gender string (" + std::string(row_value) + ")"); + throw std::runtime_error("incorrect gender string (" + std::string(columnText) + ")"); } } - Gender extract(sqlite3_stmt* stmt, int columnIndex) { + Gender extract(sqlite3_stmt* stmt, int columnIndex) const { auto str = sqlite3_column_text(stmt, columnIndex); return this->extract((const char*)str); } diff --git a/examples/nullable_enum_binding.cpp b/examples/nullable_enum_binding.cpp index 8625af059..375097144 100644 --- a/examples/nullable_enum_binding.cpp +++ b/examples/nullable_enum_binding.cpp @@ -76,19 +76,19 @@ namespace sqlite_orm { template<> struct row_extractor { - Gender extract(const char* row_value) { - if(row_value) { - if(auto gender = GenderFromString(row_value)) { + Gender extract(const char* columnText) const { + if(columnText) { + if(auto gender = GenderFromString(columnText)) { return *gender; } else { - throw std::runtime_error("incorrect gender string (" + std::string(row_value) + ")"); + throw std::runtime_error("incorrect gender string (" + std::string(columnText) + ")"); } } else { return Gender::None; } } - Gender extract(sqlite3_stmt* stmt, int columnIndex) { + Gender extract(sqlite3_stmt* stmt, int columnIndex) const { auto str = sqlite3_column_text(stmt, columnIndex); return this->extract((const char*)str); } diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 5fcda838b..ec39ad599 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8635,27 +8635,57 @@ namespace sqlite_orm { namespace sqlite_orm { /** - * Helper class used to cast values from argv to V class - * which depends from column type. - * + * Helper for casting values originating from SQL to C++ typed values, usually from rows of a result set. + * + * sqlite_orm provides specializations for known C++ types, users may define their custom specialization + * of this helper. */ template struct row_extractor { - // used in sqlite3_exec (select) - V extract(const char* row_value) const = delete; + /* + * Called during one-step query execution (one result row) for each column of a result row. + */ + V extract(const char* columnText) const = delete; - // used in sqlite_column (iteration, get_all) + /* + * Called during multi-step query execution (result set) for each column of a result row. + */ V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; - // used in user defined functions + /* + * Called before invocation of a user-defined scalar or aggregate functions, + * in order to unpack a boxed "dynamic" function value into a tuple of function arguments. + */ V extract(sqlite3_value* value) const = delete; }; +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + template + concept orm_column_text_extractable = requires(const row_extractor& extractor, const char* columnText) { + { extractor.extract(columnText) } -> std::same_as; + }; + + template + concept orm_row_value_extractable = + requires(const row_extractor& extractor, sqlite3_stmt* stmt, int columnIndex) { + { extractor.extract(stmt, columnIndex) } -> std::same_as; + }; + + template + concept orm_boxed_value_extractable = requires(const row_extractor& extractor, sqlite3_value* value) { + { extractor.extract(value) } -> std::same_as; + }; +#endif + template int extract_single_value(void* data, int argc, char** argv, char**) { auto& res = *(R*)data; if(argc) { - res = row_extractor{}.extract(argv[0]); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_column_text_extractable); +#endif + const row_extractor rowExtractor{}; + res = rowExtractor.extract(argv[0]); } return 0; } @@ -8686,12 +8716,12 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - V extract(const char* row_value) const { - return this->extract(row_value, tag()); + V extract(const char* colTxt) const { + return this->extract(colTxt, tag()); } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - return this->extract(stmt, columnIndex, tag()); + V extract(sqlite3_stmt* stmt, int colIdx) const { + return this->extract(stmt, colIdx, tag()); } V extract(sqlite3_value* value) const { @@ -8701,36 +8731,36 @@ namespace sqlite_orm { private: using tag = arithmetic_tag_t; - V extract(const char* row_value, const int_or_smaller_tag&) const { - return static_cast(atoi(row_value)); + V extract(const char* colTxt, const int_or_smaller_tag&) const { + return static_cast(atoi(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { - return static_cast(sqlite3_column_int(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const int_or_smaller_tag&) const { + return static_cast(sqlite3_column_int(stmt, colIdx)); } V extract(sqlite3_value* value, const int_or_smaller_tag&) const { return static_cast(sqlite3_value_int(value)); } - V extract(const char* row_value, const bigint_tag&) const { - return static_cast(atoll(row_value)); + V extract(const char* colTxt, const bigint_tag&) const { + return static_cast(atoll(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { - return static_cast(sqlite3_column_int64(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const bigint_tag&) const { + return static_cast(sqlite3_column_int64(stmt, colIdx)); } V extract(sqlite3_value* value, const bigint_tag&) const { return static_cast(sqlite3_value_int64(value)); } - V extract(const char* row_value, const real_tag&) const { - return static_cast(atof(row_value)); + V extract(const char* colTxt, const real_tag&) const { + return static_cast(atof(colTxt)); } - V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { - return static_cast(sqlite3_column_double(stmt, columnIndex)); + V extract(sqlite3_stmt* stmt, int colIdx, const real_tag&) const { + return static_cast(sqlite3_column_double(stmt, colIdx)); } V extract(sqlite3_value* value, const real_tag&) const { @@ -8741,25 +8771,25 @@ namespace sqlite_orm { /** * Specialization for std::string. */ - template<> - struct row_extractor { - std::string extract(const char* row_value) const { - if(row_value) { - return row_value; + template + struct row_extractor::value>> { + T extract(const char* colTxt) const { + if(colTxt) { + return colTxt; } else { return {}; } } - std::string extract(sqlite3_stmt* stmt, int columnIndex) const { - if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { + T extract(sqlite3_stmt* stmt, int colIdx) const { + if(auto cStr = (const char*)sqlite3_column_text(stmt, colIdx)) { return cStr; } else { return {}; } } - std::string extract(sqlite3_value* value) const { + T extract(sqlite3_value* value) const { if(auto cStr = (const char*)sqlite3_value_text(value)) { return cStr; } else { @@ -8773,17 +8803,17 @@ namespace sqlite_orm { */ template<> struct row_extractor { - std::wstring extract(const char* row_value) const { - if(row_value) { + std::wstring extract(const char* colTxt) const { + if(colTxt) { std::wstring_convert> converter; - return converter.from_bytes(row_value); + return converter.from_bytes(colTxt); } else { return {}; } } - std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { - auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + std::wstring extract(sqlite3_stmt* stmt, int colIdx) const { + auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); if(cStr) { std::wstring_convert> converter; return converter.from_bytes(cStr); @@ -8806,27 +8836,42 @@ namespace sqlite_orm { struct row_extractor::value>> { using unqualified_type = std::remove_cv_t; - V extract(const char* row_value) const { - if(row_value) { - return is_std_ptr::make(row_extractor().extract(row_value)); + V extract(const char* colTxt) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(colTxt) { + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(colTxt)); } else { return {}; } } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - auto type = sqlite3_column_type(stmt, columnIndex); + V extract(sqlite3_stmt* stmt, int colIdx) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { + auto type = sqlite3_column_type(stmt, colIdx); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(stmt, colIdx)); } else { return {}; } } - V extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return is_std_ptr::make(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return is_std_ptr::make(rowExtractor.extract(value)); } else { return {}; } @@ -8838,27 +8883,42 @@ namespace sqlite_orm { struct row_extractor>> { using unqualified_type = std::remove_cv_t; - V extract(const char* row_value) const { - if(row_value) { - return std::make_optional(row_extractor().extract(row_value)); + V extract(const char* colTxt) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + { + if(colTxt) { + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(colTxt)); } else { return std::nullopt; } } - V extract(sqlite3_stmt* stmt, int columnIndex) const { - auto type = sqlite3_column_type(stmt, columnIndex); + V extract(sqlite3_stmt* stmt, int colIdx) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + { + auto type = sqlite3_column_type(stmt, colIdx); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(stmt, columnIndex)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(stmt, colIdx)); } else { return std::nullopt; } } - V extract(sqlite3_value* value) const { + V extract(sqlite3_value* value) const +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { - return std::make_optional(row_extractor().extract(value)); + const row_extractor rowExtractor{}; + return std::make_optional(rowExtractor.extract(value)); } else { return std::nullopt; } @@ -8868,11 +8928,11 @@ namespace sqlite_orm { template<> struct row_extractor { - nullptr_t extract(const char* /*row_value*/) const { + nullptr_t extract(const char* /*colTxt*/) const { return nullptr; } - nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { + nullptr_t extract(sqlite3_stmt*, int /*colIdx*/) const { return nullptr; } @@ -8885,13 +8945,13 @@ namespace sqlite_orm { */ template<> struct row_extractor> { - std::vector extract(const char* row_value) const { - return {row_value, row_value + (row_value ? ::strlen(row_value) : 0)}; + std::vector extract(const char* colTxt) const { + return {colTxt, colTxt + (colTxt ? ::strlen(colTxt) : 0)}; } - std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { - auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); - auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); + std::vector extract(sqlite3_stmt* stmt, int colIdx) const { + auto bytes = static_cast(sqlite3_column_blob(stmt, colIdx)); + auto len = static_cast(sqlite3_column_bytes(stmt, colIdx)); return {bytes, bytes + len}; } @@ -8902,6 +8962,9 @@ namespace sqlite_orm { } }; + /** + * Specialization for a tuple. + */ template struct row_extractor> { @@ -8909,19 +8972,19 @@ namespace sqlite_orm { return this->extract(argv, std::make_index_sequence{}); } - std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { + std::tuple extract(sqlite3_stmt* stmt, int /*colIdx*/) const { return this->extract(stmt, std::make_index_sequence{}); } protected: template std::tuple extract(sqlite3_stmt* stmt, std::index_sequence) const { - return std::tuple{row_extractor{}.extract(stmt, Idx)...}; + return {row_extractor{}.extract(stmt, Idx)...}; } template std::tuple extract(char** argv, std::index_sequence) const { - return std::tuple{row_extractor{}.extract(argv[Idx])...}; + return {row_extractor{}.extract(argv[Idx])...}; } }; @@ -8930,9 +8993,9 @@ namespace sqlite_orm { */ template<> struct row_extractor { - journal_mode extract(const char* row_value) const { - if(row_value) { - if(auto res = internal::journal_mode_from_string(row_value)) { + journal_mode extract(const char* colTxt) const { + if(colTxt) { + if(auto res = internal::journal_mode_from_string(colTxt)) { return std::move(*res); } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; @@ -8942,8 +9005,8 @@ namespace sqlite_orm { } } - journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { - auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); + journal_mode extract(sqlite3_stmt* stmt, int colIdx) const { + auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); return this->extract(cStr); } }; @@ -10040,9 +10103,6 @@ namespace sqlite_orm { return std::get(dbObjects); } - template = true> - auto lookup_table(const DBOs& dbObjects); - template = true> decltype(auto) lookup_table_name(const DBOs& dbObjects); @@ -10065,15 +10125,6 @@ namespace sqlite_orm { return res; } - template> - auto lookup_table(const DBOs& dbObjects) { - return static_if>( - [](const auto& dbObjects) { - return &pick_table(dbObjects); - }, - empty_callable())(dbObjects); - } - template> decltype(auto) lookup_table_name(const DBOs& dbObjects) { return static_if>( @@ -10175,112 +10226,6 @@ namespace sqlite_orm { // #include "alias.h" -// #include "row_extractor_builder.h" - -// #include "functional/cxx_universal.h" - -// #include "row_extractor.h" - -// #include "mapped_row_extractor.h" - -#include - -// #include "object_from_column_builder.h" - -#include -#include // std::is_member_object_pointer - -// #include "functional/static_magic.h" - -// #include "row_extractor.h" - -namespace sqlite_orm { - - namespace internal { - - struct object_from_column_builder_base { - sqlite3_stmt* stmt = nullptr; - int index = 0; - -#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED - object_from_column_builder_base(sqlite3_stmt* stmt) : stmt{stmt} {} -#endif - }; - - /** - * This is a cute lambda replacement which is used in several places. - */ - template - struct object_from_column_builder : object_from_column_builder_base { - using object_type = O; - - object_type& object; - - object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : - object_from_column_builder_base{stmt_}, object(object_) {} - - template - void operator()(const column_field& column) { - auto value = row_extractor>().extract(this->stmt, this->index++); - static_if::value>( - [&value, &object = this->object](const auto& column) { - object.*column.member_pointer = std::move(value); - }, - [&value, &object = this->object](const auto& column) { - (object.*column.setter)(std::move(value)); - })(column); - } - }; - } -} - -namespace sqlite_orm { - - namespace internal { - - /** - * This is a private row extractor class. It is used for extracting rows as objects instead of tuple. - * Main difference from regular `row_extractor` is that this class takes table info which is required - * for constructing objects by member pointers. To construct please use `make_row_extractor()`. - * Type arguments: - * V is value type just like regular `row_extractor` has - * T is table info class `table_t` - */ - template - struct mapped_row_extractor { - using table_type = Table; - - V extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { - V res; - object_from_column_builder builder{res, stmt}; - this->tableInfo.for_each_column(builder); - return res; - } - - const table_type& tableInfo; - }; - - } - -} - -namespace sqlite_orm { - - namespace internal { - - template - row_extractor make_row_extractor(nullptr_t) { - return {}; - } - - template - mapped_row_extractor make_row_extractor(const Table* table) { - return {*table}; - } - } - -} - // #include "error_code.h" // #include "type_printer.h" @@ -10999,6 +10944,57 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" +#include +#include // std::is_member_object_pointer + +// #include "functional/static_magic.h" + +// #include "row_extractor.h" + +namespace sqlite_orm { + + namespace internal { + + struct object_from_column_builder_base { + sqlite3_stmt* stmt = nullptr; + int index = 0; + +#ifndef SQLITE_ORM_AGGREGATE_NSDMI_SUPPORTED + object_from_column_builder_base(sqlite3_stmt* stmt) : stmt{stmt} {} +#endif + }; + + /** + * Function object for building an object from a result row. + */ + template + struct object_from_column_builder : object_from_column_builder_base { + using object_type = O; + + object_type& object; + + object_from_column_builder(object_type& object_, sqlite3_stmt* stmt_) : + object_from_column_builder_base{stmt_}, object(object_) {} + + template + void operator()(const column_field& column) { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_row_value_extractable>); +#endif + const row_extractor> rowExtractor{}; + auto value = rowExtractor.extract(this->stmt, this->index++); + static_if::value>( + [&value, &object = this->object](const auto& column) { + object.*column.member_pointer = std::move(value); + }, + [&value, &object = this->object](const auto& column) { + (object.*column.setter)(std::move(value)); + })(column); + } + }; + } +} + // #include "storage_lookup.h" // #include "util.h" @@ -13456,8 +13452,9 @@ namespace sqlite_orm { inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { auto& res = *(std::vector*)data; res.reserve(argc); - for(decltype(argc) i = 0; i < argc; ++i) { - auto rowString = row_extractor().extract(argv[i]); + const row_extractor rowExtractor{}; + for(int i = 0; i < argc; ++i) { + auto rowString = rowExtractor.extract(argv[i]); res.push_back(std::move(rowString)); } return 0; @@ -13974,6 +13971,8 @@ namespace sqlite_orm { namespace sqlite_orm { + /** @short Wrapper around a dynamically typed value object. + */ struct arg_value { arg_value() : arg_value(nullptr) {} @@ -13982,7 +13981,11 @@ namespace sqlite_orm { template T get() const { - return row_extractor().extract(this->value); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_boxed_value_extractable); +#endif + const row_extractor rowExtractor{}; + return rowExtractor.extract(this->value); } bool is_null() const { @@ -14143,7 +14146,11 @@ namespace sqlite_orm { #endif template void extract(sqlite3_value* value, T& t) const { - t = row_extractor{}.extract(value); +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_boxed_value_extractable); +#endif + const row_extractor rowExtractor{}; + t = rowExtractor.extract(value); } }; } @@ -18614,18 +18621,44 @@ namespace sqlite_orm { perform_step(stmt); } - template> + template, + satisfies = true> + std::vector execute(const prepared_statement_t>& statement) { + sqlite3_stmt* stmt = reset_stmt(statement.stmt); + + iterate_ast(statement.expression, conditional_binder{stmt}); + + std::vector res; + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); + }); + res.shrink_to_fit(); + return res; + } + + template, + satisfies_not = true> std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); std::vector res; - perform_steps(stmt, - [rowExtractor = make_row_extractor(lookup_table(this->db_objects)), - &res](sqlite3_stmt* stmt) { - res.push_back(rowExtractor.extract(stmt, 0)); - }); + perform_steps(stmt, [rowExtractor = row_extractor{}, &res](sqlite3_stmt* stmt) { +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + static_assert(orm_row_value_extractable); +#endif + // note: we always pass in the first index, even though a row extractor + // for a tuple ignores it and does its custom iteration of the result row + res.push_back(rowExtractor.extract(stmt, 0)); + }); res.shrink_to_fit(); return res; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fbf3df81e..8b7366452 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(unit_tests static_tests/functional/tuple_transform.cpp static_tests/is_printable.cpp static_tests/is_bindable.cpp + static_tests/row_extractor.cpp static_tests/iterator_t.cpp static_tests/arithmetic_operators_result_type.cpp static_tests/node_tuple.cpp @@ -133,6 +134,7 @@ add_executable(unit_tests ast_iterator_tests.cpp table_name_collector.cpp pointer_passing_interface.cpp + row_extractor.cpp ) if(SQLITE_ORM_OMITS_CODECVT) diff --git a/tests/static_tests/row_extractor.cpp b/tests/static_tests/row_extractor.cpp new file mode 100644 index 000000000..28e74a46d --- /dev/null +++ b/tests/static_tests/row_extractor.cpp @@ -0,0 +1,95 @@ +#include +#include +#include // std::unique_ptr, std::shared_ptr +#include // std::string +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +#include // std::optional +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED +#include +#endif + +using namespace sqlite_orm; + +template +static void check_extractable() { + STATIC_CHECK(orm_column_text_extractable); + STATIC_CHECK(orm_row_value_extractable); + STATIC_CHECK(orm_boxed_value_extractable); +} + +template +static void check_not_extractable() { + STATIC_CHECK_FALSE(orm_column_text_extractable); + STATIC_CHECK_FALSE(orm_row_value_extractable); + STATIC_CHECK_FALSE(orm_boxed_value_extractable); +} + +namespace { + enum class custom_enum {}; + + template + class StringVeneer : public std::basic_string {}; + + struct User { + int id; + }; +} + +template<> +struct sqlite_orm::row_extractor { + custom_enum extract(const char* /*columnText*/) const {} + custom_enum extract(sqlite3_stmt*, int /*columnIndex*/) const {} + custom_enum extract(sqlite3_value*) const {} +}; + +TEST_CASE("is_extractable") { + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_extractable(); + check_not_extractable(); + check_extractable(); + check_extractable>(); +#ifndef SQLITE_ORM_OMITS_CODECVT + check_not_extractable(); + check_extractable(); + check_not_extractable>(); +#endif + check_extractable(); + check_extractable>(); + check_extractable>(); +#ifdef SQLITE_ORM_STRING_VIEW_SUPPORTED + check_not_extractable(); +#ifndef SQLITE_ORM_OMITS_CODECVT + check_not_extractable(); +#endif +#endif +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED + check_not_extractable(); + check_extractable>(); + check_extractable>(); + check_not_extractable>(); +#endif // SQLITE_ORM_OPTIONAL_SUPPORTED +#ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED + check_not_extractable>(); +#endif + + check_extractable(); + check_extractable>(); + + check_not_extractable(); + check_not_extractable>(); + check_not_extractable(); + check_not_extractable>(); +} From 1bbe31e7a4d1a904398e8e275103638da213ee22 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 17:06:27 +0300 Subject: [PATCH 02/12] Named factory functions that check concepts for row extraction --- dev/arg_values.h | 5 +- dev/object_from_column_builder.h | 5 +- dev/pragma.h | 2 +- dev/row_extractor.h | 55 +++++- dev/storage.h | 37 ++-- dev/values_to_tuple.h | 5 +- include/sqlite_orm/sqlite_orm.h | 275 ++++++++++++++++++++++----- tests/static_tests/row_extractor.cpp | 7 + tests/tests.cpp | 8 + 9 files changed, 312 insertions(+), 87 deletions(-) diff --git a/dev/arg_values.h b/dev/arg_values.h index 338d2f28b..515a1b12f 100644 --- a/dev/arg_values.h +++ b/dev/arg_values.h @@ -16,10 +16,7 @@ namespace sqlite_orm { template T get() const { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_boxed_value_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = internal::boxed_value_extractor(); return rowExtractor.extract(this->value); } diff --git a/dev/object_from_column_builder.h b/dev/object_from_column_builder.h index d76a5910d..a3e82f4f3 100644 --- a/dev/object_from_column_builder.h +++ b/dev/object_from_column_builder.h @@ -33,10 +33,7 @@ namespace sqlite_orm { template void operator()(const column_field& column) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_row_value_extractable>); -#endif - const row_extractor> rowExtractor{}; + const auto rowExtractor = row_value_extractor>(); auto value = rowExtractor.extract(this->stmt, this->index++); static_if::value>( [&value, &object = this->object](const auto& column) { diff --git a/dev/pragma.h b/dev/pragma.h index 29150a889..37de02201 100644 --- a/dev/pragma.h +++ b/dev/pragma.h @@ -28,7 +28,7 @@ namespace sqlite_orm { inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { auto& res = *(std::vector*)data; res.reserve(argc); - const row_extractor rowExtractor{}; + const auto rowExtractor = column_text_extractor(); for(int i = 0; i < argc; ++i) { auto rowString = rowExtractor.extract(argv[i]); res.push_back(std::move(rowString)); diff --git a/dev/row_extractor.h b/dev/row_extractor.h index eb9344964..ebf7eb937 100644 --- a/dev/row_extractor.h +++ b/dev/row_extractor.h @@ -29,6 +29,13 @@ namespace sqlite_orm { * * sqlite_orm provides specializations for known C++ types, users may define their custom specialization * of this helper. + * + * @note (internal): Since row extractors are used in certain contexts with only one purpose at a time + * (e.g., converting a row result set but not function values or column text), + * there are factory functions that perform conceptual checking that should be used + * instead of directly creating row extractors. + * + * */ template struct row_extractor { @@ -43,8 +50,8 @@ namespace sqlite_orm { V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; /* - * Called before invocation of a user-defined scalar or aggregate functions, - * in order to unpack a boxed "dynamic" function value into a tuple of function arguments. + * Called before invocation of user-defined scalar or aggregate functions, + * in order to unbox dynamically typed SQL function values into a tuple of C++ function arguments. */ V extract(sqlite3_value* value) const = delete; }; @@ -67,14 +74,46 @@ namespace sqlite_orm { }; #endif + namespace internal { + /* + * Make a row extractor to be used for casting SQL column text to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + row_extractor column_text_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for converting a value from a SQL result row set to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + row_extractor row_value_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for unboxing a dynamically typed SQL value to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + row_extractor boxed_value_extractor() { + return {}; + } + } + template int extract_single_value(void* data, int argc, char** argv, char**) { auto& res = *(R*)data; if(argc) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_column_text_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = internal::column_text_extractor(); res = rowExtractor.extract(argv[0]); } return 0; @@ -90,6 +129,10 @@ namespace sqlite_orm { struct row_extractor, void> { using V = pointer_arg; + V extract(const char* columnText) const = delete; + + V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; + V extract(sqlite3_value* value) const { return {(P*)sqlite3_value_pointer(value, T::value)}; } diff --git a/dev/storage.h b/dev/storage.h index c42971ac2..5cc8e196b 100644 --- a/dev/storage.h +++ b/dev/storage.h @@ -1359,19 +1359,18 @@ namespace sqlite_orm { template, - satisfies = true> - std::vector execute(const prepared_statement_t>& statement) { + class R = column_result_of_t, + satisfies_not = true> + std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); - std::vector res; - perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { - O obj; - object_from_column_builder builder{obj, stmt}; - table.for_each_column(builder); - res.push_back(std::move(obj)); + std::vector res; + perform_steps(stmt, [rowExtractor = row_value_extractor(), &res](sqlite3_stmt* stmt) { + // note: we always pass in the first index, even though a row extractor + // for a tuple ignores it and does its custom iteration of the result row + res.push_back(rowExtractor.extract(stmt, 0)); }); res.shrink_to_fit(); return res; @@ -1379,21 +1378,19 @@ namespace sqlite_orm { template, - satisfies_not = true> - std::vector execute(const prepared_statement_t>& statement) { + class O = column_result_of_t, + satisfies = true> + std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); - std::vector res; - perform_steps(stmt, [rowExtractor = row_extractor{}, &res](sqlite3_stmt* stmt) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_row_value_extractable); -#endif - // note: we always pass in the first index, even though a row extractor - // for a tuple ignores it and does its custom iteration of the result row - res.push_back(rowExtractor.extract(stmt, 0)); + std::vector res; + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); }); res.shrink_to_fit(); return res; diff --git a/dev/values_to_tuple.h b/dev/values_to_tuple.h index f355430ed..f5a477f6f 100644 --- a/dev/values_to_tuple.h +++ b/dev/values_to_tuple.h @@ -39,10 +39,7 @@ namespace sqlite_orm { #endif template void extract(sqlite3_value* value, T& t) const { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_boxed_value_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = boxed_value_extractor(); t = rowExtractor.extract(value); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index ec39ad599..da2a09437 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10,6 +10,7 @@ __pragma(push_macro("max")) // #include "cxx_universal.h" + /* * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations @@ -28,6 +29,7 @@ using std::nullptr_t; // #include "cxx_core_features.h" + /* * This header detects core C++ language features on which sqlite_orm depends. * May be updated/overwritten by cxx_compiler_quirks.h @@ -108,6 +110,7 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" + /* * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. * May amend cxx_core_features.h @@ -167,6 +170,8 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS #endif + + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -211,6 +216,7 @@ using std::nullptr_t; // #include "cxx_universal.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -352,6 +358,7 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } + namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -588,8 +595,10 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -598,6 +607,7 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif + // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -634,6 +644,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { /** @@ -732,6 +743,7 @@ namespace sqlite_orm { // #include "functional/mpl.h" + /* * Symbols for 'template metaprogramming' (compile-time template programming), * inspired by the MPL of Aleksey Gurtovoy and David Abrahams. @@ -760,6 +772,7 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { namespace mpl { @@ -1045,6 +1058,7 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" + namespace sqlite_orm { namespace internal { @@ -1074,6 +1088,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" + #include // std::is_same #include @@ -1081,6 +1096,7 @@ namespace sqlite_orm { // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { /* @@ -1129,6 +1145,7 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" + #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1136,10 +1153,12 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" + #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" + namespace sqlite_orm { namespace internal { /** @@ -1169,6 +1188,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -1260,6 +1280,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -1304,6 +1325,7 @@ namespace sqlite_orm { // #include "type_printer.h" + namespace sqlite_orm { namespace internal { @@ -1829,8 +1851,10 @@ namespace sqlite_orm { #include // std::shared_ptr, std::unique_ptr // #include "functional/cxx_optional.h" + // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { /** @@ -1871,6 +1895,7 @@ namespace sqlite_orm { // #include "tags.h" + namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1884,10 +1909,13 @@ namespace sqlite_orm { // #include "serialize_result_type.h" + // #include "functional/cxx_string_view.h" + // #include "cxx_core_features.h" + #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -1912,6 +1940,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -2200,12 +2229,14 @@ namespace sqlite_orm { // #include "member_traits/member_traits.h" + #include // std::enable_if, std::is_function, std::true_type, std::false_type // #include "../functional/cxx_universal.h" // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { // SFINAE friendly trait to get a member object pointer's field type @@ -2297,6 +2328,7 @@ namespace sqlite_orm { // #include "constraints.h" + namespace sqlite_orm { namespace internal { @@ -2477,12 +2509,14 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OMITS_CODECVT // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -2647,6 +2681,7 @@ namespace sqlite_orm { // #include "is_base_of_template.h" + #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -2692,6 +2727,7 @@ namespace sqlite_orm { // #include "optional_container.h" + namespace sqlite_orm { namespace internal { @@ -2726,6 +2762,7 @@ namespace sqlite_orm { // #include "serializer_context.h" + namespace sqlite_orm { namespace internal { @@ -2767,6 +2804,7 @@ namespace sqlite_orm { // #include "alias_traits.h" + #include // std::remove_const, std::is_base_of, std::is_same #ifdef SQLITE_ORM_WITH_CPP20_ALIASES #include @@ -2778,6 +2816,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { /** @short Base class for a custom table alias, column alias or expression alias. @@ -2856,14 +2895,17 @@ namespace sqlite_orm { // #include "expression.h" + #include #include // std::move, std::forward // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "operators.h" + namespace sqlite_orm { namespace internal { @@ -2945,6 +2987,7 @@ namespace sqlite_orm { // #include "literal.h" + namespace sqlite_orm { namespace internal { @@ -2961,6 +3004,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -4198,13 +4242,14 @@ namespace sqlite_orm { #include // std::copy_n // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" // #include "alias_traits.h" + namespace sqlite_orm { namespace internal { @@ -4530,8 +4575,10 @@ namespace sqlite_orm { // #include "ast/into.h" + // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -4550,6 +4597,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { using int64 = sqlite_int64; @@ -6662,6 +6710,7 @@ namespace sqlite_orm { #include // std::tuple, std::get, std::tuple_size // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" @@ -6674,6 +6723,7 @@ namespace sqlite_orm { // #include "ast/where.h" + #include // std::false_type, std::true_type #include // std::move @@ -6683,6 +6733,7 @@ namespace sqlite_orm { // #include "../serialize_result_type.h" + namespace sqlite_orm { namespace internal { @@ -6730,12 +6781,14 @@ namespace sqlite_orm { // #include "ast/group_by.h" + #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -6784,6 +6837,7 @@ namespace sqlite_orm { // #include "column_pointer.h" + #include // std::string #include // std::move @@ -6793,6 +6847,7 @@ namespace sqlite_orm { // #include "alias_traits.h" + namespace sqlite_orm { namespace internal { /** @@ -6847,6 +6902,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -7280,6 +7336,7 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" + namespace sqlite_orm { struct table_info { @@ -7337,6 +7394,7 @@ namespace sqlite_orm { // #include "optional_container.h" + // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? // (Could be implemented with a normal trigger that insert or update an internal table and then retreive // the event in the C++ code, to call the C++ user callback, with update hooks: https://www.sqlite.org/c3ref/update_hook.html) @@ -7660,6 +7718,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" + #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7669,6 +7728,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7910,6 +7970,7 @@ namespace sqlite_orm { #endif } + namespace sqlite_orm { /** @@ -8106,6 +8167,7 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" + namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8189,6 +8251,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { /** @@ -8556,6 +8619,7 @@ namespace sqlite_orm { // #include "journal_mode.h" + #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8632,6 +8696,7 @@ namespace sqlite_orm { // #include "is_std_ptr.h" + namespace sqlite_orm { /** @@ -8639,6 +8704,13 @@ namespace sqlite_orm { * * sqlite_orm provides specializations for known C++ types, users may define their custom specialization * of this helper. + * + * @note (internal): Since row extractors are used in certain contexts with only one purpose at a time + * (e.g., converting a row result set but not function values or column text), + * there are factory functions that perform conceptual checking that should be used + * instead of directly creating row extractors. + * + * */ template struct row_extractor { @@ -8653,8 +8725,8 @@ namespace sqlite_orm { V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; /* - * Called before invocation of a user-defined scalar or aggregate functions, - * in order to unpack a boxed "dynamic" function value into a tuple of function arguments. + * Called before invocation of user-defined scalar or aggregate functions, + * in order to unbox dynamically typed SQL function values into a tuple of C++ function arguments. */ V extract(sqlite3_value* value) const = delete; }; @@ -8677,14 +8749,46 @@ namespace sqlite_orm { }; #endif + namespace internal { + /* + * Make a row extractor to be used for casting SQL column text to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_column_text_extractable) +#endif + row_extractor column_text_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for converting a value from a SQL result row set to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_row_value_extractable) +#endif + row_extractor row_value_extractor() { + return {}; + } + + /* + * Make a row extractor to be used for unboxing a dynamically typed SQL value to a C++ typed value. + */ + template +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED + requires(orm_boxed_value_extractable) +#endif + row_extractor boxed_value_extractor() { + return {}; + } + } + template int extract_single_value(void* data, int argc, char** argv, char**) { auto& res = *(R*)data; if(argc) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_column_text_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = internal::column_text_extractor(); res = rowExtractor.extract(argv[0]); } return 0; @@ -8700,6 +8804,10 @@ namespace sqlite_orm { struct row_extractor, void> { using V = pointer_arg; + V extract(const char* columnText) const = delete; + + V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; + V extract(sqlite3_value* value) const { return {(P*)sqlite3_value_pointer(value, T::value)}; } @@ -9019,6 +9127,7 @@ namespace sqlite_orm { // #include "error_code.h" + namespace sqlite_orm { /** @@ -9214,6 +9323,7 @@ namespace sqlite_orm { // #include "indexed_column.h" + #include // std::string #include // std::move @@ -9221,6 +9331,7 @@ namespace sqlite_orm { // #include "ast/where.h" + namespace sqlite_orm { namespace internal { @@ -9286,6 +9397,7 @@ namespace sqlite_orm { // #include "table_type_of.h" + namespace sqlite_orm { namespace internal { @@ -9424,13 +9536,14 @@ namespace sqlite_orm { #include // std::forward, std::move // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "functional/cxx_functional_polyfill.h" // #include "functional/static_magic.h" + #ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant #endif @@ -9515,16 +9628,18 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" + #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::remove_reference, std::index_sequence, std::make_index_sequence #include // std::forward, std::move // #include "../functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -9663,6 +9778,7 @@ namespace sqlite_orm { // #include "column.h" + namespace sqlite_orm { namespace internal { @@ -9954,7 +10070,7 @@ namespace sqlite_orm { #include // std::string // #include "functional/cxx_universal.h" -// ::nullptr_t + // ::nullptr_t // #include "functional/static_magic.h" // #include "tuple_helper/tuple_filter.h" @@ -9967,6 +10083,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + #include // std::true_type, std::false_type, std::remove_const, std::enable_if, std::is_base_of, std::is_void #include #include // std::index_sequence, std::make_index_sequence @@ -9977,6 +10094,7 @@ namespace sqlite_orm { // #include "type_traits.h" + namespace sqlite_orm { namespace internal { @@ -10109,6 +10227,7 @@ namespace sqlite_orm { } } + // interface functions namespace sqlite_orm { namespace internal { @@ -10172,6 +10291,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10208,6 +10328,7 @@ namespace sqlite_orm { #include // std::for_each, std::ranges::for_each // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -10248,6 +10369,7 @@ namespace sqlite_orm { // #include "column_result.h" + #include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of #include // std::tuple #include // std::reference_wrapper @@ -10258,6 +10380,7 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_fy.h" + #include namespace sqlite_orm { @@ -10286,12 +10409,14 @@ namespace sqlite_orm { // #include "mapped_type_proxy.h" + #include // std::remove_const // #include "type_traits.h" // #include "alias_traits.h" + namespace sqlite_orm { namespace internal { @@ -10323,6 +10448,7 @@ namespace sqlite_orm { // #include "storage_traits.h" + #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -10331,10 +10457,12 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" + #include // std::tuple // #include "../functional/mpl.h" + namespace sqlite_orm { namespace internal { @@ -10360,6 +10488,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -10390,6 +10519,7 @@ namespace sqlite_orm { // #include "function.h" + #include #include #include // std::string @@ -10402,6 +10532,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { struct arg_values; @@ -10636,6 +10767,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -10917,6 +11049,7 @@ namespace sqlite_orm { // #include "view.h" + #include #include // std::string #include // std::forward, std::move @@ -10928,6 +11061,7 @@ namespace sqlite_orm { // #include "iterator.h" + #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -10944,6 +11078,7 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" + #include #include // std::is_member_object_pointer @@ -10951,6 +11086,7 @@ namespace sqlite_orm { // #include "row_extractor.h" + namespace sqlite_orm { namespace internal { @@ -10978,10 +11114,7 @@ namespace sqlite_orm { template void operator()(const column_field& column) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_row_value_extractable>); -#endif - const row_extractor> rowExtractor{}; + const auto rowExtractor = row_value_extractor>(); auto value = rowExtractor.extract(this->stmt, this->index++); static_if::value>( [&value, &object = this->object](const auto& column) { @@ -10999,6 +11132,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -11086,6 +11220,7 @@ namespace sqlite_orm { // #include "ast_iterator.h" + #include // std::vector #include // std::reference_wrapper @@ -11105,6 +11240,7 @@ namespace sqlite_orm { // #include "prepared_statement.h" + #include #include // std::unique_ptr #include // std::iterator_traits @@ -11122,12 +11258,14 @@ namespace sqlite_orm { // #include "connection_holder.h" + #include #include #include // std::string // #include "error_code.h" + namespace sqlite_orm { namespace internal { @@ -11200,6 +11338,7 @@ namespace sqlite_orm { // #include "values.h" + #include // std::vector #include // std::tuple #include // std::forward @@ -11208,6 +11347,7 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { @@ -11248,6 +11388,7 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" + #if SQLITE_VERSION_NUMBER >= 3024000 #include // std::tuple #include // std::forward, std::move @@ -11255,6 +11396,7 @@ namespace sqlite_orm { // #include "../functional/cxx_type_traits_polyfill.h" + namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11317,6 +11459,7 @@ namespace sqlite_orm { // #include "ast/set.h" + #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11325,6 +11468,7 @@ namespace sqlite_orm { // #include "../table_name_collector.h" + #include // std::set #include // std::string #include // std::pair, std::move @@ -11343,6 +11487,7 @@ namespace sqlite_orm { // #include "storage_lookup.h" + namespace sqlite_orm { namespace internal { @@ -11427,6 +11572,7 @@ namespace sqlite_orm { } + namespace sqlite_orm { namespace internal { @@ -11526,6 +11672,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -12243,6 +12390,7 @@ namespace sqlite_orm { // #include "ast/excluded.h" + #include // std::move namespace sqlite_orm { @@ -12272,10 +12420,12 @@ namespace sqlite_orm { // #include "ast/exists.h" + #include // std::move // #include "../tags.h" + namespace sqlite_orm { namespace internal { @@ -12306,6 +12456,7 @@ namespace sqlite_orm { // #include "ast/set.h" + namespace sqlite_orm { namespace internal { @@ -12962,6 +13113,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -13018,6 +13170,7 @@ namespace sqlite_orm { // #include "storage_base.h" + #include #include // std::function, std::bind #include // std::string @@ -13031,11 +13184,12 @@ namespace sqlite_orm { #include // std::find_if // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "tuple_helper/tuple_iteration.h" // #include "pragma.h" + #include #include // std::string #include // std::function @@ -13055,6 +13209,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + #include // std::index_sequence #include #include @@ -13063,7 +13218,7 @@ namespace sqlite_orm { #include // std::exchange, std::tuple_size // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_iteration.h" @@ -13076,6 +13231,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { template @@ -13438,6 +13594,7 @@ namespace sqlite_orm { } } + namespace sqlite_orm { namespace internal { @@ -13452,7 +13609,7 @@ namespace sqlite_orm { inline int getPragmaCallback>(void* data, int argc, char** argv, char**) { auto& res = *(std::vector*)data; res.reserve(argc); - const row_extractor rowExtractor{}; + const auto rowExtractor = column_text_extractor(); for(int i = 0; i < argc; ++i) { auto rowString = rowExtractor.extract(argv[i]); res.push_back(std::move(rowString)); @@ -13653,6 +13810,7 @@ namespace sqlite_orm { // #include "limit_accessor.h" + #include #include // std::map #include // std::function @@ -13660,6 +13818,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13793,11 +13952,13 @@ namespace sqlite_orm { // #include "transaction_guard.h" + #include // std::function #include // std::move // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13878,6 +14039,7 @@ namespace sqlite_orm { // #include "backup.h" + #include #include // std::system_error #include // std::string @@ -13888,6 +14050,7 @@ namespace sqlite_orm { // #include "connection_holder.h" + namespace sqlite_orm { namespace internal { @@ -13955,6 +14118,7 @@ namespace sqlite_orm { // #include "values_to_tuple.h" + #include #include // std::index_sequence, std::make_index_sequence #include // std::tuple, std::tuple_size, std::get @@ -13965,10 +14129,12 @@ namespace sqlite_orm { // #include "arg_values.h" + #include // #include "row_extractor.h" + namespace sqlite_orm { /** @short Wrapper around a dynamically typed value object. @@ -13981,10 +14147,7 @@ namespace sqlite_orm { template T get() const { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_boxed_value_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = internal::boxed_value_extractor(); return rowExtractor.extract(this->value); } @@ -14115,6 +14278,7 @@ namespace sqlite_orm { }; } + namespace sqlite_orm { namespace internal { @@ -14146,10 +14310,7 @@ namespace sqlite_orm { #endif template void extract(sqlite3_value* value, T& t) const { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_boxed_value_extractable); -#endif - const row_extractor rowExtractor{}; + const auto rowExtractor = boxed_value_extractor(); t = rowExtractor.extract(value); } }; @@ -14162,6 +14323,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -14929,11 +15091,13 @@ namespace sqlite_orm { // #include "expression_object_type.h" + #include // std::decay #include // std::reference_wrapper // #include "prepared_statement.h" + namespace sqlite_orm { namespace internal { @@ -15067,6 +15231,7 @@ namespace sqlite_orm { // #include "statement_serializer.h" + #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -15081,6 +15246,7 @@ namespace sqlite_orm { // #include "functional/cxx_optional.h" + // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -15125,6 +15291,7 @@ namespace sqlite_orm { // #include "column_names_getter.h" + #include // std::is_base_of #include // std::string #include // std::vector @@ -15145,11 +15312,12 @@ namespace sqlite_orm { // #include "select_constraints.h" // #include "storage_lookup.h" -// pick_table + // pick_table // #include "serializer_context.h" // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -15252,6 +15420,7 @@ namespace sqlite_orm { // #include "order_by_serializer.h" + #include // std::string #include // std::stringstream @@ -15343,6 +15512,7 @@ namespace sqlite_orm { // #include "util.h" + namespace sqlite_orm { namespace internal { @@ -17317,6 +17487,7 @@ namespace sqlite_orm { // #include "serializing_util.h" + namespace sqlite_orm { namespace internal { @@ -18623,19 +18794,18 @@ namespace sqlite_orm { template, - satisfies = true> - std::vector execute(const prepared_statement_t>& statement) { + class R = column_result_of_t, + satisfies_not = true> + std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); - std::vector res; - perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { - O obj; - object_from_column_builder builder{obj, stmt}; - table.for_each_column(builder); - res.push_back(std::move(obj)); + std::vector res; + perform_steps(stmt, [rowExtractor = row_value_extractor(), &res](sqlite3_stmt* stmt) { + // note: we always pass in the first index, even though a row extractor + // for a tuple ignores it and does its custom iteration of the result row + res.push_back(rowExtractor.extract(stmt, 0)); }); res.shrink_to_fit(); return res; @@ -18643,21 +18813,19 @@ namespace sqlite_orm { template, - satisfies_not = true> - std::vector execute(const prepared_statement_t>& statement) { + class O = column_result_of_t, + satisfies = true> + std::vector execute(const prepared_statement_t>& statement) { sqlite3_stmt* stmt = reset_stmt(statement.stmt); iterate_ast(statement.expression, conditional_binder{stmt}); - std::vector res; - perform_steps(stmt, [rowExtractor = row_extractor{}, &res](sqlite3_stmt* stmt) { -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED - static_assert(orm_row_value_extractable); -#endif - // note: we always pass in the first index, even though a row extractor - // for a tuple ignores it and does its custom iteration of the result row - res.push_back(rowExtractor.extract(stmt, 0)); + std::vector res; + perform_steps(stmt, [&table = this->get_table(), &res](sqlite3_stmt* stmt) { + O obj; + object_from_column_builder builder{obj, stmt}; + table.for_each_column(builder); + res.push_back(std::move(obj)); }); res.shrink_to_fit(); return res; @@ -18751,7 +18919,7 @@ namespace sqlite_orm { #include // std::get // #include "functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "functional/static_magic.h" // #include "prepared_statement.h" @@ -18760,12 +18928,14 @@ namespace sqlite_orm { // #include "node_tuple.h" + #include // std::enable_if #include // std::tuple #include // std::pair #include // std::reference_wrapper // #include "functional/cxx_optional.h" + // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_filter.h" @@ -18794,6 +18964,7 @@ namespace sqlite_orm { // #include "ast/group_by.h" + namespace sqlite_orm { namespace internal { @@ -19091,6 +19262,7 @@ namespace sqlite_orm { // #include "expression_object_type.h" + namespace sqlite_orm { template @@ -19270,6 +19442,7 @@ namespace sqlite_orm { // #include "pointer_value.h" + namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19344,6 +19517,7 @@ namespace sqlite_orm { // #include "alias.h" + namespace sqlite_orm { /** * SQLite's "schema table" that stores the schema for a database. @@ -19389,6 +19563,7 @@ namespace sqlite_orm { // #include "../table.h" + namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19431,6 +19606,7 @@ namespace sqlite_orm { * this file is also used to provide definitions of interface methods 'hitting the database'. */ + #include // std::make_unique // #include "../functional/cxx_core_features.h" @@ -19447,6 +19623,7 @@ namespace sqlite_orm { // #include "../column.h" + namespace sqlite_orm { namespace internal { @@ -19481,13 +19658,14 @@ namespace sqlite_orm { #include // std::find_if, std::ranges::find // #include "../functional/cxx_universal.h" -// ::size_t + // ::size_t // #include "../type_printer.h" // #include "../column.h" // #include "../table.h" + namespace sqlite_orm { namespace internal { @@ -19552,6 +19730,7 @@ namespace sqlite_orm { // #include "../storage.h" + namespace sqlite_orm { namespace internal { diff --git a/tests/static_tests/row_extractor.cpp b/tests/static_tests/row_extractor.cpp index 28e74a46d..b27f9d4b0 100644 --- a/tests/static_tests/row_extractor.cpp +++ b/tests/static_tests/row_extractor.cpp @@ -83,6 +83,13 @@ TEST_CASE("is_extractable") { #endif // SQLITE_ORM_OPTIONAL_SUPPORTED #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED check_not_extractable>(); + // pointer arguments are special: they can only be passed to and from functions, but casting is prohibited + { + using int64_pointer_arg = carray_pointer_arg; + STATIC_CHECK_FALSE(orm_column_text_extractable); + STATIC_CHECK_FALSE(orm_row_value_extractable); + STATIC_CHECK(orm_boxed_value_extractable); + } #endif check_extractable(); diff --git a/tests/tests.cpp b/tests/tests.cpp index d0e13dc57..71687322d 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -1,6 +1,14 @@ #include #include +#ifdef _DEBUG +#pragma comment(lib, "Catch2d.Lib") +#pragma comment(lib, "manual-link/Catch2Maind.Lib") +#else +#pragma comment(lib, "Catch2.Lib") +#pragma comment(lib, "manual-link/Catch2Main.Lib") +#endif + #include // std::vector #include // std::string #include // std::unique_ptr From 7239526f5f1f0e6d7ee3c66b5edc819871da261e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 23:08:46 +0300 Subject: [PATCH 03/12] appveyor: Updated vcpkg environment to 2023.06.23 --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 82a7dc203..d426348e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -107,7 +107,7 @@ for: install: - |- cd C:\Tools\vcpkg - git fetch --tags && git checkout 2023.04.15 + git fetch --tags && git checkout 2023.06.23 cd %APPVEYOR_BUILD_FOLDER% C:\Tools\vcpkg\bootstrap-vcpkg.bat -disableMetrics C:\Tools\vcpkg\vcpkg integrate install @@ -140,7 +140,7 @@ for: install: - |- pushd $HOME/vcpkg - git fetch --tags && git checkout 2023.04.15 + git fetch --tags && git checkout 2023.06.23 popd $HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics $HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets @@ -168,7 +168,7 @@ for: # using custom vcpkg triplets for building and linking dynamic dependent libraries install: - |- - git clone --depth 1 --branch 2023.04.15 https://github.com/microsoft/vcpkg.git $HOME/vcpkg + git clone --depth 1 --branch 2023.06.23 https://github.com/microsoft/vcpkg.git $HOME/vcpkg $HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics $HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets vcpkg install sqlite3[core,dbstat,math,json1] catch2 --overlay-triplets=vcpkg/triplets From d5cfc10a603eff6f9e8aba6d0df99d8f085fc605 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 23:29:40 +0300 Subject: [PATCH 04/12] Updated sqlite_orm.h --- include/sqlite_orm/sqlite_orm.h | 166 ++------------------------------ 1 file changed, 9 insertions(+), 157 deletions(-) diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index da2a09437..31b0c9fd8 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -10,7 +10,6 @@ __pragma(push_macro("max")) // #include "cxx_universal.h" - /* * This header makes central C++ functionality on which sqlite_orm depends universally available: * - alternative operator representations @@ -29,7 +28,6 @@ using std::nullptr_t; // #include "cxx_core_features.h" - /* * This header detects core C++ language features on which sqlite_orm depends. * May be updated/overwritten by cxx_compiler_quirks.h @@ -110,7 +108,6 @@ using std::nullptr_t; // #include "cxx_compiler_quirks.h" - /* * This header defines macros for circumventing compiler quirks on which sqlite_orm depends. * May amend cxx_core_features.h @@ -170,8 +167,6 @@ using std::nullptr_t; #define SQLITE_ORM_BROKEN_NONTEMPLATE_CONCEPTS #endif - - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -216,7 +211,6 @@ using std::nullptr_t; // #include "cxx_universal.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -358,7 +352,6 @@ namespace sqlite_orm { namespace polyfill = internal::polyfill; } - namespace sqlite_orm { // C++ generic traits used throughout the library namespace internal { @@ -595,10 +588,8 @@ namespace sqlite_orm { #include // std::vector // #include "functional/cxx_optional.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -607,7 +598,6 @@ namespace sqlite_orm { #define SQLITE_ORM_OPTIONAL_SUPPORTED #endif - // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" @@ -644,7 +634,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { /** @@ -743,7 +732,6 @@ namespace sqlite_orm { // #include "functional/mpl.h" - /* * Symbols for 'template metaprogramming' (compile-time template programming), * inspired by the MPL of Aleksey Gurtovoy and David Abrahams. @@ -772,7 +760,6 @@ namespace sqlite_orm { // #include "cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { namespace mpl { @@ -1058,7 +1045,6 @@ namespace sqlite_orm { // #include "tuple_helper/same_or_void.h" - namespace sqlite_orm { namespace internal { @@ -1088,7 +1074,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_traits.h" - #include // std::is_same #include @@ -1096,7 +1081,6 @@ namespace sqlite_orm { // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { /* @@ -1145,7 +1129,6 @@ namespace sqlite_orm { } // #include "tuple_helper/tuple_filter.h" - #include // std::integral_constant, std::index_sequence, std::conditional, std::declval #include // std::tuple @@ -1153,12 +1136,10 @@ namespace sqlite_orm { // #include "../functional/index_sequence_util.h" - #include // std::index_sequence, std::make_index_sequence // #include "../functional/cxx_universal.h" - namespace sqlite_orm { namespace internal { /** @@ -1188,7 +1169,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -1280,7 +1260,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -1325,7 +1304,6 @@ namespace sqlite_orm { // #include "type_printer.h" - namespace sqlite_orm { namespace internal { @@ -1851,10 +1829,8 @@ namespace sqlite_orm { #include // std::shared_ptr, std::unique_ptr // #include "functional/cxx_optional.h" - // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { /** @@ -1895,7 +1871,6 @@ namespace sqlite_orm { // #include "tags.h" - namespace sqlite_orm { namespace internal { struct negatable_t {}; @@ -1909,13 +1884,10 @@ namespace sqlite_orm { // #include "serialize_result_type.h" - // #include "functional/cxx_string_view.h" - // #include "cxx_core_features.h" - #if SQLITE_ORM_HAS_INCLUDE() #include #endif @@ -1940,7 +1912,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -2229,14 +2200,12 @@ namespace sqlite_orm { // #include "member_traits/member_traits.h" - #include // std::enable_if, std::is_function, std::true_type, std::false_type // #include "../functional/cxx_universal.h" // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { // SFINAE friendly trait to get a member object pointer's field type @@ -2328,7 +2297,6 @@ namespace sqlite_orm { // #include "constraints.h" - namespace sqlite_orm { namespace internal { @@ -2509,14 +2477,12 @@ namespace sqlite_orm { #endif // SQLITE_ORM_OMITS_CODECVT // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -2681,7 +2647,6 @@ namespace sqlite_orm { // #include "is_base_of_template.h" - #include // std::true_type, std::false_type, std::declval namespace sqlite_orm { @@ -2727,7 +2692,6 @@ namespace sqlite_orm { // #include "optional_container.h" - namespace sqlite_orm { namespace internal { @@ -2762,7 +2726,6 @@ namespace sqlite_orm { // #include "serializer_context.h" - namespace sqlite_orm { namespace internal { @@ -2804,7 +2767,6 @@ namespace sqlite_orm { // #include "alias_traits.h" - #include // std::remove_const, std::is_base_of, std::is_same #ifdef SQLITE_ORM_WITH_CPP20_ALIASES #include @@ -2816,7 +2778,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { /** @short Base class for a custom table alias, column alias or expression alias. @@ -2895,17 +2856,14 @@ namespace sqlite_orm { // #include "expression.h" - #include #include // std::move, std::forward // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "operators.h" - namespace sqlite_orm { namespace internal { @@ -2987,7 +2945,6 @@ namespace sqlite_orm { // #include "literal.h" - namespace sqlite_orm { namespace internal { @@ -3004,7 +2961,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -4242,14 +4198,13 @@ namespace sqlite_orm { #include // std::copy_n // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "type_traits.h" // #include "alias_traits.h" - namespace sqlite_orm { namespace internal { @@ -4575,10 +4530,8 @@ namespace sqlite_orm { // #include "ast/into.h" - // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -4597,7 +4550,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { using int64 = sqlite_int64; @@ -6710,7 +6662,6 @@ namespace sqlite_orm { #include // std::tuple, std::get, std::tuple_size // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_type_traits_polyfill.h" @@ -6723,7 +6674,6 @@ namespace sqlite_orm { // #include "ast/where.h" - #include // std::false_type, std::true_type #include // std::move @@ -6733,7 +6683,6 @@ namespace sqlite_orm { // #include "../serialize_result_type.h" - namespace sqlite_orm { namespace internal { @@ -6781,14 +6730,12 @@ namespace sqlite_orm { // #include "ast/group_by.h" - #include // std::tuple, std::make_tuple #include // std::true_type, std::false_type #include // std::forward, std::move // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -6837,7 +6784,6 @@ namespace sqlite_orm { // #include "column_pointer.h" - #include // std::string #include // std::move @@ -6847,7 +6793,6 @@ namespace sqlite_orm { // #include "alias_traits.h" - namespace sqlite_orm { namespace internal { /** @@ -6902,7 +6847,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -7336,7 +7280,6 @@ namespace sqlite_orm { // #include "functional/cxx_universal.h" - namespace sqlite_orm { struct table_info { @@ -7394,7 +7337,6 @@ namespace sqlite_orm { // #include "optional_container.h" - // NOTE Idea : Maybe also implement a custom trigger system to call a c++ callback when a trigger triggers ? // (Could be implemented with a normal trigger that insert or update an internal table and then retreive // the event in the C++ code, to call the C++ user callback, with update hooks: https://www.sqlite.org/c3ref/update_hook.html) @@ -7718,7 +7660,6 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" - #include // std::integral_constant #if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() #include @@ -7728,7 +7669,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { using xdestroy_fn_t = void (*)(void*); @@ -7970,7 +7910,6 @@ namespace sqlite_orm { #endif } - namespace sqlite_orm { /** @@ -8167,7 +8106,6 @@ namespace sqlite_orm { #endif // #include "../member_traits/member_traits.h" - namespace sqlite_orm { namespace internal { namespace polyfill { @@ -8251,7 +8189,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { /** @@ -8619,7 +8556,6 @@ namespace sqlite_orm { // #include "journal_mode.h" - #include // std::back_inserter #include // std::string #include // std::unique_ptr @@ -8696,7 +8632,6 @@ namespace sqlite_orm { // #include "is_std_ptr.h" - namespace sqlite_orm { /** @@ -9127,7 +9062,6 @@ namespace sqlite_orm { // #include "error_code.h" - namespace sqlite_orm { /** @@ -9323,7 +9257,6 @@ namespace sqlite_orm { // #include "indexed_column.h" - #include // std::string #include // std::move @@ -9331,7 +9264,6 @@ namespace sqlite_orm { // #include "ast/where.h" - namespace sqlite_orm { namespace internal { @@ -9397,7 +9329,6 @@ namespace sqlite_orm { // #include "table_type_of.h" - namespace sqlite_orm { namespace internal { @@ -9536,14 +9467,13 @@ namespace sqlite_orm { #include // std::forward, std::move // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "functional/cxx_functional_polyfill.h" // #include "functional/static_magic.h" - #ifndef SQLITE_ORM_IF_CONSTEXPR_SUPPORTED #include // std::false_type, std::true_type, std::integral_constant #endif @@ -9628,18 +9558,16 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_iteration.h" - #include // std::tuple, std::get, std::tuple_element, std::tuple_size #include // std::remove_reference, std::index_sequence, std::make_index_sequence #include // std::forward, std::move // #include "../functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "../functional/cxx_type_traits_polyfill.h" // #include "../functional/cxx_functional_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -9778,7 +9706,6 @@ namespace sqlite_orm { // #include "column.h" - namespace sqlite_orm { namespace internal { @@ -10070,7 +9997,7 @@ namespace sqlite_orm { #include // std::string // #include "functional/cxx_universal.h" - // ::nullptr_t +// ::nullptr_t // #include "functional/static_magic.h" // #include "tuple_helper/tuple_filter.h" @@ -10083,7 +10010,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - #include // std::true_type, std::false_type, std::remove_const, std::enable_if, std::is_base_of, std::is_void #include #include // std::index_sequence, std::make_index_sequence @@ -10094,7 +10020,6 @@ namespace sqlite_orm { // #include "type_traits.h" - namespace sqlite_orm { namespace internal { @@ -10227,7 +10152,6 @@ namespace sqlite_orm { } } - // interface functions namespace sqlite_orm { namespace internal { @@ -10291,7 +10215,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10328,7 +10251,6 @@ namespace sqlite_orm { #include // std::for_each, std::ranges::for_each // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -10369,7 +10291,6 @@ namespace sqlite_orm { // #include "column_result.h" - #include // std::enable_if, std::is_same, std::decay, std::is_arithmetic, std::is_base_of #include // std::tuple #include // std::reference_wrapper @@ -10380,7 +10301,6 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_fy.h" - #include namespace sqlite_orm { @@ -10409,14 +10329,12 @@ namespace sqlite_orm { // #include "mapped_type_proxy.h" - #include // std::remove_const // #include "type_traits.h" // #include "alias_traits.h" - namespace sqlite_orm { namespace internal { @@ -10448,7 +10366,6 @@ namespace sqlite_orm { // #include "storage_traits.h" - #include // std::tuple // #include "functional/cxx_type_traits_polyfill.h" @@ -10457,12 +10374,10 @@ namespace sqlite_orm { // #include "tuple_helper/tuple_transformer.h" - #include // std::tuple // #include "../functional/mpl.h" - namespace sqlite_orm { namespace internal { @@ -10488,7 +10403,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -10519,7 +10433,6 @@ namespace sqlite_orm { // #include "function.h" - #include #include #include // std::string @@ -10532,7 +10445,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { struct arg_values; @@ -10767,7 +10679,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -11049,7 +10960,6 @@ namespace sqlite_orm { // #include "view.h" - #include #include // std::string #include // std::forward, std::move @@ -11061,7 +10971,6 @@ namespace sqlite_orm { // #include "iterator.h" - #include #include // std::shared_ptr, std::unique_ptr, std::make_shared #include // std::decay @@ -11078,7 +10987,6 @@ namespace sqlite_orm { // #include "object_from_column_builder.h" - #include #include // std::is_member_object_pointer @@ -11086,7 +10994,6 @@ namespace sqlite_orm { // #include "row_extractor.h" - namespace sqlite_orm { namespace internal { @@ -11132,7 +11039,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -11220,7 +11126,6 @@ namespace sqlite_orm { // #include "ast_iterator.h" - #include // std::vector #include // std::reference_wrapper @@ -11240,7 +11145,6 @@ namespace sqlite_orm { // #include "prepared_statement.h" - #include #include // std::unique_ptr #include // std::iterator_traits @@ -11258,14 +11162,12 @@ namespace sqlite_orm { // #include "connection_holder.h" - #include #include #include // std::string // #include "error_code.h" - namespace sqlite_orm { namespace internal { @@ -11338,7 +11240,6 @@ namespace sqlite_orm { // #include "values.h" - #include // std::vector #include // std::tuple #include // std::forward @@ -11347,7 +11248,6 @@ namespace sqlite_orm { // #include "functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { @@ -11388,7 +11288,6 @@ namespace sqlite_orm { // #include "ast/upsert_clause.h" - #if SQLITE_VERSION_NUMBER >= 3024000 #include // std::tuple #include // std::forward, std::move @@ -11396,7 +11295,6 @@ namespace sqlite_orm { // #include "../functional/cxx_type_traits_polyfill.h" - namespace sqlite_orm { namespace internal { #if SQLITE_VERSION_NUMBER >= 3024000 @@ -11459,7 +11357,6 @@ namespace sqlite_orm { // #include "ast/set.h" - #include // std::tuple, std::tuple_size #include // std::string #include // std::vector @@ -11468,7 +11365,6 @@ namespace sqlite_orm { // #include "../table_name_collector.h" - #include // std::set #include // std::string #include // std::pair, std::move @@ -11487,7 +11383,6 @@ namespace sqlite_orm { // #include "storage_lookup.h" - namespace sqlite_orm { namespace internal { @@ -11572,7 +11467,6 @@ namespace sqlite_orm { } - namespace sqlite_orm { namespace internal { @@ -11672,7 +11566,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -12390,7 +12283,6 @@ namespace sqlite_orm { // #include "ast/excluded.h" - #include // std::move namespace sqlite_orm { @@ -12420,12 +12312,10 @@ namespace sqlite_orm { // #include "ast/exists.h" - #include // std::move // #include "../tags.h" - namespace sqlite_orm { namespace internal { @@ -12456,7 +12346,6 @@ namespace sqlite_orm { // #include "ast/set.h" - namespace sqlite_orm { namespace internal { @@ -13113,7 +13002,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -13170,7 +13058,6 @@ namespace sqlite_orm { // #include "storage_base.h" - #include #include // std::function, std::bind #include // std::string @@ -13184,12 +13071,11 @@ namespace sqlite_orm { #include // std::find_if // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "tuple_helper/tuple_iteration.h" // #include "pragma.h" - #include #include // std::string #include // std::function @@ -13209,7 +13095,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - #include // std::index_sequence #include #include @@ -13218,7 +13103,7 @@ namespace sqlite_orm { #include // std::exchange, std::tuple_size // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_iteration.h" @@ -13231,7 +13116,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { template @@ -13594,7 +13478,6 @@ namespace sqlite_orm { } } - namespace sqlite_orm { namespace internal { @@ -13810,7 +13693,6 @@ namespace sqlite_orm { // #include "limit_accessor.h" - #include #include // std::map #include // std::function @@ -13818,7 +13700,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -13952,13 +13833,11 @@ namespace sqlite_orm { // #include "transaction_guard.h" - #include // std::function #include // std::move // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -14039,7 +13918,6 @@ namespace sqlite_orm { // #include "backup.h" - #include #include // std::system_error #include // std::string @@ -14050,7 +13928,6 @@ namespace sqlite_orm { // #include "connection_holder.h" - namespace sqlite_orm { namespace internal { @@ -14118,7 +13995,6 @@ namespace sqlite_orm { // #include "values_to_tuple.h" - #include #include // std::index_sequence, std::make_index_sequence #include // std::tuple, std::tuple_size, std::get @@ -14129,12 +14005,10 @@ namespace sqlite_orm { // #include "arg_values.h" - #include // #include "row_extractor.h" - namespace sqlite_orm { /** @short Wrapper around a dynamically typed value object. @@ -14278,7 +14152,6 @@ namespace sqlite_orm { }; } - namespace sqlite_orm { namespace internal { @@ -14323,7 +14196,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -15091,13 +14963,11 @@ namespace sqlite_orm { // #include "expression_object_type.h" - #include // std::decay #include // std::reference_wrapper // #include "prepared_statement.h" - namespace sqlite_orm { namespace internal { @@ -15231,7 +15101,6 @@ namespace sqlite_orm { // #include "statement_serializer.h" - #include // std::stringstream #include // std::string #include // std::enable_if, std::remove_pointer @@ -15246,7 +15115,6 @@ namespace sqlite_orm { // #include "functional/cxx_optional.h" - // #include "functional/cxx_universal.h" // #include "functional/cxx_functional_polyfill.h" @@ -15291,7 +15159,6 @@ namespace sqlite_orm { // #include "column_names_getter.h" - #include // std::is_base_of #include // std::string #include // std::vector @@ -15312,12 +15179,11 @@ namespace sqlite_orm { // #include "select_constraints.h" // #include "storage_lookup.h" - // pick_table +// pick_table // #include "serializer_context.h" // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -15420,7 +15286,6 @@ namespace sqlite_orm { // #include "order_by_serializer.h" - #include // std::string #include // std::stringstream @@ -15512,7 +15377,6 @@ namespace sqlite_orm { // #include "util.h" - namespace sqlite_orm { namespace internal { @@ -17487,7 +17351,6 @@ namespace sqlite_orm { // #include "serializing_util.h" - namespace sqlite_orm { namespace internal { @@ -18919,7 +18782,7 @@ namespace sqlite_orm { #include // std::get // #include "functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "functional/static_magic.h" // #include "prepared_statement.h" @@ -18928,14 +18791,12 @@ namespace sqlite_orm { // #include "node_tuple.h" - #include // std::enable_if #include // std::tuple #include // std::pair #include // std::reference_wrapper // #include "functional/cxx_optional.h" - // #include "functional/cxx_type_traits_polyfill.h" // #include "tuple_helper/tuple_filter.h" @@ -18964,7 +18825,6 @@ namespace sqlite_orm { // #include "ast/group_by.h" - namespace sqlite_orm { namespace internal { @@ -19262,7 +19122,6 @@ namespace sqlite_orm { // #include "expression_object_type.h" - namespace sqlite_orm { template @@ -19442,7 +19301,6 @@ namespace sqlite_orm { // #include "pointer_value.h" - namespace sqlite_orm { inline constexpr const char carray_pvt_name[] = "carray"; @@ -19517,7 +19375,6 @@ namespace sqlite_orm { // #include "alias.h" - namespace sqlite_orm { /** * SQLite's "schema table" that stores the schema for a database. @@ -19563,7 +19420,6 @@ namespace sqlite_orm { // #include "../table.h" - namespace sqlite_orm { #ifdef SQLITE_ENABLE_DBSTAT_VTAB struct dbstat { @@ -19606,7 +19462,6 @@ namespace sqlite_orm { * this file is also used to provide definitions of interface methods 'hitting the database'. */ - #include // std::make_unique // #include "../functional/cxx_core_features.h" @@ -19623,7 +19478,6 @@ namespace sqlite_orm { // #include "../column.h" - namespace sqlite_orm { namespace internal { @@ -19658,14 +19512,13 @@ namespace sqlite_orm { #include // std::find_if, std::ranges::find // #include "../functional/cxx_universal.h" - // ::size_t +// ::size_t // #include "../type_printer.h" // #include "../column.h" // #include "../table.h" - namespace sqlite_orm { namespace internal { @@ -19730,7 +19583,6 @@ namespace sqlite_orm { // #include "../storage.h" - namespace sqlite_orm { namespace internal { From 8db2b6faf985b86de68ca5123f63e347bfc18337 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 23:34:05 +0300 Subject: [PATCH 05/12] appveyor: Updated vcpkg environment to 2023.06.20 --- appveyor.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d426348e7..2a8acd69e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -107,7 +107,7 @@ for: install: - |- cd C:\Tools\vcpkg - git fetch --tags && git checkout 2023.06.23 + git fetch --tags && git checkout 2023.06.20 cd %APPVEYOR_BUILD_FOLDER% C:\Tools\vcpkg\bootstrap-vcpkg.bat -disableMetrics C:\Tools\vcpkg\vcpkg integrate install @@ -140,7 +140,7 @@ for: install: - |- pushd $HOME/vcpkg - git fetch --tags && git checkout 2023.06.23 + git fetch --tags && git checkout 2023.06.20 popd $HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics $HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets @@ -168,7 +168,7 @@ for: # using custom vcpkg triplets for building and linking dynamic dependent libraries install: - |- - git clone --depth 1 --branch 2023.06.23 https://github.com/microsoft/vcpkg.git $HOME/vcpkg + git clone --depth 1 --branch 2023.06.20 https://github.com/microsoft/vcpkg.git $HOME/vcpkg $HOME/vcpkg/bootstrap-vcpkg.sh -disableMetrics $HOME/vcpkg/vcpkg integrate install --overlay-triplets=vcpkg/triplets vcpkg install sqlite3[core,dbstat,math,json1] catch2 --overlay-triplets=vcpkg/triplets From 44a411b8c81d0d06ccbff7759bde68f0e5d36d79 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 23:38:09 +0300 Subject: [PATCH 06/12] Removed code used in local test environment --- tests/tests.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/tests.cpp b/tests/tests.cpp index 71687322d..d0e13dc57 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -1,14 +1,6 @@ #include #include -#ifdef _DEBUG -#pragma comment(lib, "Catch2d.Lib") -#pragma comment(lib, "manual-link/Catch2Maind.Lib") -#else -#pragma comment(lib, "Catch2.Lib") -#pragma comment(lib, "manual-link/Catch2Main.Lib") -#endif - #include // std::vector #include // std::string #include // std::unique_ptr From 1439c85995725bd302925168325d3ae5aa949c97 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Tue, 18 Jul 2023 23:43:27 +0300 Subject: [PATCH 07/12] Guarded static "row extractor" unit tests --- tests/static_tests/row_extractor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/static_tests/row_extractor.cpp b/tests/static_tests/row_extractor.cpp index b27f9d4b0..854151242 100644 --- a/tests/static_tests/row_extractor.cpp +++ b/tests/static_tests/row_extractor.cpp @@ -1,4 +1,9 @@ #include +#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#define ENABLE_THIS_UT +#endif + +#ifdef ENABLE_THIS_UT #include #include // std::unique_ptr, std::shared_ptr #include // std::string @@ -100,3 +105,4 @@ TEST_CASE("is_extractable") { check_not_extractable(); check_not_extractable>(); } +#endif From c7f577cc354ae79a421d06ce83a9d08efbe07f7e Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 19 Jul 2023 09:07:51 +0300 Subject: [PATCH 08/12] Added missing unit test file row_extractor.cpp --- tests/row_extractor.cpp | 163 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tests/row_extractor.cpp diff --git a/tests/row_extractor.cpp b/tests/row_extractor.cpp new file mode 100644 index 000000000..88e63b2e6 --- /dev/null +++ b/tests/row_extractor.cpp @@ -0,0 +1,163 @@ +#include +#include + +#ifdef SQLITE_ORM_OPTIONAL_SUPPORTED +using namespace sqlite_orm; + +enum class Gender { + Invalid, + Male, + Female, +}; + +struct SuperHero { + int id; + std::string name; + Gender gender = Gender::Invalid; +}; + +std::string GenderToString(Gender gender) { + switch(gender) { + case Gender::Female: + return "female"; + case Gender::Male: + return "male"; + } + throw std::domain_error("Invalid Gender enum"); +} + +std::optional GenderFromString(const std::string& s) { + if(s == "female") { + return Gender::Female; + } else if(s == "male") { + return Gender::Male; + } + return std::nullopt; +} + +template<> +struct sqlite_orm::type_printer : public text_printer {}; + +template<> +struct statement_binder { + + int bind(sqlite3_stmt* stmt, int index, const Gender& value) { + return statement_binder().bind(stmt, index, GenderToString(value)); + // or return sqlite3_bind_text(stmt, index++, GenderToString(value).c_str(), -1, SQLITE_TRANSIENT); + } + void result(sqlite3_context* context, const Gender& value) const { + return statement_binder().result(context, GenderToString(value)); + } +}; + +template<> +struct sqlite_orm::field_printer { + std::string operator()(const Gender& t) const { + return GenderToString(t); + } +}; + +template<> +struct sqlite_orm::row_extractor { + Gender extract(const char* columnText) const { + if(auto gender = GenderFromString(columnText)) { + return *gender; + } else { + throw std::runtime_error("incorrect gender string (" + std::string(columnText) + ")"); + } + } + + Gender extract(sqlite3_stmt* stmt, int columnIndex) const { + auto str = sqlite3_column_text(stmt, columnIndex); + return this->extract((const char*)str); + } + + Gender extract(sqlite3_value* value) const { + const unsigned char* str = sqlite3_value_text(value); + return this->extract((const char*)str); + } +}; + +struct IdentityFunction { + + Gender operator()(Gender gender) const { + return gender; + } + + static const std::string& name() { + static const std::string result = "IDENTITY"; + return result; + } +}; + +struct CustomConcatFunction { + + std::string operator()(const arg_values& args) const { + std::string result; + for(auto arg_value: args) { + result += arg_value.get(); + } + return result; + } + + static const std::string& name() { + static const std::string result = "CUSTOM_CONCAT"; + return result; + } +}; + +// This test case triggers the conceptual checks performed in all functions that use the row_extractor. +// Also it is representative for all stock row extractor specializations in regard to testing +// storage's machinery during select and function calls, and whether they return proper values or build objects with proper values. +TEST_CASE("Custom row extractors") { + remove("cre.sqlite"); + struct fguard { + ~fguard() { + remove("cre.sqlite"); + } + } g; + auto storage = make_storage("cre.sqlite", + make_table("superheros", + make_column("id", &SuperHero::id, primary_key()), + make_column("name", &SuperHero::name), + make_column("gender", &SuperHero::gender))); + sqlite3* db = nullptr; + storage.on_open = [&db](sqlite3* db_) { + db = db_; + }; + storage.open_forever(); + storage.sync_schema(); + + storage.transaction([&storage]() { + storage.insert(SuperHero{-1, "Batman", Gender::Male}); + storage.insert(SuperHero{-1, "Wonder woman", Gender::Female}); + storage.insert(SuperHero{-1, "Superman", Gender::Male}); + return true; + }); + + SECTION("object builder") { + auto allSuperHeros = storage.get_all(order_by(&SuperHero::gender)); + REQUIRE(allSuperHeros.at(0).gender == Gender::Female); + } + SECTION("rowset builder") { + auto allGenders = storage.select(distinct(&SuperHero::gender), order_by(&SuperHero::gender)); + REQUIRE(allGenders.at(0) == Gender::Female); + } + SECTION("column text") { + auto firstGender = select(distinct(&SuperHero::gender), order_by(&SuperHero::gender), limit(1)); + Gender gender = Gender::Invalid; + internal::perform_exec(db, storage.dump(firstGender), &extract_single_value, &gender); + REQUIRE(gender == Gender::Female); + } + SECTION("udf") { + storage.create_scalar_function(); + auto genders = storage.select(func(Gender::Male)); + REQUIRE(genders.at(0) == Gender::Male); + } + SECTION("dynamic-arg udf") { + storage.create_scalar_function(); + auto concatGenders = storage.select(func(Gender::Male, Gender::Female)); + REQUIRE(concatGenders.at(0) == "malefemale"); + } +} +#endif From 9b3398aac28a0b95990dedae1dd63f3ebea69506 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 19 Jul 2023 09:17:35 +0300 Subject: [PATCH 09/12] Spelled out variable names --- dev/row_extractor.h | 102 ++++++++++++++++---------------- include/sqlite_orm/sqlite_orm.h | 102 ++++++++++++++++---------------- 2 files changed, 102 insertions(+), 102 deletions(-) diff --git a/dev/row_extractor.h b/dev/row_extractor.h index ebf7eb937..971a13527 100644 --- a/dev/row_extractor.h +++ b/dev/row_extractor.h @@ -149,12 +149,12 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - V extract(const char* colTxt) const { - return this->extract(colTxt, tag()); + V extract(const char* columnText) const { + return this->extract(columnText, tag()); } - V extract(sqlite3_stmt* stmt, int colIdx) const { - return this->extract(stmt, colIdx, tag()); + V extract(sqlite3_stmt* stmt, int columnIndex) const { + return this->extract(stmt, columnIndex, tag()); } V extract(sqlite3_value* value) const { @@ -164,36 +164,36 @@ namespace sqlite_orm { private: using tag = arithmetic_tag_t; - V extract(const char* colTxt, const int_or_smaller_tag&) const { - return static_cast(atoi(colTxt)); + V extract(const char* columnText, const int_or_smaller_tag&) const { + return static_cast(atoi(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const int_or_smaller_tag&) const { - return static_cast(sqlite3_column_int(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { + return static_cast(sqlite3_column_int(stmt, columnIndex)); } V extract(sqlite3_value* value, const int_or_smaller_tag&) const { return static_cast(sqlite3_value_int(value)); } - V extract(const char* colTxt, const bigint_tag&) const { - return static_cast(atoll(colTxt)); + V extract(const char* columnText, const bigint_tag&) const { + return static_cast(atoll(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const bigint_tag&) const { - return static_cast(sqlite3_column_int64(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { + return static_cast(sqlite3_column_int64(stmt, columnIndex)); } V extract(sqlite3_value* value, const bigint_tag&) const { return static_cast(sqlite3_value_int64(value)); } - V extract(const char* colTxt, const real_tag&) const { - return static_cast(atof(colTxt)); + V extract(const char* columnText, const real_tag&) const { + return static_cast(atof(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const real_tag&) const { - return static_cast(sqlite3_column_double(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { + return static_cast(sqlite3_column_double(stmt, columnIndex)); } V extract(sqlite3_value* value, const real_tag&) const { @@ -206,16 +206,16 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - T extract(const char* colTxt) const { - if(colTxt) { - return colTxt; + T extract(const char* columnText) const { + if(columnText) { + return columnText; } else { return {}; } } - T extract(sqlite3_stmt* stmt, int colIdx) const { - if(auto cStr = (const char*)sqlite3_column_text(stmt, colIdx)) { + T extract(sqlite3_stmt* stmt, int columnIndex) const { + if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { return cStr; } else { return {}; @@ -236,17 +236,17 @@ namespace sqlite_orm { */ template<> struct row_extractor { - std::wstring extract(const char* colTxt) const { - if(colTxt) { + std::wstring extract(const char* columnText) const { + if(columnText) { std::wstring_convert> converter; - return converter.from_bytes(colTxt); + return converter.from_bytes(columnText); } else { return {}; } } - std::wstring extract(sqlite3_stmt* stmt, int colIdx) const { - auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); + std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); if(cStr) { std::wstring_convert> converter; return converter.from_bytes(cStr); @@ -269,28 +269,28 @@ namespace sqlite_orm { struct row_extractor::value>> { using unqualified_type = std::remove_cv_t; - V extract(const char* colTxt) const + V extract(const char* columnText) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { - if(colTxt) { + if(columnText) { const row_extractor rowExtractor{}; - return is_std_ptr::make(rowExtractor.extract(colTxt)); + return is_std_ptr::make(rowExtractor.extract(columnText)); } else { return {}; } } - V extract(sqlite3_stmt* stmt, int colIdx) const + V extract(sqlite3_stmt* stmt, int columnIndex) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { - auto type = sqlite3_column_type(stmt, colIdx); + auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { const row_extractor rowExtractor{}; - return is_std_ptr::make(rowExtractor.extract(stmt, colIdx)); + return is_std_ptr::make(rowExtractor.extract(stmt, columnIndex)); } else { return {}; } @@ -316,28 +316,28 @@ namespace sqlite_orm { struct row_extractor>> { using unqualified_type = std::remove_cv_t; - V extract(const char* colTxt) const + V extract(const char* columnText) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { - if(colTxt) { + if(columnText) { const row_extractor rowExtractor{}; - return std::make_optional(rowExtractor.extract(colTxt)); + return std::make_optional(rowExtractor.extract(columnText)); } else { return std::nullopt; } } - V extract(sqlite3_stmt* stmt, int colIdx) const + V extract(sqlite3_stmt* stmt, int columnIndex) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { - auto type = sqlite3_column_type(stmt, colIdx); + auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { const row_extractor rowExtractor{}; - return std::make_optional(rowExtractor.extract(stmt, colIdx)); + return std::make_optional(rowExtractor.extract(stmt, columnIndex)); } else { return std::nullopt; } @@ -361,11 +361,11 @@ namespace sqlite_orm { template<> struct row_extractor { - nullptr_t extract(const char* /*colTxt*/) const { + nullptr_t extract(const char* /*columnText*/) const { return nullptr; } - nullptr_t extract(sqlite3_stmt*, int /*colIdx*/) const { + nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { return nullptr; } @@ -378,13 +378,13 @@ namespace sqlite_orm { */ template<> struct row_extractor> { - std::vector extract(const char* colTxt) const { - return {colTxt, colTxt + (colTxt ? ::strlen(colTxt) : 0)}; + std::vector extract(const char* columnText) const { + return {columnText, columnText + (columnText ? ::strlen(columnText) : 0)}; } - std::vector extract(sqlite3_stmt* stmt, int colIdx) const { - auto bytes = static_cast(sqlite3_column_blob(stmt, colIdx)); - auto len = static_cast(sqlite3_column_bytes(stmt, colIdx)); + std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { + auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); + auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); return {bytes, bytes + len}; } @@ -405,7 +405,7 @@ namespace sqlite_orm { return this->extract(argv, std::make_index_sequence{}); } - std::tuple extract(sqlite3_stmt* stmt, int /*colIdx*/) const { + std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { return this->extract(stmt, std::make_index_sequence{}); } @@ -426,9 +426,9 @@ namespace sqlite_orm { */ template<> struct row_extractor { - journal_mode extract(const char* colTxt) const { - if(colTxt) { - if(auto res = internal::journal_mode_from_string(colTxt)) { + journal_mode extract(const char* columnText) const { + if(columnText) { + if(auto res = internal::journal_mode_from_string(columnText)) { return std::move(*res); } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; @@ -438,8 +438,8 @@ namespace sqlite_orm { } } - journal_mode extract(sqlite3_stmt* stmt, int colIdx) const { - auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); + journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); return this->extract(cStr); } }; diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index 31b0c9fd8..e020f8015 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -8759,12 +8759,12 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - V extract(const char* colTxt) const { - return this->extract(colTxt, tag()); + V extract(const char* columnText) const { + return this->extract(columnText, tag()); } - V extract(sqlite3_stmt* stmt, int colIdx) const { - return this->extract(stmt, colIdx, tag()); + V extract(sqlite3_stmt* stmt, int columnIndex) const { + return this->extract(stmt, columnIndex, tag()); } V extract(sqlite3_value* value) const { @@ -8774,36 +8774,36 @@ namespace sqlite_orm { private: using tag = arithmetic_tag_t; - V extract(const char* colTxt, const int_or_smaller_tag&) const { - return static_cast(atoi(colTxt)); + V extract(const char* columnText, const int_or_smaller_tag&) const { + return static_cast(atoi(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const int_or_smaller_tag&) const { - return static_cast(sqlite3_column_int(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { + return static_cast(sqlite3_column_int(stmt, columnIndex)); } V extract(sqlite3_value* value, const int_or_smaller_tag&) const { return static_cast(sqlite3_value_int(value)); } - V extract(const char* colTxt, const bigint_tag&) const { - return static_cast(atoll(colTxt)); + V extract(const char* columnText, const bigint_tag&) const { + return static_cast(atoll(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const bigint_tag&) const { - return static_cast(sqlite3_column_int64(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { + return static_cast(sqlite3_column_int64(stmt, columnIndex)); } V extract(sqlite3_value* value, const bigint_tag&) const { return static_cast(sqlite3_value_int64(value)); } - V extract(const char* colTxt, const real_tag&) const { - return static_cast(atof(colTxt)); + V extract(const char* columnText, const real_tag&) const { + return static_cast(atof(columnText)); } - V extract(sqlite3_stmt* stmt, int colIdx, const real_tag&) const { - return static_cast(sqlite3_column_double(stmt, colIdx)); + V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { + return static_cast(sqlite3_column_double(stmt, columnIndex)); } V extract(sqlite3_value* value, const real_tag&) const { @@ -8816,16 +8816,16 @@ namespace sqlite_orm { */ template struct row_extractor::value>> { - T extract(const char* colTxt) const { - if(colTxt) { - return colTxt; + T extract(const char* columnText) const { + if(columnText) { + return columnText; } else { return {}; } } - T extract(sqlite3_stmt* stmt, int colIdx) const { - if(auto cStr = (const char*)sqlite3_column_text(stmt, colIdx)) { + T extract(sqlite3_stmt* stmt, int columnIndex) const { + if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { return cStr; } else { return {}; @@ -8846,17 +8846,17 @@ namespace sqlite_orm { */ template<> struct row_extractor { - std::wstring extract(const char* colTxt) const { - if(colTxt) { + std::wstring extract(const char* columnText) const { + if(columnText) { std::wstring_convert> converter; - return converter.from_bytes(colTxt); + return converter.from_bytes(columnText); } else { return {}; } } - std::wstring extract(sqlite3_stmt* stmt, int colIdx) const { - auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); + std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); if(cStr) { std::wstring_convert> converter; return converter.from_bytes(cStr); @@ -8879,28 +8879,28 @@ namespace sqlite_orm { struct row_extractor::value>> { using unqualified_type = std::remove_cv_t; - V extract(const char* colTxt) const + V extract(const char* columnText) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { - if(colTxt) { + if(columnText) { const row_extractor rowExtractor{}; - return is_std_ptr::make(rowExtractor.extract(colTxt)); + return is_std_ptr::make(rowExtractor.extract(columnText)); } else { return {}; } } - V extract(sqlite3_stmt* stmt, int colIdx) const + V extract(sqlite3_stmt* stmt, int columnIndex) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { - auto type = sqlite3_column_type(stmt, colIdx); + auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { const row_extractor rowExtractor{}; - return is_std_ptr::make(rowExtractor.extract(stmt, colIdx)); + return is_std_ptr::make(rowExtractor.extract(stmt, columnIndex)); } else { return {}; } @@ -8926,28 +8926,28 @@ namespace sqlite_orm { struct row_extractor>> { using unqualified_type = std::remove_cv_t; - V extract(const char* colTxt) const + V extract(const char* columnText) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { - if(colTxt) { + if(columnText) { const row_extractor rowExtractor{}; - return std::make_optional(rowExtractor.extract(colTxt)); + return std::make_optional(rowExtractor.extract(columnText)); } else { return std::nullopt; } } - V extract(sqlite3_stmt* stmt, int colIdx) const + V extract(sqlite3_stmt* stmt, int columnIndex) const #ifdef SQLITE_ORM_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { - auto type = sqlite3_column_type(stmt, colIdx); + auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { const row_extractor rowExtractor{}; - return std::make_optional(rowExtractor.extract(stmt, colIdx)); + return std::make_optional(rowExtractor.extract(stmt, columnIndex)); } else { return std::nullopt; } @@ -8971,11 +8971,11 @@ namespace sqlite_orm { template<> struct row_extractor { - nullptr_t extract(const char* /*colTxt*/) const { + nullptr_t extract(const char* /*columnText*/) const { return nullptr; } - nullptr_t extract(sqlite3_stmt*, int /*colIdx*/) const { + nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { return nullptr; } @@ -8988,13 +8988,13 @@ namespace sqlite_orm { */ template<> struct row_extractor> { - std::vector extract(const char* colTxt) const { - return {colTxt, colTxt + (colTxt ? ::strlen(colTxt) : 0)}; + std::vector extract(const char* columnText) const { + return {columnText, columnText + (columnText ? ::strlen(columnText) : 0)}; } - std::vector extract(sqlite3_stmt* stmt, int colIdx) const { - auto bytes = static_cast(sqlite3_column_blob(stmt, colIdx)); - auto len = static_cast(sqlite3_column_bytes(stmt, colIdx)); + std::vector extract(sqlite3_stmt* stmt, int columnIndex) const { + auto bytes = static_cast(sqlite3_column_blob(stmt, columnIndex)); + auto len = static_cast(sqlite3_column_bytes(stmt, columnIndex)); return {bytes, bytes + len}; } @@ -9015,7 +9015,7 @@ namespace sqlite_orm { return this->extract(argv, std::make_index_sequence{}); } - std::tuple extract(sqlite3_stmt* stmt, int /*colIdx*/) const { + std::tuple extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { return this->extract(stmt, std::make_index_sequence{}); } @@ -9036,9 +9036,9 @@ namespace sqlite_orm { */ template<> struct row_extractor { - journal_mode extract(const char* colTxt) const { - if(colTxt) { - if(auto res = internal::journal_mode_from_string(colTxt)) { + journal_mode extract(const char* columnText) const { + if(columnText) { + if(auto res = internal::journal_mode_from_string(columnText)) { return std::move(*res); } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; @@ -9048,8 +9048,8 @@ namespace sqlite_orm { } } - journal_mode extract(sqlite3_stmt* stmt, int colIdx) const { - auto cStr = (const char*)sqlite3_column_text(stmt, colIdx); + journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { + auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); return this->extract(cStr); } }; From 84849cce96726c04df21ca14d24b5dee31c4e9b7 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 19 Jul 2023 10:45:59 +0300 Subject: [PATCH 10/12] Must use nested namespace specifier in row extractor unit test --- tests/row_extractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/row_extractor.cpp b/tests/row_extractor.cpp index 88e63b2e6..a926c08ab 100644 --- a/tests/row_extractor.cpp +++ b/tests/row_extractor.cpp @@ -39,7 +39,7 @@ template<> struct sqlite_orm::type_printer : public text_printer {}; template<> -struct statement_binder { +struct sqlite_orm::statement_binder { int bind(sqlite3_stmt* stmt, int index, const Gender& value) { return statement_binder().bind(stmt, index, GenderToString(value)); From 64e1e91bf712c53f46f72a6c0e5ff05efe1671e5 Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 19 Jul 2023 12:04:41 +0300 Subject: [PATCH 11/12] Included --- dev/row_extractor.h | 23 ++++++++++++--------- dev/xdestroy_handling.h | 8 +++---- include/sqlite_orm/sqlite_orm.h | 31 +++++++++++++++------------- tests/static_tests/row_extractor.cpp | 14 +++++++++---- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/dev/row_extractor.h b/dev/row_extractor.h index 971a13527..785c9834e 100644 --- a/dev/row_extractor.h +++ b/dev/row_extractor.h @@ -14,6 +14,9 @@ #include // std::copy #include // std::back_inserter #include // std::tuple, std::tuple_size, std::tuple_element +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#include +#endif #include "functional/cxx_universal.h" #include "arithmetic_tag.h" @@ -56,7 +59,7 @@ namespace sqlite_orm { V extract(sqlite3_value* value) const = delete; }; -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED template concept orm_column_text_extractable = requires(const row_extractor& extractor, const char* columnText) { { extractor.extract(columnText) } -> std::same_as; @@ -79,7 +82,7 @@ namespace sqlite_orm { * Make a row extractor to be used for casting SQL column text to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif row_extractor column_text_extractor() { @@ -90,7 +93,7 @@ namespace sqlite_orm { * Make a row extractor to be used for converting a value from a SQL result row set to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif row_extractor row_value_extractor() { @@ -101,7 +104,7 @@ namespace sqlite_orm { * Make a row extractor to be used for unboxing a dynamically typed SQL value to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif row_extractor boxed_value_extractor() { @@ -270,7 +273,7 @@ namespace sqlite_orm { using unqualified_type = std::remove_cv_t; V extract(const char* columnText) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { @@ -283,7 +286,7 @@ namespace sqlite_orm { } V extract(sqlite3_stmt* stmt, int columnIndex) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { @@ -297,7 +300,7 @@ namespace sqlite_orm { } V extract(sqlite3_value* value) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif { @@ -317,7 +320,7 @@ namespace sqlite_orm { using unqualified_type = std::remove_cv_t; V extract(const char* columnText) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { @@ -330,7 +333,7 @@ namespace sqlite_orm { } V extract(sqlite3_stmt* stmt, int columnIndex) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { @@ -344,7 +347,7 @@ namespace sqlite_orm { } V extract(sqlite3_value* value) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif { diff --git a/dev/xdestroy_handling.h b/dev/xdestroy_handling.h index 75b89c6bb..7746f8402 100644 --- a/dev/xdestroy_handling.h +++ b/dev/xdestroy_handling.h @@ -1,7 +1,7 @@ #pragma once #include // std::integral_constant -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #include #endif @@ -45,7 +45,7 @@ namespace sqlite_orm { }; #endif -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED /** * Yield a deleter's function pointer. */ @@ -95,7 +95,7 @@ namespace sqlite_orm { template using yielded_fn_t = typename yield_fp_of::type; -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED template concept is_unusable_for_xdestroy = (!stateless_deleter && (yields_fp && !std::convertible_to, xdestroy_fn_t>)); @@ -175,7 +175,7 @@ namespace sqlite_orm { namespace sqlite_orm { -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED /** * Prohibits using a yielded function pointer, which is not of type xdestroy_fn_t. * diff --git a/include/sqlite_orm/sqlite_orm.h b/include/sqlite_orm/sqlite_orm.h index e020f8015..6a5db1dd0 100644 --- a/include/sqlite_orm/sqlite_orm.h +++ b/include/sqlite_orm/sqlite_orm.h @@ -7661,7 +7661,7 @@ namespace sqlite_orm { // #include "xdestroy_handling.h" #include // std::integral_constant -#if defined(SQLITE_ORM_CONCEPTS_SUPPORTED) && SQLITE_ORM_HAS_INCLUDE() +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #include #endif @@ -7706,7 +7706,7 @@ namespace sqlite_orm { }; #endif -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED /** * Yield a deleter's function pointer. */ @@ -7756,7 +7756,7 @@ namespace sqlite_orm { template using yielded_fn_t = typename yield_fp_of::type; -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED template concept is_unusable_for_xdestroy = (!stateless_deleter && (yields_fp && !std::convertible_to, xdestroy_fn_t>)); @@ -7836,7 +7836,7 @@ namespace sqlite_orm { namespace sqlite_orm { -#if __cpp_lib_concepts >= 201907L +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED /** * Prohibits using a yielded function pointer, which is not of type xdestroy_fn_t. * @@ -8547,6 +8547,9 @@ namespace sqlite_orm { #include // std::copy #include // std::back_inserter #include // std::tuple, std::tuple_size, std::tuple_element +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED +#include +#endif // #include "functional/cxx_universal.h" @@ -8666,7 +8669,7 @@ namespace sqlite_orm { V extract(sqlite3_value* value) const = delete; }; -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED template concept orm_column_text_extractable = requires(const row_extractor& extractor, const char* columnText) { { extractor.extract(columnText) } -> std::same_as; @@ -8689,7 +8692,7 @@ namespace sqlite_orm { * Make a row extractor to be used for casting SQL column text to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif row_extractor column_text_extractor() { @@ -8700,7 +8703,7 @@ namespace sqlite_orm { * Make a row extractor to be used for converting a value from a SQL result row set to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif row_extractor row_value_extractor() { @@ -8711,7 +8714,7 @@ namespace sqlite_orm { * Make a row extractor to be used for unboxing a dynamically typed SQL value to a C++ typed value. */ template -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif row_extractor boxed_value_extractor() { @@ -8880,7 +8883,7 @@ namespace sqlite_orm { using unqualified_type = std::remove_cv_t; V extract(const char* columnText) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { @@ -8893,7 +8896,7 @@ namespace sqlite_orm { } V extract(sqlite3_stmt* stmt, int columnIndex) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { @@ -8907,7 +8910,7 @@ namespace sqlite_orm { } V extract(sqlite3_value* value) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif { @@ -8927,7 +8930,7 @@ namespace sqlite_orm { using unqualified_type = std::remove_cv_t; V extract(const char* columnText) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_column_text_extractable) #endif { @@ -8940,7 +8943,7 @@ namespace sqlite_orm { } V extract(sqlite3_stmt* stmt, int columnIndex) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_row_value_extractable) #endif { @@ -8954,7 +8957,7 @@ namespace sqlite_orm { } V extract(sqlite3_value* value) const -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED requires(orm_boxed_value_extractable) #endif { diff --git a/tests/static_tests/row_extractor.cpp b/tests/static_tests/row_extractor.cpp index 854151242..6a2d3bf28 100644 --- a/tests/static_tests/row_extractor.cpp +++ b/tests/static_tests/row_extractor.cpp @@ -31,7 +31,7 @@ static void check_not_extractable() { } namespace { - enum class custom_enum {}; + enum class custom_enum { custom }; template class StringVeneer : public std::basic_string {}; @@ -43,9 +43,15 @@ namespace { template<> struct sqlite_orm::row_extractor { - custom_enum extract(const char* /*columnText*/) const {} - custom_enum extract(sqlite3_stmt*, int /*columnIndex*/) const {} - custom_enum extract(sqlite3_value*) const {} + custom_enum extract(const char* /*columnText*/) const { + return custom_enum::custom; + } + custom_enum extract(sqlite3_stmt*, int /*columnIndex*/) const { + return custom_enum::custom; + } + custom_enum extract(sqlite3_value*) const { + return custom_enum::custom; + } }; TEST_CASE("is_extractable") { From 98ea5849f30f90beaf2dfa0e22a792ed5349582b Mon Sep 17 00:00:00 2001 From: klaus triendl Date: Wed, 19 Jul 2023 13:01:37 +0300 Subject: [PATCH 12/12] Using same CPP guard for unit test like for row extractor --- tests/static_tests/row_extractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/static_tests/row_extractor.cpp b/tests/static_tests/row_extractor.cpp index 6a2d3bf28..4535f0052 100644 --- a/tests/static_tests/row_extractor.cpp +++ b/tests/static_tests/row_extractor.cpp @@ -1,5 +1,5 @@ #include -#ifdef SQLITE_ORM_CONCEPTS_SUPPORTED +#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED #define ENABLE_THIS_UT #endif