Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9c5e4ab
I have created the `include/sqlgen/union.hpp` file with the basic str…
google-labs-jules[bot] Nov 20, 2025
b61c04e
Various fixes
liuzicheng1987 Nov 20, 2025
2a00904
Merge branch 'main' into f-union
liuzicheng1987 Nov 20, 2025
b47b428
Merge branch 'main' into f-union
liuzicheng1987 Nov 21, 2025
5238fdf
Added compile-time checks
liuzicheng1987 Nov 21, 2025
cd7a5b6
Added support for unions inside SELECT FROM
liuzicheng1987 Nov 22, 2025
a86ab3c
I have successfully added the `all` flag to the `Union` struct in `in…
google-labs-jules[bot] Nov 22, 2025
480514e
Fixed various issues
liuzicheng1987 Nov 22, 2025
28f6df2
Added another test for unions in joins
liuzicheng1987 Nov 22, 2025
a4af042
Fixed documentation
liuzicheng1987 Nov 22, 2025
52d5186
Adapted postgres
liuzicheng1987 Nov 22, 2025
41bb284
Adapted MySQL
liuzicheng1987 Nov 22, 2025
ca9d931
Adapted DuckDB
liuzicheng1987 Nov 23, 2025
19b00a0
Adapted tests
liuzicheng1987 Nov 23, 2025
3e55cc4
Removed the Conan tests for lack of stability
liuzicheng1987 Nov 23, 2025
68bfced
Renamed template types
liuzicheng1987 Nov 23, 2025
c1147c9
_selects -> _stmts
liuzicheng1987 Nov 23, 2025
4de26c6
Set all inside transpilation
liuzicheng1987 Nov 23, 2025
281873f
Fixed typo
liuzicheng1987 Nov 23, 2025
b31f00e
Adapted tests
liuzicheng1987 Nov 23, 2025
c90ff3d
_s -> _stmt
liuzicheng1987 Nov 23, 2025
636d9f6
Fixed typo
liuzicheng1987 Nov 23, 2025
854e060
_query -> _stmt
liuzicheng1987 Nov 23, 2025
28417d7
Next attempt
liuzicheng1987 Nov 23, 2025
f069aea
Simplified to_select_from
liuzicheng1987 Nov 23, 2025
45c2ee5
Try to infer the types instead
liuzicheng1987 Nov 23, 2025
15d3b92
As parameter packs
liuzicheng1987 Nov 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 0 additions & 73 deletions .github/workflows/linux-cxx20-conan.yaml

This file was deleted.

47 changes: 0 additions & 47 deletions .github/workflows/macos-cxx20-conan.yaml

This file was deleted.

1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Welcome to the sqlgen documentation. This guide provides detailed information ab
- [sqlgen::inner_join, sqlgen::left_join, sqlgen::right_join, sqlgen::full_join](joins.md) - How to join different tables
- [sqlgen::insert](insert.md) - How to insert data within transactions
- [sqlgen::select_from](select_from.md) - How to read data from a database using more complex queries
- [sqlgen::unite and sqlgen::unite_all](unite.md) - How to combine results from multiple SELECT statements
- [sqlgen::update](update.md) - How to update data in a table

## Other Operations
Expand Down
80 changes: 80 additions & 0 deletions docs/unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# `unite` and `unite_all`

The `unite` and `unite_all` functions allow you to combine the results of multiple `SELECT` statements into a single result set.

## `unite`

The `unite` function corresponds to the SQL `UNION` operator. It combines the result sets of two or more `SELECT` statements and removes duplicate rows.

### Example

```cpp
struct User1 {
std::string name;
int age;
};

struct User2 {
std::string name;
int age;
};

const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);

const auto united = sqlgen::unite<std::vector<User1>>(s1, s2);
```

## `unite_all`

The `unite_all` function corresponds to the SQL `UNION ALL` operator. It combines the result sets of two or more `SELECT` statements, including all duplicate rows.

### Example

```cpp
struct User1 {
std::string name;
int age;
};

struct User2 {
std::string name;
int age;
};

const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);

const auto united = sqlgen::unite_all<std::vector<User1>>(s1, s2);
```

## Nesting in `SELECT` statements

You can use the result of a `unite` or `unite_all` operation as a subquery in a `SELECT` statement.

### Example

```cpp
const auto united = sqlgen::unite<std::vector<User1>>(s1, s2);

const auto sel = sqlgen::select_from(united.as("u"), "name"_c, "age"_c);
```

## Nesting in `JOIN` statements

You can also use the result of a `unite` or `unite_all` operation as a subquery in a `JOIN` statement.

### Example

```cpp
struct Login {
int id;
std::string username;
};

const auto united = sqlgen::unite<std::vector<User1>>(s1, s2);

const auto sel = select_from<Login, "t1">("id"_t1, "username"_t1) |
inner_join<"t2">(united, "username"_t1 == "name"_t2) |
where("id"_t1 == 1) | to<std::vector<Login>>;
```
1 change: 1 addition & 0 deletions include/sqlgen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "sqlgen/select_from.hpp"
#include "sqlgen/sqlgen_api.hpp"
#include "sqlgen/to.hpp"
#include "sqlgen/unite.hpp"
#include "sqlgen/update.hpp"
#include "sqlgen/where.hpp"
#include "sqlgen/write.hpp"
Expand Down
5 changes: 3 additions & 2 deletions include/sqlgen/duckdb/Connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ class SQLGEN_API Connection {
}

template <class ContainerType>
auto read(const dynamic::SelectFrom &_query) {
auto read(const rfl::Variant<dynamic::SelectFrom, dynamic::Union> &_query) {
using ValueType = transpilation::value_t<ContainerType>;
const auto sql = _query.visit([&](const auto &_q) { return to_sql(_q); });
return internal::to_container<ContainerType, Iterator<ValueType>>(
Iterator<ValueType>(to_sql(_query), conn_));
Iterator<ValueType>(sql, conn_));
}

Result<Nothing> rollback() noexcept;
Expand Down
8 changes: 7 additions & 1 deletion include/sqlgen/dynamic/SelectFrom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@
namespace sqlgen::dynamic {

struct SelectFrom {
using TableOrQueryType = rfl::Variant<Table, Ref<SelectFrom>>;
struct Union {
std::vector<std::string> columns;
Ref<std::vector<SelectFrom>> selects;
bool all = false;
};

using TableOrQueryType = rfl::Variant<Table, Ref<SelectFrom>, Ref<Union>>;

struct Field {
Operation val;
Expand Down
3 changes: 2 additions & 1 deletion include/sqlgen/dynamic/Statement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
#include "Drop.hpp"
#include "Insert.hpp"
#include "SelectFrom.hpp"
#include "Union.hpp"
#include "Update.hpp"
#include "Write.hpp"

namespace sqlgen::dynamic {

using Statement =
rfl::TaggedUnion<"stmt", CreateAs, CreateIndex, CreateTable, DeleteFrom,
Drop, Insert, SelectFrom, Update, Write>;
Drop, Insert, SelectFrom, Union, Update, Write>;

} // namespace sqlgen::dynamic

Expand Down
12 changes: 12 additions & 0 deletions include/sqlgen/dynamic/Union.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef SQLGEN_DYNAMIC_UNION_HPP_
#define SQLGEN_DYNAMIC_UNION_HPP_

#include "SelectFrom.hpp"

namespace sqlgen::dynamic {

using Union = SelectFrom::Union;

} // namespace sqlgen::dynamic

#endif
14 changes: 10 additions & 4 deletions include/sqlgen/internal/GetColType.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ struct GetColType {
static Type get_value(const T& _t) { return _t; }
};

template <rfl::internal::StringLiteral _name>
struct GetColType<Col<_name>> {
using Type = transpilation::Col<_name>;
static Type get_value(const auto&) { return transpilation::Col<_name>{}; }
template <rfl::internal::StringLiteral _name,
rfl::internal::StringLiteral _alias>
struct GetColType<Col<_name, _alias>> {
using Type = transpilation::Col<_name, _alias>;
static Type get_value(const auto&) {
return transpilation::Col<_name, _alias>{};
}
};

template <class T>
using get_col_type_t = typename GetColType<T>::Type;

} // namespace sqlgen::internal

#endif
23 changes: 23 additions & 0 deletions include/sqlgen/internal/all_same_v.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <rfl.hpp>
#include <tuple>
#include <type_traits>

namespace sqlgen::internal {

template <class TupleT>
struct AllSame;

template <class Head, class... Tail>
struct AllSame<std::tuple<Head, Tail...>> {
static constexpr bool value = std::conjunction_v<std::is_same<Head, Tail>...>;
};

template <class Head, class... Tail>
struct AllSame<rfl::Tuple<Head, Tail...>> {
static constexpr bool value = std::conjunction_v<std::is_same<Head, Tail>...>;
};

template <class TupleT>
constexpr bool all_same_v = AllSame<std::remove_cvref_t<TupleT>>::value;

} // namespace sqlgen::internal
8 changes: 6 additions & 2 deletions include/sqlgen/mysql/Connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
#include "../Result.hpp"
#include "../Transaction.hpp"
#include "../dynamic/Column.hpp"
#include "../dynamic/Insert.hpp"
#include "../dynamic/SelectFrom.hpp"
#include "../dynamic/Statement.hpp"
#include "../dynamic/Union.hpp"
#include "../dynamic/Write.hpp"
#include "../internal/to_container.hpp"
#include "../internal/write_or_insert.hpp"
Expand Down Expand Up @@ -54,7 +57,7 @@ class SQLGEN_API Connection {
}

template <class ContainerType>
auto read(const dynamic::SelectFrom& _query) {
auto read(const rfl::Variant<dynamic::SelectFrom, dynamic::Union>& _query) {
using ValueType = transpilation::value_t<ContainerType>;
return internal::to_container<ContainerType>(
read_impl(_query).transform([](auto&& _it) {
Expand Down Expand Up @@ -94,7 +97,8 @@ class SQLGEN_API Connection {
const std::variant<dynamic::Insert, dynamic::Write>& _stmt)
const noexcept;

Result<Ref<Iterator>> read_impl(const dynamic::SelectFrom& _query);
Result<Ref<Iterator>> read_impl(
const rfl::Variant<dynamic::SelectFrom, dynamic::Union>& _query);

Result<Nothing> write_impl(
const std::vector<std::vector<std::optional<std::string>>>& _data);
Expand Down
10 changes: 8 additions & 2 deletions include/sqlgen/postgres/Connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@
#include <libpq-fe.h>

#include <memory>
#include <optional>
#include <rfl.hpp>
#include <stdexcept>
#include <string>
#include <vector>

#include "../Iterator.hpp"
#include "../Ref.hpp"
#include "../Result.hpp"
#include "../Transaction.hpp"
#include "../dynamic/Column.hpp"
#include "../dynamic/Insert.hpp"
#include "../dynamic/SelectFrom.hpp"
#include "../dynamic/Statement.hpp"
#include "../dynamic/Union.hpp"
#include "../dynamic/Write.hpp"
#include "../internal/iterator_t.hpp"
#include "../internal/to_container.hpp"
Expand Down Expand Up @@ -57,7 +62,7 @@ class SQLGEN_API Connection {
}

template <class ContainerType>
auto read(const dynamic::SelectFrom& _query) {
auto read(const rfl::Variant<dynamic::SelectFrom, dynamic::Union>& _query) {
using ValueType = transpilation::value_t<ContainerType>;
return internal::to_container<ContainerType>(
read_impl(_query).transform([](auto&& _it) {
Expand Down Expand Up @@ -86,7 +91,8 @@ class SQLGEN_API Connection {
const std::vector<std::vector<std::optional<std::string>>>&
_data) noexcept;

Result<Ref<Iterator>> read_impl(const dynamic::SelectFrom& _query);
Result<Ref<Iterator>> read_impl(
const rfl::Variant<dynamic::SelectFrom, dynamic::Union>& _query);

std::string to_buffer(
const std::vector<std::optional<std::string>>& _line) const noexcept;
Expand Down
Loading
Loading