mirror of
https://github.com/getml/sqlgen.git
synced 2026-01-06 01:19:58 -06:00
205 lines
5.6 KiB
Markdown
205 lines
5.6 KiB
Markdown
#  sqlgen
|
|
|
|
[](https://opensource.org/licenses/MIT)
|
|
[](https://github.com/getml/reflect-cpp/graphs/commit-activity)
|
|
[](https://shields.io/)
|
|
[](https://shields.io/)
|
|
|
|
sqlgen is a modern, type-safe ORM and SQL query generator for C++20, inspired by Python's [SQLAlchemy](https://github.com/sqlalchemy/sqlalchemy)/[SQLModel](https://github.com/fastapi/sqlmodel) and Rust's [Diesel](https://github.com/diesel-rs/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](https://github.com/getml/reflect-cpp)
|
|
|
|
## Quick Start
|
|
|
|
### Installation
|
|
|
|
1. Install required dependencies:
|
|
```bash
|
|
sudo apt-get install autoconf bison flex libpq-dev libsqlite3-dev
|
|
```
|
|
|
|
2. Set up vcpkg:
|
|
```bash
|
|
git submodule update --init
|
|
./vcpkg/bootstrap-vcpkg.sh # Linux, macOS
|
|
./vcpkg/bootstrap-vcpkg.bat # Windows
|
|
```
|
|
|
|
3. Build the library:
|
|
```bash
|
|
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
|
|
```
|
|
|
|
4. Include in your CMake project:
|
|
```cmake
|
|
find_package(sqlgen REQUIRED)
|
|
target_link_libraries(your_target PRIVATE sqlgen::sqlgen)
|
|
```
|
|
|
|
## Usage Examples
|
|
|
|
### Hello World
|
|
|
|
```cpp
|
|
#include <sqlgen/sqlite.hpp>
|
|
#include <iostream>
|
|
|
|
struct User {
|
|
std::string name;
|
|
int age;
|
|
};
|
|
|
|
int main() {
|
|
// Connect to SQLite database
|
|
const auto conn = sqlgen::sqlite::connect("test.db");
|
|
|
|
// Create and insert a user
|
|
const auto user = User{.name = "John", .age = 30};
|
|
sqlgen::write(conn, user);
|
|
|
|
// Read all users
|
|
const auto users = sqlgen::read<std::vector<User>>(conn).value();
|
|
|
|
for (const auto& u : users) {
|
|
std::cout << u.name << " is " << u.age << " years old\n";
|
|
}
|
|
}
|
|
```
|
|
|
|
### Connecting to a Database
|
|
|
|
```cpp
|
|
#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
|
|
|
|
```cpp
|
|
struct Person {
|
|
std::string first_name;
|
|
std::string last_name;
|
|
uint32_t age;
|
|
std::optional<std::string> email; // Nullable field
|
|
};
|
|
```
|
|
|
|
### Inserting Data
|
|
|
|
```cpp
|
|
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:
|
|
```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
|
|
|
|
```cpp
|
|
#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:
|
|
```sql
|
|
SELECT "first_name", "last_name", "age", "email"
|
|
FROM "Person"
|
|
WHERE "age" >= 18
|
|
ORDER BY "age" DESC, "last_name"
|
|
LIMIT 10;
|
|
```
|
|
|
|
### Type Safety and SQL Injection Protection
|
|
|
|
sqlgen provides comprehensive compile-time checks and runtime protection:
|
|
|
|
```cpp
|
|
// 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](docs/README.md).
|
|
|
|
## Contributing
|
|
|
|
We welcome constructive criticism, feature requests and contributions! Please open an issue or a pull request.
|
|
|
|
## License
|
|
|
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|