Skip to content

Commit

Permalink
Refactor SQLitePreparedSelectStatement.*
Browse files Browse the repository at this point in the history
  • Loading branch information
kirkrodrigues committed Jul 2, 2024
1 parent 9daefd8 commit 9348e56
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 57 deletions.
43 changes: 23 additions & 20 deletions components/core/src/clp/SQLitePreparedSelectStatement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@
#include "ErrorCode.hpp"
#include "SQLitePreparedStatement.hpp"

using std::string;
using std::vector;

namespace clp {
auto SQLitePreparedSelectStatement::create_sqlite_prepared_select_statement(
std::vector<std::string> const& columns_to_select,
vector<string> const& columns_to_select,
std::string_view table,
std::vector<std::string> const& where_clause,
std::vector<std::string> const& ordering_clause,
vector<string> const& where_clause_predicates,
vector<string> const& sort_keys,
sqlite3* db_handle
) -> SQLitePreparedSelectStatement {
if (columns_to_select.empty()) {
throw OperationFailed(
ErrorCode_Failure,
__FILENAME__,
__LINE__,
"clp::SQLitePreparedSelectStatement Failed: no column to select."
"clp::SQLitePreparedSelectStatement: No columns to select."
);
}

std::unordered_map<std::string, size_t> idx_map;
std::unordered_map<string, size_t> selected_column_to_idx;
fmt::memory_buffer statement_buffer;
auto statement_buffer_ix{std::back_inserter(statement_buffer)};

Expand All @@ -43,45 +46,45 @@ auto SQLitePreparedSelectStatement::create_sqlite_prepared_select_statement(
);
size_t idx{0};
for (auto const& column : columns_to_select) {
idx_map.emplace(column, idx++);
selected_column_to_idx.emplace(column, idx++);
}

if (false == where_clause.empty()) {
if (false == where_clause_predicates.empty()) {
bool is_first{true};
for (auto const& filter : where_clause) {
fmt::format_to(statement_buffer_ix, " {} {}", is_first ? "WHERE" : "AND", filter);
for (auto const& predicate : where_clause_predicates) {
fmt::format_to(statement_buffer_ix, " {} {}", is_first ? "WHERE" : "AND", predicate);
is_first = false;
}
}

if (false == ordering_clause.empty()) {
if (false == sort_keys.empty()) {
fmt::format_to(statement_buffer_ix, " ORDER BY");
bool is_first{true};
for (auto const& ordering : ordering_clause) {
for (auto const& sort_key : sort_keys) {
if (is_first) {
fmt::format_to(statement_buffer_ix, " {}", ordering);
fmt::format_to(statement_buffer_ix, " {}", sort_key);
is_first = false;
continue;
}
fmt::format_to(statement_buffer_ix, ", {}", ordering);
fmt::format_to(statement_buffer_ix, ", {}", sort_key);
}
}

return SQLitePreparedSelectStatement{
{statement_buffer.data(), statement_buffer.size()},
db_handle,
idx_map
selected_column_to_idx
};
}

auto SQLitePreparedSelectStatement::get_selected_column_idx(std::string const& selected_column
auto SQLitePreparedSelectStatement::get_selected_column_idx(string const& column_name
) const -> size_t {
auto const idx_it{m_idx_map.find(selected_column)};
if (m_idx_map.cend() == idx_it) {
std::string const msg{
"clp::SQLitePreparedSelectStatement Failed with unknown selected column: "
auto const idx_it{m_selected_column_to_idx.find(column_name)};
if (m_selected_column_to_idx.cend() == idx_it) {
string const msg{
"clp::SQLitePreparedSelectStatement: " + column_name + " is not a selected column."
};
throw OperationFailed(ErrorCode_Failure, __FILENAME__, __LINE__, msg + selected_column);
throw OperationFailed(ErrorCode_BadParam, __FILENAME__, __LINE__, msg + column_name);
}
return idx_it->second;
}
Expand Down
75 changes: 38 additions & 37 deletions components/core/src/clp/SQLitePreparedSelectStatement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#define CLP_SQLITEPREPAREDSELECTSTATEMENT_HPP

#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
Expand All @@ -14,8 +13,8 @@
#include "TraceableException.hpp"

/**
* This class provides abstractions to a sqlite select statement. It maintains a map to lookup the
* index of a selected column in the statement from a given name.
* A SQLite `SELECT` prepared statement that maintains a mapping between each selected column and
* its index, so that each column in the result set can be retrieved using its name.
*/
namespace clp {
class SQLitePreparedSelectStatement : public SQLitePreparedStatement {
Expand All @@ -40,63 +39,65 @@ class SQLitePreparedSelectStatement : public SQLitePreparedStatement {
std::string m_msg;
};

// Factory functions.
// Factory functions
/**
* Constructs and returns a SQLite select statement with given parameters.
* @param columns_to_select The name of columns to select.
* Constructs a SQLite `SELECT` statement with the given parameters.
* @param columns_to_select The names of the columns to select.
* @param table The name of the table to select from.
* @param where_clause SQLite `WHERE` clause to filter rows in the result set. Each element is
* a formatted comparison. All the comparisons are chained with `AND` logic operator.
* @param ordering_clause SQLite `ORDER BY` clause to sort the result set.
* @param where_clause_predicates Optional predicates for the `WHERE` clause.
* @param sort_keys Optional sort keys for the `ORDER BY` clause. These may be in the form
* "<column-name>" OR "<column-name> <ASC|DESC>".
* @param db_handle
* @return a new constructed select statement.
* @return The SQLite statement.
* @throw clp::SQLitePreparedStatement::OperationFailed on failure.
*/
[[nodiscard]] static auto create_sqlite_prepared_select_statement(
std::vector<std::string> const& columns_to_select,
std::string_view table,
std::vector<std::string> const& where_clause,
std::vector<std::string> const& ordering_clause,
std::vector<std::string> const& where_clause_predicates,
std::vector<std::string> const& sort_keys,
sqlite3* db_handle
) -> SQLitePreparedSelectStatement;

~SQLitePreparedSelectStatement() override = default;

// Deletes copy constructor and assignment.
// Constructors and assignment operators
// Disable copy constructor and assignment operator
SQLitePreparedSelectStatement(SQLitePreparedSelectStatement const&) = delete;
auto operator=(SQLitePreparedSelectStatement const&) -> SQLitePreparedSelectStatement& = delete;

// Defines default move constructor and assignment.
// Use default move constructor and assignment operator
SQLitePreparedSelectStatement(SQLitePreparedSelectStatement&& rhs) noexcept = default;
auto operator=(SQLitePreparedSelectStatement&& rhs
) noexcept -> SQLitePreparedSelectStatement& = default;

// Destructor
~SQLitePreparedSelectStatement() override = default;

// Methods
/**
* @param selected_column
* @return The int value from the selected column.
* @throw OperationFailed if the name is not a valid selected column.
* @param column_name
* @return The selected column's value as an int.
* @throw OperationFailed if the name is not a selected column.
*/
[[nodiscard]] auto column_int(std::string const& selected_column) const -> int {
[[nodiscard]] auto column_int(std::string const& column_name) const -> int {
return SQLitePreparedStatement::column_int(
static_cast<int>(get_selected_column_idx(selected_column))
static_cast<int>(get_selected_column_idx(column_name))
);
}

/**
* @param selected_column
* @return The int64 value from the selected column.
* @throw OperationFailed if the name is not a valid selected column.
* @param column_name
* @return The selected column's value as an int64.
* @throw OperationFailed if the name is not a selected column.
*/
[[nodiscard]] auto column_int64(std::string const& selected_column) const -> int64_t {
[[nodiscard]] auto column_int64(std::string const& column_name) const -> int64_t {
return SQLitePreparedStatement::column_int64(
static_cast<int>(get_selected_column_idx(selected_column))
static_cast<int>(get_selected_column_idx(column_name))
);
}

/**
* @param selected_column
* @param value Returns the string value from the selected column.
* @param value Returns the selected column's value as a string.
* @throw OperationFailed if the name is not a valid selected column.
*/
auto column_string(std::string const& selected_column, std::string& value) const -> void {
Expand All @@ -108,26 +109,26 @@ class SQLitePreparedSelectStatement : public SQLitePreparedStatement {

private:
/**
* Constructor. It should not be accessible outside of the class.
* `create_sqlite_prepared_select_statement` should be used to create an instance of this
* class.
* @param statement
* @param db_handle
* @param selected_column_to_idx
*/
explicit SQLitePreparedSelectStatement(
std::string_view statement,
sqlite3* db_handle,
std::unordered_map<std::string, size_t> idx_map
std::unordered_map<std::string, size_t> selected_column_to_idx
)
: SQLitePreparedStatement{statement.data(), statement.size(), db_handle},
m_idx_map{std::move(idx_map)} {}
m_selected_column_to_idx{std::move(selected_column_to_idx)} {}

/**
* @param selected_column
* @return The idx of the selected column in the statement.
* @throw OperationFailed if the name doesn't appear in the select statement.
* @param column_name
* @return Index of the selected column in the statement.
* @throw OperationFailed if the name is not a selected column.
*/
[[nodiscard]] auto get_selected_column_idx(std::string const& selected_column) const -> size_t;
[[nodiscard]] auto get_selected_column_idx(std::string const& column_name) const -> size_t;

std::unordered_map<std::string, size_t> m_idx_map;
std::unordered_map<std::string, size_t> m_selected_column_to_idx;
};
} // namespace clp

Expand Down

0 comments on commit 9348e56

Please sign in to comment.