2025-05-10 17:10:36 +02:00
2025-05-10 16:32:34 +02:00
2025-05-10 16:32:34 +02:00
2025-03-29 06:09:34 +01:00
2025-03-19 06:44:18 +01:00
2025-03-18 04:00:16 +01:00
2025-03-29 06:09:34 +01:00
2025-03-17 12:57:52 +08:00
2025-05-10 16:46:27 +02:00
2025-03-18 04:06:15 +01:00
2025-03-18 03:40:30 +01:00
2025-04-15 08:18:28 +02:00

C++ sqlgen

License: MIT Maintenance Generic badge Generic badge

sqlgen is a modern, type-safe ORM and SQL query generator for C++20, inspired by Python's SQLAlchemy/SQLModel and Rust's Diesel. It provides a fluent, composable interface for database operations with compile-time type checking and SQL injection protection.

Features

  • 🔒 Type Safety: Compile-time validation of table schemas and queries
  • 🛡️ SQL Injection Protection: Built-in input validation and parameterized queries
  • 🔄 Composable Queries: Fluent interface for building complex queries
  • 🚀 High Performance: Efficient batch operations and prepared statements
  • 📦 Modern C++: Leverages C++20 features for a clean, expressive API
  • 🔌 Multiple Backends: Support for PostgreSQL and SQLite
  • 🔍 Reflection Integration: Seamless integration with reflect-cpp

Quick Start

Installation

  1. Install required dependencies for PostgreSQL:
sudo apt-get install autoconf bison flex
  1. Set up vcpkg:
git submodule update --init
./vcpkg/bootstrap-vcpkg.sh  # Linux, macOS
./vcpkg/bootstrap-vcpkg.bat # Windows
  1. Build the library:
cmake -S . -B build -DCMAKE_CXX_STANDARD=20 -DCMAKE_BUILD_TYPE=Release
cmake --build build -j 4  # gcc, clang
cmake --build build --config Release -j 4  # MSVC

Usage Examples

Connecting to a Database

#include <sqlgen/postgres.hpp>

// PostgreSQL connection
const auto credentials = sqlgen::postgres::Credentials{
    .user = "username",
    .password = "password",
    .host = "localhost",
    .dbname = "mydb",
    .port = 5432
};

const auto conn = sqlgen::postgres::connect(credentials);

// SQLite connection
const auto sqlite_conn = sqlgen::sqlite::connect("database.db");

Defining Models

struct Person {
    std::string first_name;
    std::string last_name;
    uint32_t age;
    std::optional<std::string> email;  // Nullable field
};

Inserting Data

const auto people = std::vector<Person>({
    Person{.first_name = "Homer", .last_name = "Simpson", .age = 45},
    Person{.first_name = "Marge", .last_name = "Simpson", .age = 42}
});

// Automatically creates table if it doesn't exist
const auto result = sqlgen::write(conn, people);

if (!result) {
    std::cerr << "Error: " << result.error().what() << std::endl;
}

Generated SQL:

CREATE TABLE IF NOT EXISTS "Person" (
    "first_name" TEXT NOT NULL,
    "last_name" TEXT NOT NULL,
    "age" INTEGER NOT NULL,
    "email" TEXT
);

INSERT INTO "Person" ("first_name", "last_name", "age", "email") 
VALUES (?, ?, ?, ?);

Querying Data

#include <rfl/json.hpp>
#include <sqlgen/postgres.hpp>

using namespace sqlgen;

// Build a query for adults, ordered by age
const auto query = read<std::vector<Person>> |
                   where("age"_c >= 18) |
                   order_by("age"_c.desc(), "last_name"_c) |
                   limit(10);

// Execute the query
const auto result = query(conn);

if (result) {
    // Print results as JSON
    std::cout << rfl::json::write(*result) << std::endl;
} else {
    std::cerr << "Error: " << result.error().what() << std::endl;
}

Generated SQL:

SELECT "first_name", "last_name", "age", "email"
FROM "Person"
WHERE "age" >= 18
ORDER BY "age" DESC, "last_name"
LIMIT 10;

Deleting Data

using namespace sqlgen;

// Delete specific records
const auto query = delete_from<Person> |
                   where("last_name"_c == "Simpson" and "age"_c < 18);

const auto result = query(conn);
if (!result) {
    std::cerr << "Error: " << result.error().what() << std::endl;
}

Dropping Tables

using namespace sqlgen;

// Safely drop a table if it exists
const auto query = drop<Person> | if_exists;
query(conn).value();

Type Safety and SQL Injection Protection

sqlgen provides comprehensive compile-time checks and runtime protection:

// Compile-time error: No such column "color"
const auto query = read<std::vector<Person>> |
                   where("color"_c == "blue");

// Runtime protection against SQL injection
std::vector<Person> get_people(const auto& conn, 
                              const sqlgen::AlphaNumeric& first_name) {
    using namespace sqlgen;
    return (read<std::vector<Person>> | 
            where("first_name"_c == first_name))(conn).value();
}

// This will be rejected
get_people(conn, "Homer' OR '1'='1");  // SQL injection attempt

Documentation

For detailed documentation, visit our documentation page.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Description
sqlgen is a reflection-based ORM and SQL query generator for C++-20, similar to Python's SQLAlchemy/SQLModel or Rust's Diesel.
Readme MIT 2.2 MiB
Languages
C++ 98.8%
CMake 0.9%
Python 0.3%