Files
sqlgen/docs/literals.md
T
2025-07-23 22:32:26 +02:00

128 lines
3.9 KiB
Markdown

# `sqlgen::literals`
The `sqlgen::literals` namespace provides user-defined literal operators for referencing columns and table aliases in a type-safe, expressive, and concise way when building SQL queries with sqlgen. These literals are essential for writing readable and maintainable query expressions, especially when working with complex queries involving joins and table aliases.
## Usage
### Column Literals: `_c`
Reference a column by name using the `_c` literal:
```cpp
using namespace sqlgen;
using namespace sqlgen::literals;
// Reference the "age" column
const auto age_col = "age"_c;
// Use in a query
const auto query = sqlgen::read<std::vector<Person>> | where("age"_c < 18);
```
This generates SQL like:
```sql
SELECT "id", "first_name", "last_name", "age"
FROM "Person"
WHERE "age" < 18;
```
If the column name does not exist in the struct, the code will fail to compile, ensuring type safety.
### Table Alias Literals: `_t1`, `_t2`, ..., `_t99`
When working with joins or subqueries, you often need to disambiguate columns by table alias. The `sqlgen::literals` namespace provides `_tN` suffixes for this purpose, where `N` ranges from 1 to 99:
```cpp
using namespace sqlgen;
using namespace sqlgen::literals;
// Reference the "id" column from table alias t1
const auto id_t1 = "id"_t1;
// Reference the "first_name" column from table alias t2
const auto first_name_t2 = "first_name"_t2;
```
#### Example: Joins with Aliases
```cpp
const auto get_people =
select_from<Person, "t1">(
"last_name"_t1 | as<"last_name">,
"first_name"_t1 | as<"first_name_parent">,
"first_name"_t3 | as<"first_name_child">,
("age"_t1 - "age"_t3) | as<"parent_age_at_birth">
)
| inner_join<Relationship, "t2">("id"_t1 == "parent_id"_t2)
| left_join<Person, "t3">("id"_t3 == "child_id"_t2)
| order_by("id"_t1, "id"_t3)
| to<std::vector<ParentAndChild>>;
```
This produces SQL like:
```sql
SELECT t1."last_name" AS "last_name", t1."first_name" AS "first_name_parent", t3."first_name" AS "first_name_child", (t1."age") - (t3."age") AS "parent_age_at_birth"
FROM "Person" t1
INNER JOIN "Relationship" t2 ON t1."id" = t2."parent_id"
LEFT JOIN "Person" t3 ON t3."id" = t2."child_id"
ORDER BY t1."id", t3."id"
```
### Supported Suffixes
- `_c` — Reference a column by name (e.g., `"age"_c`)
- `_t1`, `_t2`, ..., `_t99` — Reference a column by name and table alias (e.g., `"id"_t2`)
All these literals are defined in the `sqlgen::literals` namespace. It is strongly recommended to use:
```cpp
using namespace sqlgen::literals;
```
in your query files for convenience.
## Type Safety
- Column names are checked at compile time against the struct definition.
- Table aliases are enforced by the literal suffix, preventing ambiguous references in joins.
- If you use a column or alias that does not exist, the code will fail to compile.
## Advanced: Custom Aliases
If you need an alias outside the provided `_tN` range, you can use the `col` template directly:
```cpp
const auto custom_col = col<"id", "custom_alias">;
```
## Notes
- The `_c` and `_tN` literals return `Col` objects, which support all standard SQL operations (comparison, ordering, etc.).
- These literals are composable with all sqlgen query builder functions, such as `where`, `order_by`, `group_by`, and join conditions.
- The use of these literals is required for type-safe, readable, and maintainable query construction in sqlgen.
- All operations are thread-safe and have no mutable state.
## Example: Full Query Composition
```cpp
using namespace sqlgen;
using namespace sqlgen::literals;
const auto query = sqlgen::read<std::vector<Person>>
| where("age"_c >= 18 and "last_name"_c == "Simpson")
| order_by("first_name"_c.desc())
| limit(10);
```
This generates:
```sql
SELECT "id", "first_name", "last_name", "age"
FROM "Person"
WHERE ("age" >= 18) AND ("last_name" = 'Simpson')
ORDER BY "first_name" DESC
LIMIT 10;
```