mirror of
https://github.com/getml/sqlgen.git
synced 2026-01-01 23:19:58 -06:00
Added SQL snippets to the documentation
This commit is contained in:
@@ -11,18 +11,26 @@ Read all rows from a table into a container (e.g., `std::vector<Person>`):
|
||||
```cpp
|
||||
const auto conn = sqlgen::sqlite::connect("database.db");
|
||||
|
||||
const auto people = sqlgen::read<std::vector<Person>>(conn).value();
|
||||
const std::vector<Person> people = sqlgen::read<std::vector<Person>>(conn).value();
|
||||
```
|
||||
|
||||
This generates the following SQL:
|
||||
|
||||
```sql
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person";
|
||||
```
|
||||
|
||||
Note that `conn` is actually a connection wrapped into an `sqlgen::Result<...>`.
|
||||
This means you can use monadic error handling and fit this into a single line:
|
||||
|
||||
```cpp
|
||||
// sqlgen::Result<std::vector<Person>>
|
||||
const auto people = sqlgen::sqlite::connect("database.db").and_then(
|
||||
sqlgen::read<std::vector<Person>>).value();
|
||||
sqlgen::read<std::vector<Person>>);
|
||||
```
|
||||
|
||||
Please refer to the documentation on `sqlgen::Result<...>` for more information.
|
||||
Please refer to the documentation on `sqlgen::Result<...>` for more information on error handling.
|
||||
|
||||
### With `where` clause
|
||||
|
||||
@@ -37,6 +45,16 @@ const auto query = sqlgen::read<std::vector<Person>> |
|
||||
const auto minors = query(conn).value();
|
||||
```
|
||||
|
||||
This generates the following SQL:
|
||||
|
||||
```sql
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE
|
||||
("age" < 18) AND
|
||||
("first_name" != 'Hugo');
|
||||
```
|
||||
|
||||
Note that `"..."_c` refers to the name of the column. If such a field does not
|
||||
exists on the struct `Person`, the code will fail to compile.
|
||||
|
||||
@@ -48,7 +66,8 @@ using namespace sqlgen;
|
||||
const auto query = sqlgen::read<std::vector<Person>> |
|
||||
where("age"_c < 18 and "first_name"_c != "Hugo");
|
||||
|
||||
const auto minors = sqlite::connect("database.db").and_then(query).value();
|
||||
// sqlgen::Result<std::vector<Person>>
|
||||
const auto minors = sqlite::connect("database.db").and_then(query);
|
||||
```
|
||||
|
||||
### With `order_by` and `limit`
|
||||
@@ -65,17 +84,43 @@ const auto query = sqlgen::read<std::vector<Person>> |
|
||||
const auto youngest_two = query(conn).value();
|
||||
```
|
||||
|
||||
This generates the following SQL:
|
||||
|
||||
```sql
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
ORDER BY "age"
|
||||
LIMIT 2;
|
||||
```
|
||||
|
||||
### With ranges
|
||||
|
||||
Read results as a lazy range:
|
||||
|
||||
```cpp
|
||||
const auto people_range = sqlgen::read<sqlgen::Range<Person>>(conn).value();
|
||||
|
||||
for (const sqlgen::Result<Person>& person : people_range) {
|
||||
// process result
|
||||
}
|
||||
```
|
||||
|
||||
`sqlgen::Range<T>` satisfies the `std::ranges::input_range` concept, making it compatible with C++20 ranges and views. This allows for memory-efficient iteration through database results and enables composition with other range operations:
|
||||
|
||||
```cpp
|
||||
using namespace std::ranges::views;
|
||||
|
||||
// Transform range results
|
||||
const auto first_names = people_range | transform([](const sqlgen::Result<Person>& r) {
|
||||
return r.value().first_name;
|
||||
});
|
||||
|
||||
// Filter range results
|
||||
const auto adults = people_range | filter([](const sqlgen::Result<Person>& r) {
|
||||
return r && r->age >= 18;
|
||||
});
|
||||
```
|
||||
|
||||
## Example: Full Query Composition
|
||||
|
||||
```cpp
|
||||
@@ -89,6 +134,19 @@ const auto query = sqlgen::read<std::vector<Person>> |
|
||||
const auto adults = query(conn).value();
|
||||
```
|
||||
|
||||
This generates the following SQL:
|
||||
|
||||
```sql
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE
|
||||
("age" >= 18)
|
||||
ORDER BY
|
||||
"last_name",
|
||||
"first_name" DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
It is strongly recommended that you use `using namespace sqlgen`. However,
|
||||
if you do not want to do that, you can rewrite the example above as follows:
|
||||
|
||||
|
||||
@@ -19,6 +19,32 @@ const auto conn = sqlgen::sqlite::connect();
|
||||
sqlgen::write(conn, people);
|
||||
```
|
||||
|
||||
This generates the following SQL for PostgreSQL:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS "Person" (
|
||||
"id" INTEGER,
|
||||
"first_name" TEXT NOT NULL,
|
||||
"last_name" TEXT NOT NULL,
|
||||
"age" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
COPY "Person"("id", "first_name", "last_name", "age") FROM STDIN WITH DELIMITER '\t' NULL '\e' QUOTE '\a';
|
||||
```
|
||||
|
||||
For other dialects like SQLite, it uses prepared INSERT statements instead:
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS "Person" (
|
||||
"id" INTEGER,
|
||||
"first_name" TEXT NOT NULL,
|
||||
"last_name" TEXT NOT NULL,
|
||||
"age" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "Person" ("id", "first_name", "last_name", "age") VALUES (?, ?, ?, ?);
|
||||
```
|
||||
|
||||
### With Result<Ref<Connection>>
|
||||
|
||||
Handle connection creation and writing in a single chain:
|
||||
@@ -29,6 +55,8 @@ sqlgen::sqlite::connect("database.db")
|
||||
.value();
|
||||
```
|
||||
|
||||
This generates the same SQL as above, adapted to the specific database dialect being used.
|
||||
|
||||
### With Iterators
|
||||
|
||||
Write a range of objects using iterators:
|
||||
@@ -38,6 +66,8 @@ std::vector<Person> people = /* ... */;
|
||||
sqlgen::write(conn, people.begin(), people.end());
|
||||
```
|
||||
|
||||
This also generates the same SQL, adapted to the specific database dialect.
|
||||
|
||||
## How It Works
|
||||
|
||||
The `write` function performs the following operations in sequence:
|
||||
@@ -56,4 +86,7 @@ The `write` function performs the following operations in sequence:
|
||||
1. Takes a connection reference and iterators
|
||||
2. Takes a `Result<Ref<Connection>>` and iterators
|
||||
3. Takes a connection and a container directly
|
||||
- The SQL generation adapts to the database dialect:
|
||||
- PostgreSQL uses the efficient COPY command for bulk inserts
|
||||
- Other dialects use prepared INSERT statements
|
||||
|
||||
|
||||
Reference in New Issue
Block a user