An ORM built on C++20 that is inspired by Django's ORM, built to support multiple database engines.
Strata provides an easy-to-use, intuitive API to interact with databases. As of now, it only supports PostgreSQL but plans to add support for more database engines are in mind.
Documentation can be found at the WIKI.
Warning
This library is still under ACTIVE development and should not be considered stable!
- CRUD operations for rows of data.
- Class-based models representing SQL tables.
- Migration tracking between changes in models and their columns.
- Support for raw SQL execution.
- Clean abstraction over raw, basic SQL datatypes using classes.
- Support for performing fetches, filters(limited) and joins.
- Environmental variables set in-program for db connections.
- Support for nullable values.
- Support for user-defined datatypes.
- Support for more database engines eg MySQL, SQLite, MSSQL etc.
Since this library supports only PostgreSQL now, dependencies are:
- A C++ compiler supporting
-std=C++20
. - CMake (at least version 3.16).
- PostgreSQL library.
- libpqxx -> Official C++ client library for postgres.
Warning
This library depends on a feature from libpqxx that is only available on the latest development version(not released yet).
Options are to build from source or wait for the upcoming 8.0
release.
$ git clone [email protected]:bitflaw/strataorm.git
$ cd strataorm
Since we are using CMake, I recommend building in a dedicated build directory:
$ mkdir build
$ cmake -B ${BUILD_DIR} -S . -DDB_ENGINE=PSQL
$ cmake --build ${BUILD_DIR}
-DDB_ENGINE=PSQL
to specify the database you want to use the ORM with. This flag only takesPSQL
for now since only postgres is supported for now.- Note that both static and dynamic libraries will be built for both use cases, avoiding rebuilding just to use a desired one.
To install to the default location specified by CMake, run:
$ cmake --install ${BUILD_DIR}
To install to a specified location, do:
$ cmake --install ${BUILD_DIR} --prefix ${DESTINATION}
Note
You might need sudo/admin privileges to run this command.
If it's a CMake project, add this in your CMakeLists.txt file immediately after cloning the repo:
add_subdirectory(strata)
target_link_libraries(my_project PRIVATE strata)
Examples can be found under the examples
directory in the source tree.
Model usage example
#include <memory>
#include <strata/models.hpp>
#include <strata/db_adapters.hpp>
class users : public Model{
public:
users(){
col_map["username"] = std::make_shared<CharField>(CharField("varchar", 24, true, true));
col_map["email"] = std::make_shared<CharField>(CharField("varchar", 50, true, true));
col_map["pin"] = std::make_shared<IntegerField>(IntegerField("integer", false, true));
}
};REGISTER_MODEL(users);
class message : public Model{
public:
message(){
col_map["sender"] = std::make_shared<ForeignKey>(ForeignKey("sender", "users", "users_id", std::nullopt, "CASCADE", "CASCADE"));
col_map["receiver"] = std::make_shared<ForeignKey>(ForeignKey("receiver", "users", "users_id", std::nullopt, "CASCADE", "CASCADE"));
col_map["content"] = std::make_shared<CharField>(CharField("varchar", 256, true));
}
};REGISTER_MODEL(message);
int main(){
Utils::dbenvars vars = {
{"DBUSER", ""},
{"DBPASS", ""},
{"DBNAME", ""},
{"DBHOST", ""},
{"DBPORT", ""}
};
Utils::set_dbenvars(vars);
Model model {};
nlohmann::json mrm {};
nlohmann::json frm {};
std::string sql_filename {"migrations.sql"};
model.make_migrations(mrm, frm, sql_filename);
db_adapter::opt_result_t result = db_adapter::execute_sql(sql_filename);
return 0;
}
Usage of inserts
This example uses a user-defined function .parse_json_rows()
defined inside the corresponding classes to convert json objects into pqxx::params
which
exec_insert
needs to insert into the database.
#include "./include/models.hpp"
#include <strata/db_adapters.hpp>
int main(){
Utils::dbenvars vars = {
{"DBUSER", ""},
{"DBPASS", ""},
{"DBNAME", ""},
{"DBHOST", ""},
{"DBPORT", ""}
};
Utils::set_dbenvars(vars);
users user {};
message m {};
using params = std::vector<pqxx::params>;
params user_rows = user.parse_json_rows();
params message_rows = m.parse_json_rows();
pqxx::connection cxn = db_adapter::prepare_insert<users>();
for(pqxx::params& user_row : user_rows){
db_adapter::exec_insert(cxn, user_row);
}
cxn = db_adapter::prepare_insert<message>();
for(pqxx::params& message_r : message_rows){
db_adapter::exec_insert(cxn, message_r);
}
return 0;
}
Queries Example
#include <strata/db_adapters.hpp>
#include "./include/models.hpp"
int main(){
Utils::dbenvars vars = {
{"DBUSER", ""},
{"DBPASS", ""},
{"DBNAME", ""},
{"DBHOST", ""},
{"DBPORT", ""}
};
Utils::set_dbenvars(vars);
users user {};
db_adapter::query::fetch_all(user, "*");
//db_adapter::query::get(user, "username", "berna");
filters filters = {
{"email", OP::CONTAINS, "gmail"},
{"username", OP::STARTSWITH, "b"}
};
db_adapter::query::filter(user, "or", filters);
std::vector<users> my_users = db_adapter::query::to_instances(user);
return 0;
}
Joins Example
#include <strata/db_adapters.hpp>
#include "./include/models.hpp"
int main(){
Utils::dbenvars vars = {
{"DBUSER", ""},
{"DBPASS", ""},
{"DBNAME", ""},
{"DBHOST", ""},
{"DBPORT", ""}
};
Utils::set_dbenvars(vars);
users user {};
db_adapter::query::JoinBuilder JB {user};
pqxx::result result = JB.select("username, email")
.inner_join("message")
.on("and", "users.users_id = message.sender")
.execute();
std::cout<<"Number of results returned: "<<result.size()<<std::endl;
return 0;
}
Note
Tests have not been implemented yet but will be soon.
All contributions are welcome. Please open an issue or submit a pull request for contributions to the library.