/
UCS
/
sqlite_orm
Обзор
Документация
Войти
/
UCS
/
sqlite_orm
Код
Запросы
0
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
dev/row_extractor.h
340 строк
11 KB
klaus triendl
Tuple expansion for statement and row binding
18 май 2022, 23:35
18 май 2022, 23:35
a6831ac
Код
Авторство
О чём код?
#pragma once #include <sqlite3.h> #include <type_traits> // std::enable_if_t, std::is_arithmetic, std::is_same, std::enable_if #include <stdlib.h> // atof, atoi, atoll #include <system_error> // std::system_error #include <string> // std::string, std::wstring #ifndef SQLITE_ORM_OMITS_CODECVT #include <codecvt> // std::wstring_convert, std::codecvt_utf8_utf16 #endif // SQLITE_ORM_OMITS_CODECVT #include <vector> // std::vector #include <cstring> // strlen #include <locale> #include <algorithm> // std::copy #include <iterator> // std::back_inserter #include <tuple> // std::tuple, std::tuple_size, std::tuple_element #include "functional/cxx_universal.h" #include "arithmetic_tag.h" #include "pointer_value.h" #include "journal_mode.h" #include "error_code.h" #include "is_std_ptr.h" namespace sqlite_orm { /** * Helper class used to cast values from argv to V class * which depends from column type. * */ template<class V, typename Enable = void> struct row_extractor { // used in sqlite3_exec (select) V extract(const char* row_value) const = delete; // used in sqlite_column (iteration, get_all) V extract(sqlite3_stmt* stmt, int columnIndex) const = delete; // used in user defined functions V extract(sqlite3_value* value) const = delete; }; template<class R> int extract_single_value(void* data, int argc, char** argv, char**) { auto& res = *(R*)data; if(argc) { res = row_extractor<R>{}.extract(argv[0]); } return 0; } /** * Specialization for the 'pointer-passing interface'. * * @note The 'pointer-passing' interface doesn't support (and in fact prohibits) * extracting pointers from columns. */ template<class P, class T> struct row_extractor<pointer_arg<P, T>, void> { using V = pointer_arg<P, T>; V extract(sqlite3_value* value) const { return {(P*)sqlite3_value_pointer(value, T::value)}; } }; /** * Undefine using pointer_binding<> for querying values */ template<class P, class T, class D> struct row_extractor<pointer_binding<P, T, D>, void>; /** * Specialization for arithmetic types. */ template<class V> struct row_extractor<V, std::enable_if_t<std::is_arithmetic<V>::value>> { V extract(const char* row_value) const { return this->extract(row_value, tag()); } V extract(sqlite3_stmt* stmt, int columnIndex) const { return this->extract(stmt, columnIndex, tag()); } V extract(sqlite3_value* value) const { return this->extract(value, tag()); } private: using tag = arithmetic_tag_t<V>; V extract(const char* row_value, const int_or_smaller_tag&) const { return static_cast<V>(atoi(row_value)); } V extract(sqlite3_stmt* stmt, int columnIndex, const int_or_smaller_tag&) const { return static_cast<V>(sqlite3_column_int(stmt, columnIndex)); } V extract(sqlite3_value* value, const int_or_smaller_tag&) const { return static_cast<V>(sqlite3_value_int(value)); } V extract(const char* row_value, const bigint_tag&) const { return static_cast<V>(atoll(row_value)); } V extract(sqlite3_stmt* stmt, int columnIndex, const bigint_tag&) const { return static_cast<V>(sqlite3_column_int64(stmt, columnIndex)); } V extract(sqlite3_value* value, const bigint_tag&) const { return static_cast<V>(sqlite3_value_int64(value)); } V extract(const char* row_value, const real_tag&) const { return static_cast<V>(atof(row_value)); } V extract(sqlite3_stmt* stmt, int columnIndex, const real_tag&) const { return static_cast<V>(sqlite3_column_double(stmt, columnIndex)); } V extract(sqlite3_value* value, const real_tag&) const { return static_cast<V>(sqlite3_value_double(value)); } }; /** * Specialization for std::string. */ template<> struct row_extractor<std::string, void> { std::string extract(const char* row_value) const { if(row_value) { return row_value; } else { return {}; } } std::string extract(sqlite3_stmt* stmt, int columnIndex) const { if(auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex)) { return cStr; } else { return {}; } } std::string extract(sqlite3_value* value) const { if(auto cStr = (const char*)sqlite3_value_text(value)) { return cStr; } else { return {}; } } }; #ifndef SQLITE_ORM_OMITS_CODECVT /** * Specialization for std::wstring. */ template<> struct row_extractor<std::wstring, void> { std::wstring extract(const char* row_value) const { if(row_value) { std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; return converter.from_bytes(row_value); } else { return {}; } } std::wstring extract(sqlite3_stmt* stmt, int columnIndex) const { auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); if(cStr) { std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; return converter.from_bytes(cStr); } else { return {}; } } std::wstring extract(sqlite3_value* value) const { if(auto cStr = (const wchar_t*)sqlite3_value_text16(value)) { return cStr; } else { return {}; } } }; #endif // SQLITE_ORM_OMITS_CODECVT template<class V> struct row_extractor<V, std::enable_if_t<is_std_ptr<V>::value>> { using unqualified_type = std::remove_cv_t<typename V::element_type>; V extract(const char* row_value) const { if(row_value) { return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(row_value)); } else { return {}; } } V extract(sqlite3_stmt* stmt, int columnIndex) const { auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(stmt, columnIndex)); } else { return {}; } } V extract(sqlite3_value* value) const { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { return is_std_ptr<V>::make(row_extractor<unqualified_type>().extract(value)); } else { return {}; } } }; #ifdef SQLITE_ORM_OPTIONAL_SUPPORTED template<class V> struct row_extractor<V, std::enable_if_t<polyfill::is_specialization_of_v<V, std::optional>>> { using unqualified_type = std::remove_cv_t<typename V::value_type>; V extract(const char* row_value) const { if(row_value) { return std::make_optional(row_extractor<unqualified_type>().extract(row_value)); } else { return std::nullopt; } } V extract(sqlite3_stmt* stmt, int columnIndex) const { auto type = sqlite3_column_type(stmt, columnIndex); if(type != SQLITE_NULL) { return std::make_optional(row_extractor<unqualified_type>().extract(stmt, columnIndex)); } else { return std::nullopt; } } V extract(sqlite3_value* value) const { auto type = sqlite3_value_type(value); if(type != SQLITE_NULL) { return std::make_optional(row_extractor<unqualified_type>().extract(value)); } else { return std::nullopt; } } }; #endif // SQLITE_ORM_OPTIONAL_SUPPORTED template<> struct row_extractor<nullptr_t> { nullptr_t extract(const char* /*row_value*/) const { return nullptr; } nullptr_t extract(sqlite3_stmt*, int /*columnIndex*/) const { return nullptr; } nullptr_t extract(sqlite3_value*) const { return nullptr; } }; /** * Specialization for std::vector<char>. */ template<> struct row_extractor<std::vector<char>> { std::vector<char> extract(const char* row_value) const { return {row_value, row_value + (row_value ? ::strlen(row_value) : 0)}; } std::vector<char> extract(sqlite3_stmt* stmt, int columnIndex) const { auto bytes = static_cast<const char*>(sqlite3_column_blob(stmt, columnIndex)); auto len = static_cast<size_t>(sqlite3_column_bytes(stmt, columnIndex)); return {bytes, bytes + len}; } std::vector<char> extract(sqlite3_value* value) const { auto bytes = static_cast<const char*>(sqlite3_value_blob(value)); auto len = static_cast<size_t>(sqlite3_value_bytes(value)); return {bytes, bytes + len}; } }; template<class... Args> struct row_extractor<std::tuple<Args...>> { std::tuple<Args...> extract(char** argv) const { return this->extract(argv, std::make_index_sequence<sizeof...(Args)>{}); } std::tuple<Args...> extract(sqlite3_stmt* stmt, int /*columnIndex*/) const { return this->extract(stmt, std::make_index_sequence<sizeof...(Args)>{}); } protected: template<size_t... Idx> std::tuple<Args...> extract(sqlite3_stmt* stmt, std::index_sequence<Idx...>) const { return std::tuple<Args...>{row_extractor<Args>{}.extract(stmt, Idx)...}; } template<size_t... Idx> std::tuple<Args...> extract(char** argv, std::index_sequence<Idx...>) const { return std::tuple<Args...>{row_extractor<Args>{}.extract(argv[Idx])...}; } }; /** * Specialization for journal_mode. */ template<> struct row_extractor<journal_mode, void> { journal_mode extract(const char* row_value) const { if(row_value) { if(auto res = internal::journal_mode_from_string(row_value)) { return std::move(*res); } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; } } else { throw std::system_error{orm_error_code::incorrect_journal_mode_string}; } } journal_mode extract(sqlite3_stmt* stmt, int columnIndex) const { auto cStr = (const char*)sqlite3_column_text(stmt, columnIndex); return this->extract(cStr); } }; }