The following is a prospective interface of a (future) C++ database abstraction layer. This interface is inspired by proposal N3886 of Johann Anhofer.
This interface is made up of 2 (primary) classes. The first, namely connection, allows a user to connect to a particular database. A user can then begin, rollback and commit a transaction. A convenience function, namely exec(), is included in order to perform (simple) operations that do not return a result set, such as creating a table. The second class, named statement, allows a user to create and process more involved statements, such as those that bind parameters and extract individual the values of a result set. This class uses the (C++17) any data type to manipulate parameters and values of arbitrary data types.
We welcome all comments, feedback, revisions, enhancements, additions, deletions, etc. to this interface. Ultimately, we are seeking a candidate to present any future proposal stemming from this interface.
/*
* References:
* Johann Anhofer N3886, dlib.net, SQLAPI++, SOCI, POCO, MFC (CDatabase, CRecordset), Java JDBC, .NET Core 2.2
*/
#ifndef DATABASE_H
#define DATABASE_H
#include <any>
#include <stdexcept>
#include <string>
namespace std {
namespace database {
class connection_exception : public std::runtime_error { // inspired by N3886 of Johann Anhofer
public:
explicit connection_exception(const std::string& what_arg) : std::runtime_error(what_arg) { }
explicit connection_exception(const char* what_arg) : std::runtime_error(what_arg) { }
};
class statement_exception : public std::runtime_error { // inspired by N3886 of Johann Anhofer
public:
explicit statement_exception(const std::string& what_arg) : std::runtime_error(what_arg) { }
explicit statement_exception(const char* what_arg) : std::runtime_error(what_arg) { }
};
class connection {
public:
connection() noexcept;
explicit connection(const std::string& conn); // conn is database, username and password
~connection() noexcept;
void open(const std::string& conn);
void close();
constexpr bool is_open() const noexcept;
constexpr std::string conn() const noexcept;
void begin_transaction();
void commit();
void rollback();
void exec(const std::string& sql_statement); // convenience func., does not produce a result set
};
class statement {
public:
explicit statement(connection& db);
statement(connection& db, const std::string& sql_statement);
~statement() noexcept;
void sql_statement(const std::string& sql_statement);
constexpr std::string sql_statement() const noexcept;
void bind(const std::string &name, const std::any& value);
void bind(int index, const std::any& value);
statement& operator<<(const std::any& value); // bind parameters (in order)
constexpr int param_count() const noexcept;
constexpr int param_index(const std::string &name) const; // name -> index
constexpr std::string param_name(int index) const; // index -> name
constexpr std::any param_value(const std::string &name) const;
constexpr std::any param_value(int index) const;
constexpr bool is_param_value_null(const std::string &name) const;
constexpr bool is_param_value_null(int pos) const;
void prepare();
constexpr bool is_prepared() const noexcept;
void exec();
constexpr bool is_eof() const noexcept;
void move_first();
void move_next();
constexpr int field_count() const noexcept;
constexpr int field_index(const std::string &name) const; // name -> index
constexpr std::string field_name(int index) const; // index -> name
constexpr std::any field_value(const std::string &name) const;
constexpr std::any field_value(int index) const;
constexpr bool is_field_value_null(const std::string &name) const;
constexpr bool is_field_value_null(int index) const;
};
} // namespace database
} // namespace std
#endif