diff --git a/support/include/utils/db/sqlite/db_common.hpp b/support/include/utils/db/sqlite/db_common.hpp index e00d016f..de69300e 100644 --- a/support/include/utils/db/sqlite/db_common.hpp +++ b/support/include/utils/db/sqlite/db_common.hpp @@ -68,122 +68,72 @@ struct db_context_t { std::string table_name; }; -class db_column final { -public: - db_column() noexcept = default; - db_column(const db_column &) = default; - db_column(db_column &&column) noexcept = default; - ~db_column() = default; - - auto operator=(const db_column &) -> db_column & = default; - auto operator=(db_column &&) -> db_column & = default; - - db_column(std::int32_t index, std::string name, db_types_t value) noexcept - : index_(index), name_(std::move(name)), value_(std::move(value)) {} - -private: - std::int32_t index_{}; - std::string name_; - db_types_t value_; - -public: - [[nodiscard]] auto get_index() const -> std::int32_t { return index_; } - - [[nodiscard]] auto get_name() const -> std::string { return name_; } - - template - [[nodiscard]] auto get_value() const -> data_type { - REPERTORY_USES_FUNCTION_NAME(); - - return std::visit( - overloaded{ - [](const data_type &value) -> data_type { return value; }, - [](auto &&) -> data_type { - throw utils::error::create_exception( - function_name, { - "data type not supported", - }); - }, - }, - value_); - } - -#if defined(PROJECT_ENABLE_JSON) - [[nodiscard]] auto get_value_as_json() const -> nlohmann::json; -#endif // defined(PROJECT_ENABLE_JSON) -}; - -template class db_row final { -public: - db_row(std::shared_ptr ctx) { - REPERTORY_USES_FUNCTION_NAME(); - - auto column_count = sqlite3_column_count(ctx->stmt.get()); - for (std::int32_t col = 0; col < column_count; col++) { - std::string name{sqlite3_column_name(ctx->stmt.get(), col)}; - auto column_type = sqlite3_column_type(ctx->stmt.get(), col); - - db_types_t value; - switch (column_type) { - case SQLITE_INTEGER: { - value = sqlite3_column_int64(ctx->stmt.get(), col); - } break; - - case SQLITE_TEXT: { - const auto *text = reinterpret_cast( - sqlite3_column_text(ctx->stmt.get(), col)); - value = std::string(text == nullptr ? "" : text); - } break; - - default: - throw utils::error::create_exception(function_name, - { - "column type not implemented", - std::to_string(column_type), - }); - } - - columns_[name] = db_column{col, name, value}; - } - } - -private: - std::map columns_; - -public: - [[nodiscard]] auto get_columns() const -> std::vector { - std::vector ret; - for (const auto &item : columns_) { - ret.push_back(item.second); - } - return ret; - } - - [[nodiscard]] auto get_column(std::int32_t index) const -> db_column { - auto iter = std::find_if(columns_.begin(), columns_.end(), - [&index](auto &&col) -> bool { - return col.second.get_index() == index; - }); - if (iter == columns_.end()) { - throw std::out_of_range(""); - } - - return iter->second; - } - - [[nodiscard]] auto get_column(std::string name) const -> db_column { - return columns_.at(name); - } -}; - struct db_result final { struct context final { db3_stmt_t stmt; }; - using row = db_row; + class db_column final { + public: + db_column(std::int32_t index, std::string name, db_types_t value) noexcept; - db_result(sqlite3_stmt *stmt, std::int32_t res); + db_column() noexcept = default; + db_column(const db_column &) = default; + db_column(db_column &&column) noexcept = default; + + ~db_column() = default; + + auto operator=(const db_column &) -> db_column & = default; + auto operator=(db_column &&) -> db_column & = default; + + private: + std::int32_t index_{}; + std::string name_; + db_types_t value_; + + public: + [[nodiscard]] auto get_index() const -> std::int32_t { return index_; } + + [[nodiscard]] auto get_name() const -> std::string { return name_; } + + template + [[nodiscard]] auto get_value() const -> data_type { + REPERTORY_USES_FUNCTION_NAME(); + + return std::visit( + overloaded{ + [](const data_type &value) -> data_type { return value; }, + [](auto &&) -> data_type { + throw utils::error::create_exception( + function_name, { + "data type not supported", + }); + }, + }, + value_); + } + +#if defined(PROJECT_ENABLE_JSON) + [[nodiscard]] auto get_value_as_json() const -> nlohmann::json; +#endif // defined(PROJECT_ENABLE_JSON) + }; + + class db_row final { + public: + db_row(std::shared_ptr ctx); + + private: + std::map columns_; + + public: + [[nodiscard]] auto get_columns() const -> std::vector; + + [[nodiscard]] auto get_column(std::int32_t index) const -> db_column; + + [[nodiscard]] auto get_column(std::string name) const -> db_column; + }; + + db_result(db3_stmt_t stmt, std::int32_t res); db_result() = default; db_result(const db_result &) = default; @@ -192,6 +142,8 @@ struct db_result final { auto operator=(const db_result &) -> db_result & = default; auto operator=(db_result &&) -> db_result & = default; + using row = db_row; + private: std::shared_ptr ctx_; mutable std::int32_t res_{}; diff --git a/support/include/utils/db/sqlite/db_insert.hpp b/support/include/utils/db/sqlite/db_insert.hpp index 6a03829f..fdf5d25e 100644 --- a/support/include/utils/db/sqlite/db_insert.hpp +++ b/support/include/utils/db/sqlite/db_insert.hpp @@ -36,8 +36,6 @@ public: std::map values; }; - using row = db_row; - public: db_insert(sqlite3 &db3, std::string table_name) : ctx_(std::make_shared(&db3, table_name)) {} @@ -48,15 +46,13 @@ private: std::shared_ptr ctx_; public: - [[nodiscard]] auto or_replace() -> db_insert & { + [[nodiscard]] auto or_replace() -> db_insert { ctx_->or_replace = true; return *this; } [[nodiscard]] auto column_value(std::string column_name, db_types_t value) - - - -> db_insert &; + -> db_insert; [[nodiscard]] auto dump() const -> std::string; diff --git a/support/include/utils/db/sqlite/db_select.hpp b/support/include/utils/db/sqlite/db_select.hpp index 127eee09..a80ae2aa 100644 --- a/support/include/utils/db/sqlite/db_select.hpp +++ b/support/include/utils/db/sqlite/db_select.hpp @@ -45,8 +45,6 @@ public: [[nodiscard]] auto offset(std::int32_t value) -> db_select_op_t; [[nodiscard]] auto order_by(std::string column_name, bool ascending) - - -> db_select_op_t; }; @@ -77,32 +75,26 @@ private: std::shared_ptr ctx_; public: - [[nodiscard]] auto column(std::string column_name) -> db_select &; + [[nodiscard]] auto column(std::string column_name) -> db_select; [[nodiscard]] auto count(std::string column_name, std::string as_column_name) - - - -> db_select &; + -> db_select; [[nodiscard]] auto dump() const -> std::string; [[nodiscard]] auto go() const -> db_result; - [[nodiscard]] auto group_by(std::string column_name) -> db_select &; - + [[nodiscard]] auto group_by(std::string column_name) -> db_select; [[nodiscard]] auto group(context::w_t::group_func_t func) - -> context::w_t::wn_t; - [[nodiscard]] auto limit(std::int32_t value) -> db_select &; + [[nodiscard]] auto limit(std::int32_t value) -> db_select; - [[nodiscard]] auto offset(std::int32_t value) -> db_select &; + [[nodiscard]] auto offset(std::int32_t value) -> db_select; [[nodiscard]] auto order_by(std::string column_name, bool ascending) - - - -> db_select &; + -> db_select; [[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t; }; diff --git a/support/include/utils/db/sqlite/db_update.hpp b/support/include/utils/db/sqlite/db_update.hpp index bf4c42bf..335d0ec1 100644 --- a/support/include/utils/db/sqlite/db_update.hpp +++ b/support/include/utils/db/sqlite/db_update.hpp @@ -69,22 +69,19 @@ private: public: [[nodiscard]] auto column_value(std::string column_name, db_types_t value) - - -> db_update &; + -> db_update; [[nodiscard]] auto dump() const -> std::string; [[nodiscard]] auto go() const -> db_result; [[nodiscard]] auto group(context::w_t::group_func_t func) - -> context::w_t::wn_t; - [[nodiscard]] auto limit(std::int32_t value) -> db_update &; + [[nodiscard]] auto limit(std::int32_t value) -> db_update; [[nodiscard]] auto order_by(std::string column_name, bool ascending) - - -> db_update &; + -> db_update; [[nodiscard]] auto where(std::string column_name) const -> context::w_t::cn_t; }; diff --git a/support/src/utils/db/sqlite/db_common.cpp b/support/src/utils/db/sqlite/db_common.cpp index 9b65b42e..15e6301a 100644 --- a/support/src/utils/db/sqlite/db_common.cpp +++ b/support/src/utils/db/sqlite/db_common.cpp @@ -63,8 +63,12 @@ void sqlite3_deleter::operator()(sqlite3 *db3) const { } } +db_result::db_column::db_column(std::int32_t index, std::string name, + db_types_t value) noexcept + : index_(index), name_(std::move(name)), value_(std::move(value)) {} + #if defined(PROJECT_ENABLE_JSON) -auto db_column::get_value_as_json() const -> nlohmann::json { +auto db_result::db_column::get_value_as_json() const -> nlohmann::json { return std::visit( overloaded{ [this](std::int64_t value) -> auto { @@ -76,13 +80,64 @@ auto db_column::get_value_as_json() const -> nlohmann::json { } #endif // defined(PROJECT_ENABLE_JSON) -db_result::db_result(sqlite3_stmt *stmt, std::int32_t res) - : ctx_(std::make_shared()), res_(res) { - ctx_->stmt = db3_stmt_t{ - stmt, - sqlite3_statement_deleter(), - }; +db_result::db_row::db_row(std::shared_ptr ctx) { + REPERTORY_USES_FUNCTION_NAME(); + auto column_count = sqlite3_column_count(ctx->stmt.get()); + for (std::int32_t col = 0; col < column_count; col++) { + std::string name{sqlite3_column_name(ctx->stmt.get(), col)}; + auto column_type = sqlite3_column_type(ctx->stmt.get(), col); + + db_types_t value; + switch (column_type) { + case SQLITE_INTEGER: { + value = sqlite3_column_int64(ctx->stmt.get(), col); + } break; + + case SQLITE_TEXT: { + const auto *text = reinterpret_cast( + sqlite3_column_text(ctx->stmt.get(), col)); + value = std::string(text == nullptr ? "" : text); + } break; + + default: + throw utils::error::create_exception(function_name, + { + "column type not implemented", + std::to_string(column_type), + }); + } + + columns_[name] = db_column{col, name, value}; + } +} + +auto db_result::db_row::get_columns() const -> std::vector { + std::vector ret; + for (const auto &item : columns_) { + ret.push_back(item.second); + } + return ret; +} + +auto db_result::db_row::get_column(std::int32_t index) const -> db_column { + auto iter = std::find_if( + columns_.begin(), columns_.end(), + [&index](auto &&col) -> bool { return col.second.get_index() == index; }); + if (iter == columns_.end()) { + throw std::out_of_range(""); + } + + return iter->second; +} + +auto db_result::db_row::get_column(std::string name) const -> db_column { + return columns_.at(name); +} + +db_result::db_result(db3_stmt_t stmt, std::int32_t res) + : ctx_(std::make_shared()), res_(res) { + ctx_->stmt = std::move(stmt); if (res == SQLITE_OK) { set_res(sqlite3_step(ctx_->stmt.get())); } @@ -100,7 +155,7 @@ auto db_result::get_row(std::optional &opt_row) const -> bool { return false; } - opt_row = db_row{ctx_}; + opt_row = db_row{ctx_}; set_res(sqlite3_step(ctx_->stmt.get())); return true; } diff --git a/support/src/utils/db/sqlite/db_delete.cpp b/support/src/utils/db/sqlite/db_delete.cpp index cfb62208..de928e16 100644 --- a/support/src/utils/db/sqlite/db_delete.cpp +++ b/support/src/utils/db/sqlite/db_delete.cpp @@ -52,34 +52,39 @@ auto db_delete::go() const -> db_result { auto res = sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr); + auto stmt = db3_stmt_t{ + stmt_ptr, + sqlite3_statement_deleter(), + }; + if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } if (not ctx_->where_data) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } for (std::int32_t idx = 0; idx < static_cast(ctx_->where_data->values.size()); idx++) { - res = std::visit( - overloaded{ - [&stmt_ptr, &idx](std::int64_t data) -> std::int32_t { - return sqlite3_bind_int64(stmt_ptr, idx + 1, data); - }, - [&stmt_ptr, &idx](const std::string &data) -> std::int32_t { - return sqlite3_bind_text(stmt_ptr, idx + 1, data.c_str(), -1, - nullptr); - }, - }, - ctx_->where_data->values.at(static_cast(idx))); + res = + std::visit(overloaded{ + [&stmt, &idx](std::int64_t data) -> std::int32_t { + return sqlite3_bind_int64(stmt.get(), idx + 1, data); + }, + [&stmt, &idx](const std::string &data) -> std::int32_t { + return sqlite3_bind_text(stmt.get(), idx + 1, + data.c_str(), -1, nullptr); + }, + }, + ctx_->where_data->values.at(static_cast(idx))); if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } - return {stmt_ptr, res}; + return {std::move(stmt), res}; } auto db_delete::group(context::w_t::group_func_t func) -> context::w_t::wn_t { diff --git a/support/src/utils/db/sqlite/db_insert.cpp b/support/src/utils/db/sqlite/db_insert.cpp index 4e6b1c54..a82de4f2 100644 --- a/support/src/utils/db/sqlite/db_insert.cpp +++ b/support/src/utils/db/sqlite/db_insert.cpp @@ -24,8 +24,8 @@ #include "utils/db/sqlite/db_insert.hpp" namespace repertory::utils::db::sqlite { -auto db_insert::column_value(std::string column_name, - db_types_t value) -> db_insert & { +auto db_insert::column_value(std::string column_name, db_types_t value) + -> db_insert { ctx_->values[column_name] = value; return *this; } @@ -65,29 +65,34 @@ auto db_insert::go() const -> db_result { auto res = sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr); + auto stmt = db3_stmt_t{ + stmt_ptr, + sqlite3_statement_deleter(), + }; + if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } for (std::int32_t idx = 0; idx < static_cast(ctx_->values.size()); idx++) { - res = std::visit( - overloaded{ - [&idx, &stmt_ptr](std::int64_t data) -> std::int32_t { - return sqlite3_bind_int64(stmt_ptr, idx + 1, data); - }, - [&idx, &stmt_ptr](const std::string &data) -> std::int32_t { - return sqlite3_bind_text(stmt_ptr, idx + 1, data.c_str(), -1, - nullptr); - }, - }, - std::next(ctx_->values.begin(), idx)->second); + res = + std::visit(overloaded{ + [&idx, &stmt](std::int64_t data) -> std::int32_t { + return sqlite3_bind_int64(stmt.get(), idx + 1, data); + }, + [&idx, &stmt](const std::string &data) -> std::int32_t { + return sqlite3_bind_text(stmt.get(), idx + 1, + data.c_str(), -1, nullptr); + }, + }, + std::next(ctx_->values.begin(), idx)->second); if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } // namespace repertory::utils::db::sqlite diff --git a/support/src/utils/db/sqlite/db_select.cpp b/support/src/utils/db/sqlite/db_select.cpp index 5d61d3c2..54c9f3a2 100644 --- a/support/src/utils/db/sqlite/db_select.cpp +++ b/support/src/utils/db/sqlite/db_select.cpp @@ -57,13 +57,13 @@ auto db_select::context::db_select_op_t::order_by(std::string column_name, return *this; } -auto db_select::column(std::string column_name) -> db_select & { +auto db_select::column(std::string column_name) -> db_select { ctx_->columns.push_back(column_name); return *this; } -auto db_select::count(std::string column_name, - std::string as_column_name) -> db_select & { +auto db_select::count(std::string column_name, std::string as_column_name) + -> db_select { ctx_->count_columns[column_name] = as_column_name; return *this; } @@ -138,34 +138,39 @@ auto db_select::go() const -> db_result { auto res = sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr); + auto stmt = db3_stmt_t{ + stmt_ptr, + sqlite3_statement_deleter(), + }; + if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } if (not ctx_->where_data) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } for (std::int32_t idx = 0; idx < static_cast(ctx_->where_data->values.size()); idx++) { - res = std::visit( - overloaded{ - [&idx, &stmt_ptr](std::int64_t data) -> std::int32_t { - return sqlite3_bind_int64(stmt_ptr, idx + 1, data); - }, - [&idx, &stmt_ptr](const std::string &data) -> std::int32_t { - return sqlite3_bind_text(stmt_ptr, idx + 1, data.c_str(), -1, - nullptr); - }, - }, - ctx_->where_data->values.at(static_cast(idx))); + res = + std::visit(overloaded{ + [&idx, &stmt](std::int64_t data) -> std::int32_t { + return sqlite3_bind_int64(stmt.get(), idx + 1, data); + }, + [&idx, &stmt](const std::string &data) -> std::int32_t { + return sqlite3_bind_text(stmt.get(), idx + 1, + data.c_str(), -1, nullptr); + }, + }, + ctx_->where_data->values.at(static_cast(idx))); if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } - return {stmt_ptr, res}; + return {std::move(stmt), res}; } auto db_select::group(context::w_t::group_func_t func) -> context::w_t::wn_t { @@ -180,23 +185,22 @@ auto db_select::group(context::w_t::group_func_t func) -> context::w_t::wn_t { return ctx_->where_data->base.group(std::move(func)); } -auto db_select::group_by(std::string column_name) -> db_select & { +auto db_select::group_by(std::string column_name) -> db_select { ctx_->group_by.emplace_back(std::move(column_name)); return *this; } -auto db_select::limit(std::int32_t value) -> db_select & { +auto db_select::limit(std::int32_t value) -> db_select { ctx_->limit = value; return *this; } -auto db_select::offset(std::int32_t value) -> db_select & { +auto db_select::offset(std::int32_t value) -> db_select { ctx_->offset = value; return *this; } -auto db_select::order_by(std::string column_name, - bool ascending) -> db_select & { +auto db_select::order_by(std::string column_name, bool ascending) -> db_select { ctx_->order_by = {column_name, ascending}; return *this; } diff --git a/support/src/utils/db/sqlite/db_update.cpp b/support/src/utils/db/sqlite/db_update.cpp index a467418f..4000e9be 100644 --- a/support/src/utils/db/sqlite/db_update.cpp +++ b/support/src/utils/db/sqlite/db_update.cpp @@ -45,8 +45,8 @@ auto db_update::context::db_update_op_t::order_by(std::string column_name, return *this; } -auto db_update::column_value(std::string column_name, - db_types_t value) -> db_update & { +auto db_update::column_value(std::string column_name, db_types_t value) + -> db_update { ctx_->column_values[column_name] = value; return *this; } @@ -91,30 +91,35 @@ auto db_update::go() const -> db_result { auto res = sqlite3_prepare_v2(ctx_->db3, query_str.c_str(), -1, &stmt_ptr, nullptr); + auto stmt = db3_stmt_t{ + stmt_ptr, + sqlite3_statement_deleter(), + }; + if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } for (std::int32_t idx = 0; idx < static_cast(ctx_->column_values.size()); idx++) { - res = std::visit( - overloaded{ - [&stmt_ptr, &idx](std::int64_t data) -> std::int32_t { - return sqlite3_bind_int64(stmt_ptr, idx + 1, data); - }, - [&stmt_ptr, &idx](const std::string &data) -> std::int32_t { - return sqlite3_bind_text(stmt_ptr, idx + 1, data.c_str(), -1, - nullptr); - }, - }, - std::next(ctx_->column_values.begin(), idx)->second); + res = + std::visit(overloaded{ + [&idx, &stmt](std::int64_t data) -> std::int32_t { + return sqlite3_bind_int64(stmt.get(), idx + 1, data); + }, + [&idx, &stmt](const std::string &data) -> std::int32_t { + return sqlite3_bind_text(stmt.get(), idx + 1, + data.c_str(), -1, nullptr); + }, + }, + std::next(ctx_->column_values.begin(), idx)->second); if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } if (not ctx_->where_data) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } for (std::int32_t idx = 0; @@ -122,16 +127,16 @@ auto db_update::go() const -> db_result { idx++) { res = std::visit( overloaded{ - [this, &idx, &stmt_ptr](std::int64_t data) -> std::int32_t { + [this, &idx, &stmt](std::int64_t data) -> std::int32_t { return sqlite3_bind_int64( - stmt_ptr, + stmt.get(), idx + static_cast(ctx_->column_values.size()) + 1, data); }, - [this, &idx, &stmt_ptr](const std::string &data) -> std::int32_t { + [this, &idx, &stmt](const std::string &data) -> std::int32_t { return sqlite3_bind_text( - stmt_ptr, + stmt.get(), idx + static_cast(ctx_->column_values.size()) + 1, data.c_str(), -1, nullptr); @@ -139,11 +144,11 @@ auto db_update::go() const -> db_result { }, ctx_->where_data->values.at(static_cast(idx))); if (res != SQLITE_OK) { - return {stmt_ptr, res}; + return {std::move(stmt), res}; } } - return {stmt_ptr, res}; + return {std::move(stmt), res}; } auto db_update::group(context::w_t::group_func_t func) -> context::w_t::wn_t { @@ -158,13 +163,12 @@ auto db_update::group(context::w_t::group_func_t func) -> context::w_t::wn_t { return ctx_->where_data->base.group(std::move(func)); } -auto db_update::limit(std::int32_t value) -> db_update & { +auto db_update::limit(std::int32_t value) -> db_update { ctx_->limit = value; return *this; } -auto db_update::order_by(std::string column_name, - bool ascending) -> db_update & { +auto db_update::order_by(std::string column_name, bool ascending) -> db_update { ctx_->order_by = {column_name, ascending}; return *this; }