/
UCS
/
sqlite_orm
Обзор
Документация
Войти
/
UCS
/
sqlite_orm
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
examples/pointer_passing_interface.cpp
228 строк
9 KB
klaus triendl
Fixed availability of pointer passing example
16 янв 2023, 11:02
16 янв 2023, 11:02
b9bcc29
Код
Авторство
О чём код?
/** * Example of how to use the pointer-passing interface, creating an ad-hoc sqlite extension. * * It demonstrates how to modularize turning a seralized representation of an object * into C/C++ native object instance, plus invoking operations on that object. * This approach is much better in regard to encapsulation in contrary to defining a set of * functions which always only accept the serialized representation of an object. * * This example assumes an application that deals with a fixed set of c++ system error categories and codes, * which are also stored in a result table: * - stores results of some type, along with a error category enumeration and an error code. * - registers a sqlite scalar function getting the pointer to the error category. * - registers another set of sqlite scalar functions that accept a pointer to an error category. * - registers a sqlite scalar function creating a std::error_code. * - registers a sqlite scalar function comparing two std::error_code. * * Note: pointers are only accessible within application code, and therefore unleakable. */ #include <sqlite_orm/sqlite_orm.h> #ifdef SQLITE_ORM_INLINE_VARIABLES_SUPPORTED #define ENABLE_THIS_EXAMPLE #endif #ifdef ENABLE_THIS_EXAMPLE #include <type_traits> #include <tuple> #include <system_error> #include <future> #include <string> #include <algorithm> #include <iostream> using namespace sqlite_orm; using std::cout; using std::default_delete; using std::endl; using std::error_category; using std::error_code; using std::make_unique; using std::min; // name for our pointer value types inline constexpr const char ecat_pvt_name[] = "ecat"; inline constexpr const char ecode_pvt_name[] = "ecode"; // c++ integral constant for our pointer value types using ecat_pvt = std::integral_constant<const char*, ecat_pvt_name>; using ecode_pvt = std::integral_constant<const char*, ecode_pvt_name>; // a fixed set of error categories the application is dealing with enum class app_error_category : unsigned int { generic, system, io, future, sqlite_orm, }; // map app_error_category enum to std::error_category // sorted by app_error_category using ecat_map_t = std::tuple<const app_error_category, const std::error_category&>; extern const std::array<ecat_map_t, 5> ecat_map; const std::array<ecat_map_t, 5> ecat_map = {{ {app_error_category::generic, std::generic_category()}, {app_error_category::system, std::system_category()}, {app_error_category::io, std::iostream_category()}, {app_error_category::future, std::future_category()}, {app_error_category::sqlite_orm, sqlite_orm::get_sqlite_error_category()}, }}; template<char A, char... L> struct str_alias : alias_tag { static constexpr char str[] = {A, L..., '\0'}; static constexpr const char* get() { return str; } }; #endif int main() { #ifdef ENABLE_THIS_EXAMPLE // table structure for results of some type struct Result { int id = 0; int errorValue = 0; unsigned int errorCategory = 0; }; using ecat_arg_t = pointer_arg<const std::error_category, ecat_pvt>; using ecode_arg_t = pointer_arg<std::error_code, ecode_pvt>; // function returning a pointer to a std::error_category, // which is only visible to functions accepting pointer values of type "ecat" struct get_error_category_fn { using ecat_binding = static_pointer_binding<const std::error_category, ecat_pvt>; ecat_binding operator()(unsigned int errorCategory) const { size_t idx = min<size_t>(errorCategory, ecat_map.size()); const error_category* ecat = idx != ecat_map.size() ? &get<const error_category&>(ecat_map[idx]) : nullptr; return statically_bindable_pointer<ecat_pvt>(ecat); } static constexpr const char* name() { return "get_error_category"; } }; // function accepting a pointer to a std::error_category, // returns the category's name struct error_category_name_fn { std::string operator()(ecat_arg_t pv) const { if(const error_category* ec = pv) { return ec->name(); } return {}; } static constexpr const char* name() { return "error_category_name"; } }; // function accepting a pointer to a std::error_category and an error code, // returns the error message struct error_category_message_fn { std::string operator()(ecat_arg_t pv, int errorValue) const { if(const error_category* ec = pv) { return ec->message(errorValue); } return {}; } static constexpr const char* name() { return "error_category_message"; } }; // function returning an error_code object from an error value struct make_error_code_fn { using ecode_binding = pointer_binding<std::error_code, ecode_pvt, std::default_delete<std::error_code>>; ecode_binding operator()(int errorValue, unsigned int errorCategory) const { size_t idx = min<size_t>(errorCategory, ecat_map.size()); error_code* ec = idx != ecat_map.size() ? new error_code{errorValue, get<const error_category&>(ecat_map[idx])} : nullptr; return bindable_pointer<ecode_binding>(ec, default_delete<error_code>{}); } static constexpr const char* name() { return "make_error_code"; } }; // function comparing two error_code objects struct equal_error_code_fn { bool operator()(ecode_arg_t pv1, ecode_arg_t pv2) const { error_code *ec1 = pv1, *ec2 = pv2; if(ec1 && ec2) { return *ec1 == *ec2; } return false; } static constexpr const char* name() { return "equal_error_code"; } }; auto storage = make_storage({}, make_table("result", make_column("id", &Result::id, primary_key()), make_column("error_value", &Result::errorValue), make_column("error_category", &Result::errorCategory))); storage.sync_schema(); storage.transaction([&storage] { storage.replace(Result{1, 2, 0}); storage.replace(Result{2, 0, 1}); storage.replace(Result{3, 1, 2}); storage.replace(Result{4, 1, 3}); storage.replace(Result{5, 0, 4}); // error category out of bounds, get_error_category() will return null storage.replace(Result{6, 0, 5}); return true; }); storage.create_scalar_function<get_error_category_fn>(); storage.create_scalar_function<error_category_name_fn>(); storage.create_scalar_function<error_category_message_fn>(); storage.create_scalar_function<make_error_code_fn>(); storage.create_scalar_function<equal_error_code_fn>(); // list all results including error category name and error message { // SELECT id, not error_value as ok, error_category, error_value, // equal_error_code(make_error_code(error_value, error_category), ?), // error_category_name(get_error_category(error_category)), // error_category_message(get_error_category(error_category), error_value) // FROM result // ORDER BY not error_value, error_category, error_value, id; auto rows = storage.select(columns(&Result::id, as<str_alias<'o', 'k'>>(c(&Result::errorValue) == 0), &Result::errorValue, &Result::errorCategory, as<str_alias<'e', 'q'>>(func<equal_error_code_fn>( func<make_error_code_fn>(&Result::errorValue, &Result::errorCategory), bindable_pointer<ecode_pvt>(make_unique<error_code>()))), func<error_category_name_fn>(func<get_error_category_fn>(&Result::errorCategory)), func<error_category_message_fn>(func<get_error_category_fn>(&Result::errorCategory), &Result::errorValue)), multi_order_by(order_by(c(&Result::errorValue) == 0), order_by(&Result::errorCategory), order_by(&Result::errorValue), order_by(&Result::id))); for(auto& row: rows) { cout << std::get<0>(row) << ' ' << std::get<1>(row) << ' ' << std::get<2>(row) << ' ' << std::get<3>(row) << ' ' << std::get<4>(row) << " \"" << std::get<5>(row) << "\"" << " \"" << std::get<6>(row) << "\"" << endl; } cout << endl; } #endif return 0; }