diff --git a/ormpp/mysql.hpp b/ormpp/mysql.hpp index 482d145..68d9f80 100644 --- a/ormpp/mysql.hpp +++ b/ormpp/mysql.hpp @@ -16,8 +16,6 @@ namespace ormpp { -using blob = ormpp_mysql::blob; - class mysql { public: ~mysql() { disconnect(); } @@ -193,6 +191,13 @@ class mysql { param.buffer = (void *)(value.data()); param.buffer_length = (unsigned long)value.size(); } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + param.buffer_type = MYSQL_TYPE_STRING; + param.buffer = (void *)(value.GetString()); + param.buffer_length = (unsigned long)value.GetLength(); + } +#endif else { static_assert(!sizeof(U), "this type has not supported yet"); } @@ -241,6 +246,15 @@ class mysql { param_bind.buffer = &(mp.rbegin()->second[0]); param_bind.buffer_length = 65536; } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + param_bind.buffer_type = MYSQL_TYPE_STRING; + std::vector tmp(65536, 0); + mp.emplace(i, std::move(tmp)); + param_bind.buffer = &(mp.rbegin()->second[0]); + param_bind.buffer_length = 65536; + } +#endif else { static_assert(!sizeof(U), "this type has not supported yet"); } @@ -276,6 +290,12 @@ class mysql { auto &vec = mp[i]; value = blob(vec.data(), vec.data() + get_blob_len(i)); } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + auto &vec = mp[i]; + value.SetString(std::string(&vec[0], strlen(vec.data()).c_str())); + } +#endif } template diff --git a/ormpp/postgresql.hpp b/ormpp/postgresql.hpp index ac104c5..52626b6 100644 --- a/ormpp/postgresql.hpp +++ b/ormpp/postgresql.hpp @@ -719,6 +719,20 @@ class postgresql { std::copy(value, value + sizeof(U), std::back_inserter(temp)); param_values.push_back(std::move(temp)); } + else if constexpr (std::is_same_v) { + std::vector temp = {}; + std::copy(value.data(), value.data() + value.size(), + std::back_inserter(temp)); + param_values.push_back(std::move(temp)); + } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + std::vector temp = {}; + std::copy(value.GetString(), value.GetString() + value.GetLength() + 1, + std::back_inserter(temp)); + param_values.push_back(std::move(temp)); + } +#endif else { static_assert(!sizeof(U), "this type has not supported yet"); } @@ -752,14 +766,23 @@ class postgresql { else if constexpr (std::is_same_v) { value = PQgetvalue(res_, row, i); } + else if constexpr (iguana::array_v) { + auto p = PQgetvalue(res_, row, i); + memcpy(value.data(), p, value.size()); + } else if constexpr (iguana::c_array_v) { auto p = PQgetvalue(res_, row, i); memcpy(value, p, sizeof(U)); } - else if constexpr (iguana::array_v) { + else if constexpr (std::is_same_v) { auto p = PQgetvalue(res_, row, i); - memcpy(value.data(), p, value.size()); + value = blob(p, p + PQgetlength(res_, row, i)); } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + value.SetString(PQgetvalue(res_, row, i)); + } +#endif else { static_assert(!sizeof(U), "this type has not supported yet"); } diff --git a/ormpp/sqlite.hpp b/ormpp/sqlite.hpp index 02f27ab..89d64ed 100644 --- a/ormpp/sqlite.hpp +++ b/ormpp/sqlite.hpp @@ -572,10 +572,16 @@ class sqlite { return SQLITE_OK == sqlite3_bind_text(stmt_, i, value, strlen(value), nullptr); } + else if constexpr (std::is_same_v) { + return SQLITE_OK == sqlite3_bind_blob(stmt_, i, value.data(), + static_cast(value.size()), + nullptr); + } #ifdef ORMPP_WITH_CSTRING else if constexpr (std::is_same_v) { - return SQLITE_OK == sqlite3_bind_text(stmt_, i, value.GetString(), - (int)value.GetLength(), nullptr); + return SQLITE_OK == + sqlite3_bind_text(stmt_, i, value.GetString(), + static_cast(value.GetLength()), nullptr); } #endif else { @@ -624,6 +630,10 @@ class sqlite { else if constexpr (iguana::c_array_v) { memcpy(value, sqlite3_column_text(stmt_, i), sizeof(U)); } + else if constexpr (std::is_same_v) { + auto p = (const char *)sqlite3_column_blob(stmt_, i); + value = blob(p, p + sqlite3_column_bytes(stmt_, i)); + } #ifdef ORMPP_WITH_CSTRING else if constexpr (std::is_same_v) { value.SetString((const char *)sqlite3_column_text(stmt_, i)); diff --git a/ormpp/type_mapping.hpp b/ormpp/type_mapping.hpp index 7699571..5c09a27 100644 --- a/ormpp/type_mapping.hpp +++ b/ormpp/type_mapping.hpp @@ -19,36 +19,34 @@ using namespace std::string_view_literals; #define EXAMPLE1_TYPE_MAPPING_HPP namespace ormpp { + +using blob = std::vector; + template struct identity {}; -#define REGISTER_TYPE(Type, Index) \ - inline constexpr int type_to_id(identity) noexcept { return Index; } \ - inline constexpr auto id_to_type( \ - std::integral_constant) noexcept { \ - Type res{}; \ - return res; \ - } - #ifdef ORMPP_ENABLE_MYSQL namespace ormpp_mysql { -REGISTER_TYPE(char, MYSQL_TYPE_TINY) -REGISTER_TYPE(short, MYSQL_TYPE_SHORT) -REGISTER_TYPE(int, MYSQL_TYPE_LONG) -REGISTER_TYPE(float, MYSQL_TYPE_FLOAT) -REGISTER_TYPE(double, MYSQL_TYPE_DOUBLE) -REGISTER_TYPE(int64_t, MYSQL_TYPE_LONGLONG) - -using blob = std::vector; - +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_TINY; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_SHORT; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_LONG; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_FLOAT; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_DOUBLE; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_TINY; } +inline int type_to_id(identity) noexcept { + return MYSQL_TYPE_LONGLONG; +} +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_SHORT; } +inline int type_to_id(identity) noexcept { return MYSQL_TYPE_LONG; } +inline int type_to_id(identity) noexcept { + return MYSQL_TYPE_LONGLONG; +} +inline int type_to_id(identity) noexcept { + return MYSQL_TYPE_LONGLONG; +} inline int type_to_id(identity) noexcept { return MYSQL_TYPE_VAR_STRING; } -inline std::string id_to_type( - std::integral_constant) noexcept { - std::string res{}; - return res; -} inline constexpr auto type_to_name(identity) noexcept { return "BOOLEAN"sv; @@ -68,9 +66,24 @@ inline constexpr auto type_to_name(identity) noexcept { inline constexpr auto type_to_name(identity) noexcept { return "DOUBLE"sv; } +inline constexpr auto type_to_name(identity) noexcept { + return "TINYINT"sv; +} inline constexpr auto type_to_name(identity) noexcept { return "BIGINT"sv; } +inline constexpr auto type_to_name(identity) noexcept { + return "SMALLINT"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "BIGINT"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "BIGINT"sv; +} inline constexpr auto type_to_name(identity) noexcept { return "BLOB"sv; } inline auto type_to_name(identity) noexcept { return "TEXT"sv; } template @@ -82,16 +95,12 @@ inline auto type_to_name(identity>) noexcept { #endif #ifdef ORMPP_ENABLE_SQLITE3 namespace ormpp_sqlite { -REGISTER_TYPE(int, SQLITE_INTEGER) -REGISTER_TYPE(double, SQLITE_FLOAT) - -inline int type_to_id(identity) noexcept { return SQLITE_TEXT; } -inline std::string id_to_type( - std::integral_constant) noexcept { - std::string res{}; - return res; +inline constexpr auto type_to_name(identity) noexcept { + return "FLOAT"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "DOUBLE"sv; } - inline constexpr auto type_to_name(identity) noexcept { return "INTEGER"sv; } @@ -104,15 +113,25 @@ inline constexpr auto type_to_name(identity) noexcept { inline constexpr auto type_to_name(identity) noexcept { return "INTEGER"sv; } -inline constexpr auto type_to_name(identity) noexcept { - return "FLOAT"sv; -} -inline constexpr auto type_to_name(identity) noexcept { - return "DOUBLE"sv; +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; } inline constexpr auto type_to_name(identity) noexcept { return "INTEGER"sv; } +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "INTEGER"sv; +} +inline constexpr auto type_to_name(identity) noexcept { return "BLOB"sv; } inline auto type_to_name(identity) noexcept { return "TEXT"sv; } template inline auto type_to_name(identity>) noexcept { @@ -123,21 +142,6 @@ inline auto type_to_name(identity>) noexcept { #endif #ifdef ORMPP_ENABLE_PG namespace ormpp_postgresql { -REGISTER_TYPE(bool, BOOLOID) -REGISTER_TYPE(char, CHAROID) -REGISTER_TYPE(short, INT2OID) -REGISTER_TYPE(int, INT4OID) -REGISTER_TYPE(float, FLOAT4OID) -REGISTER_TYPE(double, FLOAT8OID) -REGISTER_TYPE(int64_t, INT8OID) - -inline int type_to_id(identity) noexcept { return TEXTOID; } -inline std::string id_to_type( - std::integral_constant) noexcept { - std::string res{}; - return res; -} - inline constexpr auto type_to_name(identity) noexcept { return "integer"sv; } @@ -154,9 +158,27 @@ inline constexpr auto type_to_name(identity) noexcept { inline constexpr auto type_to_name(identity) noexcept { return "double precision"sv; } +inline constexpr auto type_to_name(identity) noexcept { + return "char"sv; +} inline constexpr auto type_to_name(identity) noexcept { return "bigint"sv; } +inline constexpr auto type_to_name(identity) noexcept { + return "smallint"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "integer"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "bigint"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "bigint"sv; +} +inline constexpr auto type_to_name(identity) noexcept { + return "bytea"sv; +} inline auto type_to_name(identity) noexcept { return "text"sv; } template inline auto type_to_name(identity>) noexcept { diff --git a/ormpp/utility.hpp b/ormpp/utility.hpp index e615d45..1007b32 100644 --- a/ormpp/utility.hpp +++ b/ormpp/utility.hpp @@ -150,6 +150,11 @@ inline constexpr auto get_type_names(DBType type) { else if constexpr (is_optional_v::value) { s = ormpp_mysql::type_to_name(identity{}); } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + s = "TEXT"sv; + } +#endif else { s = ormpp_mysql::type_to_name(identity{}); } @@ -181,6 +186,11 @@ inline constexpr auto get_type_names(DBType type) { else if constexpr (is_optional_v::value) { s = ormpp_postgresql::type_to_name(identity{}); } +#ifdef ORMPP_WITH_CSTRING + else if constexpr (std::is_same_v) { + s = "TEXT"sv; + } +#endif else { s = ormpp_postgresql::type_to_name(identity{}); } diff --git a/tests/test_ormpp.cpp b/tests/test_ormpp.cpp index 32e0a4d..db31d9a 100644 --- a/tests/test_ormpp.cpp +++ b/tests/test_ormpp.cpp @@ -1029,7 +1029,6 @@ struct validate { } }; -#ifdef ORMPP_ENABLE_MYSQL TEST_CASE("aop") { // dbng mysql; // auto r = mysql.wraper_connect(ip, username, password, @@ -1054,21 +1053,53 @@ struct image { }; REFLECTION(image, id, bin); -TEST_CASE("mysql blob") { +TEST_CASE("blob") { +#ifdef ORMPP_ENABLE_MYSQL dbng mysql; if (mysql.connect(ip, username, password, db)) { - mysql.execute("DROP TABLE IF EXISTS image"); + mysql.execute("drop table if exists image"); mysql.create_datatable(); auto data = "this is a test binary stream\0, and ?..."; auto size = 40; - image img; - img.id = 1; + image img{1}; img.bin.assign(data, data + size); CHECK(mysql.insert(img) == 1); - auto vec = mysql.query("id=1"); + auto vec = mysql.query_s("id=?", 1); + CHECK(vec.size() == 1); + CHECK(vec.front().bin.size() == size); + } +#endif +#ifdef ORMPP_ENABLE_PG + dbng postgres; + if (postgres.connect(ip, username, password, db)) { + postgres.execute("drop table if exists image"); + postgres.create_datatable(); + auto data = "this is a test binary stream\0, and ?..."; + auto size = 40; + image img{1}; + img.bin.assign(data, data + size); + CHECK(postgres.insert(img) == 1); + auto vec = postgres.query_s( + "select id,convert_from(bin,'utf8') from image where id=$1;", 1); + CHECK(vec.size() == 1); + // CHECK(vec.front().bin.size() == size); + } +#endif +#ifdef ORMPP_ENABLE_SQLITE3 + dbng sqlite; + if (sqlite.connect(db)) { + sqlite.execute("drop table if exists image"); + sqlite.create_datatable(); + auto data = "this is a test binary stream\0, and ?..."; + auto size = 40; + image img{1}; + img.bin.assign(data, data + size); + CHECK(sqlite.insert(img) == 1); + auto vec = sqlite.query_s("id=?", 1); CHECK(vec.size() == 1); - CHECK(vec[0].bin.size() == size); + CHECK(vec.front().bin.size() == size); } +#endif } struct image_ex { @@ -1078,33 +1109,86 @@ struct image_ex { }; REFLECTION(image_ex, id, bin, time); -TEST_CASE("mysql blob tuple") { +TEST_CASE("blob tuple") { +#ifdef ORMPP_ENABLE_MYSQL dbng mysql; if (mysql.connect(ip, username, password, db)) { - mysql.execute("DROP TABLE IF EXISTS image_ex"); + mysql.execute("drop table if exists image_ex"); mysql.create_datatable(); auto data = "this is a test binary stream\0, and ?..."; auto size = 40; - image_ex img_ex; - img_ex.id = 1; + image_ex img_ex{1}; img_ex.bin.assign(data, data + size); img_ex.time = "2023-03-29 13:55:00"; CHECK(mysql.insert(img_ex) == 1); - auto vec1 = mysql.query("id=1"); + auto vec1 = mysql.query_s("id=?", 1); CHECK(vec1.size() == 1); - CHECK(vec1[0].bin.size() == size); + CHECK(vec1.front().bin.size() == size); using image_t = std::tuple; - auto vec2 = - mysql.query("select id,bin,time from image_ex where id=1;"); + auto vec2 = mysql.query_s( + "select id,bin,time from image_ex where id=?;", 1); CHECK(vec2.size() == 1); - auto &img = std::get<0>(vec2[0]); - auto &time = std::get<1>(vec2[0]); + auto &img = std::get<0>(vec2.front()); + auto &time = std::get<1>(vec2.front()); CHECK(img.id == 1); + CHECK(time == img_ex.time); CHECK(img.bin.size() == size); + } +#endif +#ifdef ORMPP_ENABLE_PG + dbng postgres; + if (postgres.connect(ip, username, password, db)) { + postgres.execute("drop table if exists image_ex"); + postgres.create_datatable(); + auto data = "this is a test binary stream\0, and ?..."; + auto size = 40; + image_ex img_ex{1}; + img_ex.bin.assign(data, data + size); + img_ex.time = "2023-03-29 13:55:00"; + CHECK(postgres.insert(img_ex) == 1); + auto vec1 = postgres.query_s( + "select id,convert_from(bin,'utf8'),time from image_ex where id=$1;", + 1); + CHECK(vec1.size() == 1); + // CHECK(vec1.front().bin.size() == size); + using image_t = std::tuple; + auto vec2 = postgres.query_s( + "select id,convert_from(bin,'utf8'),time from image_ex where id=$1;", + 1); + CHECK(vec2.size() == 1); + auto &img = std::get<0>(vec2.front()); + auto &time = std::get<1>(vec2.front()); + CHECK(img.id == 1); CHECK(time == img_ex.time); + // CHECK(img.bin.size() == size); + } +#endif +#ifdef ORMPP_ENABLE_SQLITE3 + dbng sqlite; + if (sqlite.connect(db)) { + sqlite.execute("drop table if exists image_ex"); + sqlite.create_datatable(); + auto data = "this is a test binary stream\0, and ?..."; + auto size = 40; + image_ex img_ex{1}; + img_ex.bin.assign(data, data + size); + img_ex.time = "2023-03-29 13:55:00"; + CHECK(sqlite.insert(img_ex) == 1); + auto vec1 = sqlite.query_s("id=?", 1); + CHECK(vec1.size() == 1); + CHECK(vec1.front().bin.size() == size); + using image_t = std::tuple; + auto vec2 = sqlite.query_s( + "select id,bin,time from image_ex where id=?;", 1); + CHECK(vec2.size() == 1); + auto &img = std::get<0>(vec2.front()); + auto &time = std::get<1>(vec2.front()); + CHECK(img.id == 1); + CHECK(time == img_ex.time); + CHECK(img.bin.size() == size); } -} #endif +} TEST_CASE("create table with unique") { #ifdef ORMPP_ENABLE_MYSQL @@ -1679,12 +1763,12 @@ TEST_CASE("test bool") { mysql.execute("drop table if exists test_bool_t"); mysql.create_datatable(ormpp_auto_key{"id"}); mysql.insert(test_bool_t{true}); - auto vec = mysql.query(); + auto vec = mysql.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == true); mysql.delete_records(); mysql.insert(test_bool_t{false}); - vec = mysql.query(); + vec = mysql.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == false); } @@ -1695,12 +1779,12 @@ TEST_CASE("test bool") { postgres.execute("drop table if exists test_bool_t"); postgres.create_datatable(ormpp_auto_key{"id"}); postgres.insert(test_bool_t{true}); - auto vec = postgres.query(); + auto vec = postgres.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == true); postgres.delete_records(); postgres.insert(test_bool_t{false}); - vec = postgres.query(); + vec = postgres.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == false); } @@ -1711,12 +1795,12 @@ TEST_CASE("test bool") { sqlite.execute("drop table if exists test_bool_t"); sqlite.create_datatable(ormpp_auto_key{"id"}); sqlite.insert(test_bool_t{true}); - auto vec = sqlite.query(); + auto vec = sqlite.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == true); sqlite.delete_records(); sqlite.insert(test_bool_t{false}); - vec = sqlite.query(); + vec = sqlite.query_s(); CHECK(vec.size() == 1); CHECK(vec.front().ok == false); } @@ -1738,7 +1822,7 @@ TEST_CASE("alias") { mysql.create_datatable(ormpp_auto_key{"alias_id"}); mysql.delete_records(); mysql.insert({"purecpp"}); - auto vec = mysql.query(); + auto vec = mysql.query_s(); CHECK(vec.front().name == "purecpp"); } #endif @@ -1749,7 +1833,7 @@ TEST_CASE("alias") { sqlite.create_datatable(ormpp_auto_key{"alias_id"}); sqlite.delete_records(); sqlite.insert({"purecpp"}); - auto vec = sqlite.query(); + auto vec = sqlite.query_s(); CHECK(vec.front().name == "purecpp"); } #endif @@ -1762,11 +1846,11 @@ TEST_CASE("pg update") { postgres.execute("drop table if exists person"); postgres.create_datatable(ormpp_auto_key{"id"}); postgres.insert({"purecpp"}); - auto vec1 = postgres.query(); + auto vec1 = postgres.query_s(); CHECK(vec1.size() == 1); vec1.front().name = "other"; postgres.update(vec1.front()); - auto vec2 = postgres.query(); + auto vec2 = postgres.query_s(); CHECK(vec2.size() == 1); CHECK(vec2.front().name == "other"); CHECK(vec1.front().id == vec2.front().id); @@ -1928,4 +2012,73 @@ TEST_CASE("update section filed") { CHECK(vec2.front().name == "purecpp_bbbb"); } #endif +} + +struct unsigned_type_t { + uint8_t a; + uint16_t b; + uint32_t c; + uint64_t d; + int8_t e; + int16_t f; + int32_t g; + int64_t h; +}; +REFLECTION(unsigned_type_t, a, b, c, d, e, f, g, h) + +TEST_CASE("unsigned type") { +#ifdef ORMPP_ENABLE_MYSQL + dbng mysql; + if (mysql.connect(ip, username, password, db)) { + mysql.execute("drop table if exists unsigned_type_t"); + mysql.create_datatable(); + mysql.insert(unsigned_type_t{1, 2, 3, 4, 5, 6, 7, 8}); + auto vec = mysql.query_s(); + CHECK(vec.size() == 1); + CHECK(vec.front().a == 1); + CHECK(vec.front().b == 2); + CHECK(vec.front().c == 3); + CHECK(vec.front().d == 4); + CHECK(vec.front().e == 5); + CHECK(vec.front().f == 6); + CHECK(vec.front().g == 7); + CHECK(vec.front().h == 8); + } +#endif +#ifdef ORMPP_ENABLE_PG + dbng postgres; + if (postgres.connect(ip, username, password, db)) { + postgres.execute("drop table if exists unsigned_type_t"); + postgres.create_datatable(); + postgres.insert(unsigned_type_t{1, 2, 3, 4, 5, 6, 7, 8}); + auto vec = postgres.query_s(); + CHECK(vec.size() == 1); + CHECK(vec.front().a == 1); + CHECK(vec.front().b == 2); + CHECK(vec.front().c == 3); + CHECK(vec.front().d == 4); + CHECK(vec.front().e == 5); + CHECK(vec.front().f == 6); + CHECK(vec.front().g == 7); + CHECK(vec.front().h == 8); + } +#endif +#ifdef ORMPP_ENABLE_SQLITE3 + dbng sqlite; + if (sqlite.connect(db)) { + sqlite.execute("drop table if exists unsigned_type_t"); + sqlite.create_datatable(); + sqlite.insert(unsigned_type_t{1, 2, 3, 4, 5, 6, 7, 8}); + auto vec = sqlite.query_s(); + CHECK(vec.size() == 1); + CHECK(vec.front().a == 1); + CHECK(vec.front().b == 2); + CHECK(vec.front().c == 3); + CHECK(vec.front().d == 4); + CHECK(vec.front().e == 5); + CHECK(vec.front().f == 6); + CHECK(vec.front().g == 7); + CHECK(vec.front().h == 8); + } +#endif } \ No newline at end of file