This commit is contained in:
Scott E. Graves 2024-10-23 11:13:56 -05:00
parent 18c53fad9a
commit 2a6ecf61b2
9 changed files with 233 additions and 223 deletions

View File

@ -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 <typename data_type>
[[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 <typename ctx_t> class db_row final {
public:
db_row(std::shared_ptr<ctx_t> 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<const char *>(
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<std::string, db_column> columns_;
public:
[[nodiscard]] auto get_columns() const -> std::vector<db_column> {
std::vector<db_column> 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<context>;
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 <typename data_type>
[[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<context> ctx);
private:
std::map<std::string, db_column> columns_;
public:
[[nodiscard]] auto get_columns() const -> std::vector<db_column>;
[[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<context> ctx_;
mutable std::int32_t res_{};

View File

@ -36,8 +36,6 @@ public:
std::map<std::string, db_types_t> values;
};
using row = db_row<context>;
public:
db_insert(sqlite3 &db3, std::string table_name)
: ctx_(std::make_shared<context>(&db3, table_name)) {}
@ -48,15 +46,13 @@ private:
std::shared_ptr<context> 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;

View File

@ -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<context> 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;
};

View File

@ -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;
};

View File

@ -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<context>()), res_(res) {
ctx_->stmt = db3_stmt_t{
stmt,
sqlite3_statement_deleter(),
};
db_result::db_row::db_row(std::shared_ptr<context> 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<const char *>(
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<db_column> {
std::vector<db_column> 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<context>()), 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<row> &opt_row) const -> bool {
return false;
}
opt_row = db_row<context>{ctx_};
opt_row = db_row{ctx_};
set_res(sqlite3_step(ctx_->stmt.get()));
return true;
}

View File

@ -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<std::int32_t>(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<std::size_t>(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<std::size_t>(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 {

View File

@ -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<std::int32_t>(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

View File

@ -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<std::int32_t>(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<std::size_t>(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<std::size_t>(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;
}

View File

@ -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<std::int32_t>(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<std::int32_t>(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<std::int32_t>(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<std::size_t>(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;
}