Added documentation for create_index and create_table

This commit is contained in:
Dr. Patrick Urbanke
2025-05-18 18:52:16 +02:00
parent 6d6e957e42
commit 816568f40e
2 changed files with 245 additions and 0 deletions

141
docs/create_index.md Normal file
View File

@@ -0,0 +1,141 @@
# `sqlgen::create_index`
The `sqlgen::create_index` interface provides a type-safe way to create indexes on SQL database tables. It supports creating both regular and unique indexes, with optional `if_not_exists` clause to handle cases where the index may already exist.
## Usage
### Basic Index Creation
Create an index on one or more columns:
```cpp
const auto conn = sqlgen::sqlite::connect("database.db");
sqlgen::create_index<"person_ix", Person>("first_name"_c, "last_name"_c)(conn).value();
```
This generates the following SQL:
```sql
CREATE INDEX "person_ix" ON "Person" ("first_name", "last_name");
```
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<Ref<Connection>>
const auto result = sqlgen::sqlite::connect("database.db").and_then(
sqlgen::create_index<"person_ix", Person>("first_name"_c, "last_name"_c));
```
Please refer to the documentation on `sqlgen::Result<...>` for more information on error handling.
### With `if_not_exists` clause
Create an index only if it doesn't already exist:
```cpp
using namespace sqlgen;
const auto query = create_index<"person_ix", Person>("first_name"_c, "last_name"_c) | if_not_exists;
query(conn).value();
```
This generates the following SQL:
```sql
CREATE INDEX IF NOT EXISTS "person_ix" ON "Person" ("first_name", "last_name");
```
You can also use monadic error handling here:
```cpp
using namespace sqlgen;
const auto query = create_index<"person_ix", Person>("first_name"_c, "last_name"_c) | if_not_exists;
// sqlgen::Result<Ref<Connection>>
const auto result = sqlite::connect("database.db").and_then(query);
```
### Creating Unique Indexes
Create a unique index to enforce uniqueness constraints:
```cpp
using namespace sqlgen;
const auto query = create_unique_index<"person_ix", Person>("first_name"_c, "last_name"_c);
query(conn).value();
```
This generates the following SQL:
```sql
CREATE UNIQUE INDEX "person_ix" ON "Person" ("first_name", "last_name");
```
### Creating Indexes with WHERE Clause
Create a partial index by adding a WHERE clause to filter which rows are included in the index:
```cpp
using namespace sqlgen;
const auto query = create_index<"test_table_ix", TestTable>("field1"_c, "field2"_c) |
if_not_exists |
where("field2"_c > 0);
query(conn).value();
```
This generates the following SQL:
```sql
CREATE INDEX IF NOT EXISTS "test_table_ix" ON "TestTable"("field1", "field2") WHERE "field2" > 0;
```
The WHERE clause can be combined with other modifiers like `if_not_exists` and works with both regular and unique indexes. This is particularly useful for creating partial indexes that only include rows matching certain conditions, which can improve index performance and reduce index size.
## Example: Full Query Composition
```cpp
using namespace sqlgen;
const auto query = create_index<"person_ix", Person>("first_name"_c, "last_name"_c) | if_not_exists;
const auto result = query(conn);
if (!result) {
// Error handling
}
```
This generates the following SQL:
```sql
CREATE INDEX IF NOT EXISTS "person_ix" ON "Person" ("first_name", "last_name");
```
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:
```cpp
const auto query = sqlgen::create_index<"person_ix", Person>("first_name"_c, "last_name"_c) |
sqlgen::if_not_exists;
const auto result = query(conn);
```
## Notes
- The `if_not_exists` clause is optional - if omitted, the query will fail if the index already exists
- The `Result<Ref<Connection>>` type provides error handling; use `.value()` to extract the result (will throw an exception if there's an error) or handle errors as needed or refer to the documentation on `sqlgen::Result<...>` for other forms of error handling.
- `"..."_c` refers to the name of the column. If such a field does not exist on the struct (e.g., `Person`), the code will fail to compile.
- Index names must be unique within a database
- You can create indexes on multiple columns by providing multiple column names
- Use `create_unique_index` when you need to enforce uniqueness constraints on the indexed columns

104
docs/create_table.md Normal file
View File

@@ -0,0 +1,104 @@
# `sqlgen::create_table`
The `sqlgen::create_table` interface provides a type-safe way to create tables in a SQL database. It supports the `if_not_exists` clause to handle cases where the table may already exist.
## Usage
### Basic Create Table
Create a table:
```cpp
const auto conn = sqlgen::sqlite::connect("database.db");
sqlgen::create_table<Person>(conn).value();
```
This generates the following SQL:
```sql
CREATE TABLE "Person" ("id" INTEGER NOT NULL, "first_name" TEXT NOT NULL, "last_name" TEXT NOT NULL, "age" INTEGER NOT NULL);
```
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<Ref<Connection>>
const auto result = sqlgen::sqlite::connect("database.db").and_then(
sqlgen::create_table<Person>);
```
Please refer to the documentation on `sqlgen::Result<...>` for more information on error handling.
### With `if_not_exists` clause
Create a table only if it doesn't exist:
```cpp
using namespace sqlgen;
const auto query = create_table<Person> | if_not_exists;
query(conn).value();
```
This generates the following SQL:
```sql
CREATE TABLE IF NOT EXISTS "Person" ("id" INTEGER NOT NULL, "first_name" TEXT NOT NULL, "last_name" TEXT NOT NULL, "age" INTEGER NOT NULL);
```
You can also use monadic error handling here:
```cpp
using namespace sqlgen;
const auto query = create_table<Person> | if_not_exists;
// sqlgen::Result<Ref<Connection>>
const auto result = sqlite::connect("database.db").and_then(query);
```
## Example: Full Query Composition
```cpp
using namespace sqlgen;
const auto query = create_table<Person> | if_not_exists;
const auto result = query(conn);
if (!result) {
// Error handling
}
```
This generates the following SQL:
```sql
CREATE TABLE IF NOT EXISTS "Person" ("id" INTEGER NOT NULL, "first_name" TEXT NOT NULL, "last_name" TEXT NOT NULL, "age" INTEGER NOT NULL);
```
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:
```cpp
const auto query = sqlgen::create_table<Person> | sqlgen::if_not_exists;
const auto result = query(conn);
```
## Notes
- The `if_not_exists` clause is optional - if omitted, the query will fail if the table already exists
- The `Result<Ref<Connection>>` type provides error handling; use `.value()` to extract the result (will throw an exception if there's an error) or handle errors as needed or refer to the documentation on `sqlgen::Result<...>` for other forms of error handling.
- The table name is derived from the struct name (e.g., `Person` becomes `"Person"` in SQL)
- Column types are automatically mapped from C++ types:
- `std::string``TEXT`
- `int`/`int32_t``INTEGER`
- `uint32_t``INTEGER`
- `std::optional<T>` → nullable column of type T
- `sqlgen::PrimaryKey<T>` → column of type T with PRIMARY KEY constraint
- All columns are NOT NULL by default unless they are `std::optional`