Skip to content

Commit ca9d931

Browse files
Adapted DuckDB
1 parent 41bb284 commit ca9d931

8 files changed

Lines changed: 356 additions & 206 deletions

File tree

include/sqlgen/duckdb/Connection.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SQLGEN_API Connection {
7474
template <class ContainerType>
7575
auto read(const rfl::Variant<dynamic::SelectFrom, dynamic::Union> &_query) {
7676
using ValueType = transpilation::value_t<ContainerType>;
77-
const auto sql = _query.visit([](const auto &_q) { return to_sql(_q); });
77+
const auto sql = _query.visit([&](const auto &_q) { return to_sql(_q); });
7878
return internal::to_container<ContainerType, Iterator<ValueType>>(
7979
Iterator<ValueType>(sql, conn_));
8080
}

src/sqlgen/duckdb/to_sql.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,9 +933,7 @@ std::string union_to_sql(const dynamic::Union& _stmt) noexcept {
933933
_stmt.all ? std::string(" UNION ALL ") : std::string(" UNION ");
934934

935935
return internal::strings::join(
936-
separator,
937-
internal::collect::vector(*_stmt.selects | transform(to_str))) +
938-
";";
936+
separator, internal::collect::vector(*_stmt.selects | transform(to_str)));
939937
}
940938

941939
std::string update_to_sql(const dynamic::Update& _stmt) noexcept {

tests/duckdb/test_union.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <rfl.hpp>
4+
#include <rfl/json.hpp>
5+
#include <sqlgen.hpp>
6+
#include <sqlgen/duckdb.hpp>
7+
#include <vector>
8+
9+
#include "sqlgen/duckdb/to_sql.hpp"
10+
11+
namespace test_union {
12+
13+
struct User1 {
14+
std::string name;
15+
int age;
16+
};
17+
18+
struct User2 {
19+
std::string name;
20+
int age;
21+
};
22+
23+
struct User3 {
24+
int age;
25+
std::string name;
26+
};
27+
28+
TEST(duckdb, test_union) {
29+
using namespace sqlgen::literals;
30+
31+
const auto conn = sqlgen::duckdb::connect();
32+
33+
const auto user1 = User1{.name = "John", .age = 30};
34+
sqlgen::write(conn, user1);
35+
36+
const auto user2 = User2{.name = "Jane", .age = 25};
37+
sqlgen::write(conn, user2);
38+
39+
const auto user3 = User3{.age = 40, .name = "Joe"};
40+
sqlgen::write(conn, user3);
41+
42+
const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
43+
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);
44+
const auto s3 = sqlgen::select_from<User3>("name"_c, "age"_c);
45+
46+
const auto result = sqlgen::unite<std::vector<User1>>(s1, s2, s3)(conn);
47+
48+
const auto users = result.value();
49+
50+
const auto query =
51+
sqlgen::duckdb::to_sql(sqlgen::unite<std::vector<User1>>(s1, s2, s3));
52+
53+
EXPECT_EQ(
54+
query,
55+
R"(SELECT "name", "age" FROM (SELECT "name", "age" FROM "User1") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User2") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User3"))");
56+
57+
EXPECT_EQ(users.size(), 3);
58+
EXPECT_EQ(users.at(0).name, "Joe");
59+
EXPECT_EQ(users.at(0).age, 40);
60+
EXPECT_EQ(users.at(1).name, "Jane");
61+
EXPECT_EQ(users.at(1).age, 25);
62+
EXPECT_EQ(users.at(2).name, "John");
63+
EXPECT_EQ(users.at(2).age, 30);
64+
}
65+
66+
} // namespace test_union

tests/duckdb/test_union_all.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <rfl.hpp>
4+
#include <rfl/json.hpp>
5+
#include <sqlgen.hpp>
6+
#include <sqlgen/duckdb.hpp>
7+
#include <vector>
8+
9+
#include "sqlgen/duckdb/to_sql.hpp"
10+
11+
namespace test_union_all {
12+
13+
struct User1 {
14+
std::string name;
15+
int age;
16+
};
17+
18+
struct User2 {
19+
std::string name;
20+
int age;
21+
};
22+
23+
struct User3 {
24+
int age;
25+
std::string name;
26+
};
27+
28+
TEST(duckdb, test_union_all) {
29+
using namespace sqlgen::literals;
30+
31+
const auto conn = sqlgen::duckdb::connect();
32+
33+
const auto user1 = User1{.name = "John", .age = 30};
34+
sqlgen::write(conn, user1);
35+
36+
const auto user2 = User2{.name = "Jane", .age = 25};
37+
sqlgen::write(conn, user2);
38+
39+
const auto user3 = User3{.age = 30, .name = "John"};
40+
sqlgen::write(conn, user3);
41+
42+
const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
43+
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);
44+
const auto s3 = sqlgen::select_from<User3>("name"_c, "age"_c);
45+
46+
const auto result = sqlgen::unite_all<std::vector<User1>>(s1, s2, s3)(conn);
47+
48+
const auto users = result.value();
49+
50+
const auto query =
51+
sqlgen::duckdb::to_sql(sqlgen::unite_all<std::vector<User1>>(s1, s2, s3));
52+
53+
EXPECT_EQ(
54+
query,
55+
R"(SELECT "name", "age" FROM (SELECT "name", "age" FROM "User1") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User2") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User3"))");
56+
57+
EXPECT_EQ(users.size(), 3);
58+
EXPECT_EQ(users.at(0).name, "John");
59+
EXPECT_EQ(users.at(0).age, 30);
60+
EXPECT_EQ(users.at(1).name, "Jane");
61+
EXPECT_EQ(users.at(1).age, 25);
62+
EXPECT_EQ(users.at(2).name, "John");
63+
EXPECT_EQ(users.at(2).age, 30);
64+
}
65+
66+
} // namespace test_union_all
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <rfl.hpp>
4+
#include <rfl/json.hpp>
5+
#include <sqlgen.hpp>
6+
#include <sqlgen/duckdb.hpp>
7+
#include <vector>
8+
9+
#include "sqlgen/duckdb/to_sql.hpp"
10+
11+
namespace test_union_in_join {
12+
13+
struct User1 {
14+
std::string name;
15+
int age;
16+
};
17+
18+
struct User2 {
19+
std::string name;
20+
int age;
21+
};
22+
23+
struct User3 {
24+
int age;
25+
std::string name;
26+
};
27+
28+
struct Login {
29+
int id;
30+
std::string username;
31+
};
32+
33+
TEST(duckdb, test_union_in_join) {
34+
using namespace sqlgen;
35+
using namespace sqlgen::literals;
36+
37+
const auto conn = sqlgen::duckdb::connect();
38+
39+
const auto user1 = User1{.name = "John", .age = 30};
40+
sqlgen::write(conn, user1);
41+
42+
const auto user2 = User2{.name = "Jane", .age = 25};
43+
sqlgen::write(conn, user2);
44+
45+
const auto user3 = User3{.age = 40, .name = "Joe"};
46+
sqlgen::write(conn, user3);
47+
48+
const auto login = Login{.id = 1, .username = "John"};
49+
sqlgen::write(conn, login);
50+
51+
const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
52+
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);
53+
const auto s3 = sqlgen::select_from<User3>("name"_c, "age"_c);
54+
55+
const auto united = sqlgen::unite<std::vector<User1>>(s1, s2, s3);
56+
57+
const auto sel = select_from<Login, "t1">("id"_t1, "username"_t1) |
58+
inner_join<"t2">(united, "username"_t1 == "name"_t2) |
59+
where("id"_t1 == 1) | to<std::vector<Login>>;
60+
61+
const auto query = sqlgen::duckdb::to_sql(sel);
62+
63+
const auto result = sel(conn);
64+
65+
const auto users = result.value();
66+
67+
EXPECT_EQ(
68+
query,
69+
R"(SELECT t1."id", t1."username" FROM "Login" t1 INNER JOIN (SELECT "name", "age" FROM (SELECT "name", "age" FROM "User1") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User2") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User3")) t2 ON t1."username" = t2."name" WHERE t1."id" = 1)");
70+
71+
EXPECT_EQ(users.size(), 1);
72+
EXPECT_EQ(users.at(0).id, 1);
73+
EXPECT_EQ(users.at(0).username, "John");
74+
}
75+
76+
} // namespace test_union_in_join
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <rfl.hpp>
4+
#include <rfl/json.hpp>
5+
#include <sqlgen.hpp>
6+
#include <sqlgen/duckdb.hpp>
7+
#include <vector>
8+
9+
#include "sqlgen/duckdb/to_sql.hpp"
10+
11+
namespace test_union_in_join2 {
12+
13+
struct User1 {
14+
std::string name;
15+
int age;
16+
};
17+
18+
struct User2 {
19+
std::string name;
20+
int age;
21+
};
22+
23+
struct User3 {
24+
int age;
25+
std::string name;
26+
};
27+
28+
struct Login {
29+
int id;
30+
std::string username;
31+
};
32+
33+
TEST(duckdb, test_union_in_join2) {
34+
using namespace sqlgen;
35+
using namespace sqlgen::literals;
36+
37+
const auto conn = sqlgen::duckdb::connect();
38+
39+
const auto user1 = User1{.name = "John", .age = 30};
40+
sqlgen::write(conn, user1);
41+
42+
const auto user2 = User2{.name = "Jane", .age = 25};
43+
sqlgen::write(conn, user2);
44+
45+
const auto user3 = User3{.age = 40, .name = "Joe"};
46+
sqlgen::write(conn, user3);
47+
48+
const auto login = Login{.id = 1, .username = "John"};
49+
sqlgen::write(conn, login);
50+
51+
const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
52+
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);
53+
const auto s3 = sqlgen::select_from<User3>("name"_c, "age"_c);
54+
55+
const auto united = sqlgen::unite<std::vector<User1>>(s1, s2, s3);
56+
57+
const auto sel = select_from<"t1">(united, "id"_t2, "username"_t2) |
58+
inner_join<Login, "t2">("username"_t2 == "name"_t1) |
59+
where("id"_t2 == 1) | to<std::vector<Login>>;
60+
61+
const auto query = sqlgen::duckdb::to_sql(sel);
62+
63+
const auto result = sel(conn);
64+
65+
const auto users = result.value();
66+
67+
EXPECT_EQ(
68+
query,
69+
R"(SELECT t2."id", t2."username" FROM (SELECT "name", "age" FROM (SELECT "name", "age" FROM "User1") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User2") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User3")) t1 INNER JOIN "Login" t2 ON t2."username" = t1."name" WHERE t2."id" = 1)");
70+
71+
EXPECT_EQ(users.size(), 1);
72+
EXPECT_EQ(users.at(0).id, 1);
73+
EXPECT_EQ(users.at(0).username, "John");
74+
}
75+
76+
} // namespace test_union_in_join2
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include <gtest/gtest.h>
2+
3+
#include <rfl.hpp>
4+
#include <rfl/json.hpp>
5+
#include <sqlgen.hpp>
6+
#include <sqlgen/duckdb.hpp>
7+
#include <vector>
8+
9+
#include "sqlgen/duckdb/to_sql.hpp"
10+
11+
namespace test_union_in_select {
12+
13+
struct User1 {
14+
std::string name;
15+
int age;
16+
};
17+
18+
struct User2 {
19+
std::string name;
20+
int age;
21+
};
22+
23+
struct User3 {
24+
int age;
25+
std::string name;
26+
};
27+
28+
TEST(duckdb, test_union_in_select) {
29+
using namespace sqlgen::literals;
30+
31+
const auto conn = sqlgen::duckdb::connect();
32+
33+
const auto user1 = User1{.name = "John", .age = 30};
34+
sqlgen::write(conn, user1);
35+
36+
const auto user2 = User2{.name = "Jane", .age = 25};
37+
sqlgen::write(conn, user2);
38+
39+
const auto user3 = User3{.age = 40, .name = "Joe"};
40+
sqlgen::write(conn, user3);
41+
42+
const auto s1 = sqlgen::select_from<User1>("name"_c, "age"_c);
43+
const auto s2 = sqlgen::select_from<User2>("name"_c, "age"_c);
44+
const auto s3 = sqlgen::select_from<User3>("name"_c, "age"_c);
45+
46+
const auto united = sqlgen::unite<std::vector<User1>>(s1, s2, s3);
47+
48+
const auto sel = sqlgen::select_from(united, "name"_c, "age"_c) |
49+
sqlgen::to<std::vector<User1>>;
50+
51+
const auto result = sel(conn);
52+
53+
const auto users = result.value();
54+
55+
const auto query = sqlgen::duckdb::to_sql(sel);
56+
57+
EXPECT_EQ(
58+
query,
59+
R"(SELECT "name", "age" FROM (SELECT "name", "age" FROM (SELECT "name", "age" FROM "User1") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User2") UNION SELECT "name", "age" FROM (SELECT "name", "age" FROM "User3")))");
60+
61+
EXPECT_EQ(users.size(), 3);
62+
EXPECT_EQ(users.at(0).name, "Jane");
63+
EXPECT_EQ(users.at(0).age, 25);
64+
EXPECT_EQ(users.at(1).name, "Joe");
65+
EXPECT_EQ(users.at(1).age, 40);
66+
EXPECT_EQ(users.at(2).name, "John");
67+
EXPECT_EQ(users.at(2).age, 30);
68+
}
69+
70+
} // namespace test_union_in_select

0 commit comments

Comments
 (0)