Skip to content

Commit 91e993f

Browse files
Make sure we can use boolean values in conditions; fixes #74 (#75)
1 parent 15108fb commit 91e993f

12 files changed

Lines changed: 404 additions & 6 deletions

File tree

include/sqlgen/dynamic/Condition.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <rfl.hpp>
55

66
#include "../Ref.hpp"
7-
#include "Column.hpp"
87
#include "ColumnOrValue.hpp"
98
#include "Operation.hpp"
109

@@ -16,6 +15,10 @@ struct Condition {
1615
Ref<Condition> cond2;
1716
};
1817

18+
struct BooleanColumnOrValue {
19+
ColumnOrValue col_or_val;
20+
};
21+
1922
struct Equal {
2023
Operation op1;
2124
Operation op2;
@@ -84,9 +87,9 @@ struct Condition {
8487
};
8588

8689
using ReflectionType =
87-
rfl::TaggedUnion<"what", And, Equal, GreaterEqual, GreaterThan, In,
88-
IsNull, IsNotNull, LesserEqual, LesserThan, Like, Not,
89-
NotEqual, NotIn, NotLike, Or>;
90+
rfl::TaggedUnion<"what", And, BooleanColumnOrValue, Equal, GreaterEqual,
91+
GreaterThan, In, IsNull, IsNotNull, LesserEqual,
92+
LesserThan, Like, Not, NotEqual, NotIn, NotLike, Or>;
9093

9194
const ReflectionType& reflection() const { return val; }
9295

include/sqlgen/dynamic/Value.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ struct Duration {
1313
int64_t val;
1414
};
1515

16+
struct Boolean {
17+
bool val;
18+
};
19+
1620
struct Float {
1721
double val;
1822
};
@@ -30,8 +34,8 @@ struct Timestamp {
3034
};
3135

3236
struct Value {
33-
using ReflectionType =
34-
rfl::TaggedUnion<"type", Duration, Float, Integer, String, Timestamp>;
37+
using ReflectionType = rfl::TaggedUnion<"type", Duration, Boolean, Float,
38+
Integer, String, Timestamp>;
3539
const auto& reflection() const { return val; }
3640
ReflectionType val;
3741
};

include/sqlgen/transpilation/to_value.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ struct ToValue {
2020
if constexpr (std::is_floating_point_v<Type>) {
2121
return dynamic::Value{dynamic::Float{.val = static_cast<double>(_t)}};
2222

23+
} else if constexpr (std::is_same_v<Type, bool>) {
24+
return dynamic::Value{dynamic::Boolean{.val = _t}};
25+
2326
} else if constexpr (std::is_integral_v<Type>) {
2427
return dynamic::Value{dynamic::Integer{.val = static_cast<int64_t>(_t)}};
2528

src/sqlgen/mysql/to_sql.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
219219
stream << "(" << condition_to_sql(*_condition.cond1) << ") AND ("
220220
<< condition_to_sql(*_condition.cond2) << ")";
221221

222+
} else if constexpr (std::is_same_v<
223+
C, dynamic::Condition::BooleanColumnOrValue>) {
224+
stream << column_or_value_to_sql(_condition.col_or_val);
225+
222226
} else if constexpr (std::is_same_v<C, dynamic::Condition::Equal>) {
223227
stream << operation_to_sql(_condition.op1) << " = "
224228
<< operation_to_sql(_condition.op2);

src/sqlgen/postgres/to_sql.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ std::string column_or_value_to_sql(
135135
} else if constexpr (std::is_same_v<Type, dynamic::Timestamp>) {
136136
return "to_timestamp(" + std::to_string(_v.seconds_since_unix) + ")";
137137

138+
} else if constexpr (std::is_same_v<Type, dynamic::Boolean>) {
139+
return _v.val ? "TRUE" : "FALSE";
140+
138141
} else {
139142
return std::to_string(_v.val);
140143
}
@@ -171,6 +174,10 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
171174
stream << "(" << condition_to_sql(*_condition.cond1) << ") AND ("
172175
<< condition_to_sql(*_condition.cond2) << ")";
173176

177+
} else if constexpr (std::is_same_v<
178+
C, dynamic::Condition::BooleanColumnOrValue>) {
179+
stream << column_or_value_to_sql(_condition.col_or_val);
180+
174181
} else if constexpr (std::is_same_v<C, dynamic::Condition::Equal>) {
175182
stream << operation_to_sql(_condition.op1) << " = "
176183
<< operation_to_sql(_condition.op2);

src/sqlgen/sqlite/to_sql.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
179179
stream << "(" << condition_to_sql(*_condition.cond1) << ") AND ("
180180
<< condition_to_sql(*_condition.cond2) << ")";
181181

182+
} else if constexpr (std::is_same_v<
183+
C, dynamic::Condition::BooleanColumnOrValue>) {
184+
stream << column_or_value_to_sql(_condition.col_or_val);
185+
182186
} else if constexpr (std::is_same_v<C, dynamic::Condition::Equal>) {
183187
stream << operation_to_sql(_condition.op1) << " = "
184188
<< operation_to_sql(_condition.op2);
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <rfl.hpp>
6+
#include <rfl/json.hpp>
7+
#include <sqlgen.hpp>
8+
#include <sqlgen/mysql.hpp>
9+
#include <vector>
10+
11+
namespace test_boolean_conditions {
12+
13+
struct Person {
14+
sqlgen::PrimaryKey<uint32_t> id;
15+
std::string first_name;
16+
std::string last_name;
17+
bool has_children;
18+
};
19+
20+
TEST(mysql, test_boolean_conditions) {
21+
const auto people1 = std::vector<Person>({Person{.id = 0,
22+
.first_name = "Homer",
23+
.last_name = "Simpson",
24+
.has_children = true},
25+
Person{.id = 1,
26+
.first_name = "Bart",
27+
.last_name = "Simpson",
28+
.has_children = false},
29+
Person{.id = 2,
30+
.first_name = "Lisa",
31+
.last_name = "Simpson",
32+
.has_children = false},
33+
Person{.id = 3,
34+
.first_name = "Maggie",
35+
.last_name = "Simpson",
36+
.has_children = false}});
37+
38+
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
39+
.user = "sqlgen",
40+
.password = "password",
41+
.dbname = "mysql"};
42+
43+
using namespace sqlgen;
44+
using namespace sqlgen::literals;
45+
46+
const auto conn =
47+
mysql::connect(credentials).and_then(drop<Person> | if_exists);
48+
49+
const auto homer =
50+
sqlgen::write(conn, people1)
51+
.and_then(sqlgen::read<Person> | where("has_children"_c == true) |
52+
order_by("id"_c))
53+
.value();
54+
55+
const auto json1 = rfl::json::write(people1.at(0));
56+
const auto json2 = rfl::json::write(homer);
57+
58+
EXPECT_EQ(json1, json2);
59+
}
60+
61+
} // namespace test_boolean_conditions
62+
63+
#endif
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <rfl.hpp>
6+
#include <rfl/json.hpp>
7+
#include <sqlgen.hpp>
8+
#include <sqlgen/mysql.hpp>
9+
#include <vector>
10+
11+
namespace test_boolean_update {
12+
13+
struct Person {
14+
sqlgen::PrimaryKey<uint32_t> id;
15+
std::string first_name;
16+
std::string last_name;
17+
bool has_children;
18+
};
19+
20+
TEST(mysql, test_boolean_update) {
21+
auto people1 = std::vector<Person>({Person{.id = 0,
22+
.first_name = "Homer",
23+
.last_name = "Simpson",
24+
.has_children = true},
25+
Person{.id = 1,
26+
.first_name = "Bart",
27+
.last_name = "Simpson",
28+
.has_children = false},
29+
Person{.id = 2,
30+
.first_name = "Lisa",
31+
.last_name = "Simpson",
32+
.has_children = false},
33+
Person{.id = 3,
34+
.first_name = "Maggie",
35+
.last_name = "Simpson",
36+
.has_children = false}});
37+
38+
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
39+
.user = "sqlgen",
40+
.password = "password",
41+
.dbname = "mysql"};
42+
43+
using namespace sqlgen;
44+
using namespace sqlgen::literals;
45+
46+
const auto conn =
47+
mysql::connect(credentials).and_then(drop<Person> | if_exists);
48+
49+
const auto people2 =
50+
sqlgen::write(conn, people1)
51+
.and_then(update<Person>("has_children"_c.set(false)) |
52+
where("has_children"_c == true))
53+
.and_then(sqlgen::read<std::vector<Person>> |
54+
where("has_children"_c == false) | order_by("id"_c))
55+
.value();
56+
57+
people1.at(0).has_children = false;
58+
59+
const auto json1 = rfl::json::write(people1);
60+
const auto json2 = rfl::json::write(people2);
61+
62+
EXPECT_EQ(json1, json2);
63+
}
64+
65+
} // namespace test_boolean_update
66+
67+
#endif
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <rfl.hpp>
6+
#include <rfl/json.hpp>
7+
#include <sqlgen.hpp>
8+
#include <sqlgen/postgres.hpp>
9+
#include <vector>
10+
11+
namespace test_boolean_conditions {
12+
13+
struct Person {
14+
sqlgen::PrimaryKey<uint32_t> id;
15+
std::string first_name;
16+
std::string last_name;
17+
bool has_children;
18+
};
19+
20+
TEST(postgres, test_boolean_conditions) {
21+
const auto people1 = std::vector<Person>({Person{.id = 0,
22+
.first_name = "Homer",
23+
.last_name = "Simpson",
24+
.has_children = true},
25+
Person{.id = 1,
26+
.first_name = "Bart",
27+
.last_name = "Simpson",
28+
.has_children = false},
29+
Person{.id = 2,
30+
.first_name = "Lisa",
31+
.last_name = "Simpson",
32+
.has_children = false},
33+
Person{.id = 3,
34+
.first_name = "Maggie",
35+
.last_name = "Simpson",
36+
.has_children = false}});
37+
38+
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
39+
.password = "password",
40+
.host = "localhost",
41+
.dbname = "postgres"};
42+
43+
using namespace sqlgen;
44+
using namespace sqlgen::literals;
45+
46+
const auto conn =
47+
postgres::connect(credentials).and_then(drop<Person> | if_exists);
48+
49+
const auto homer =
50+
sqlgen::write(conn, people1)
51+
.and_then(sqlgen::read<Person> | where("has_children"_c == true) |
52+
order_by("id"_c))
53+
.value();
54+
55+
const auto json1 = rfl::json::write(people1.at(0));
56+
const auto json2 = rfl::json::write(homer);
57+
58+
EXPECT_EQ(json1, json2);
59+
}
60+
61+
} // namespace test_boolean_conditions
62+
63+
#endif
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
2+
3+
#include <gtest/gtest.h>
4+
5+
#include <rfl.hpp>
6+
#include <rfl/json.hpp>
7+
#include <sqlgen.hpp>
8+
#include <sqlgen/postgres.hpp>
9+
#include <vector>
10+
11+
namespace test_boolean_update {
12+
13+
struct Person {
14+
sqlgen::PrimaryKey<uint32_t> id;
15+
std::string first_name;
16+
std::string last_name;
17+
bool has_children;
18+
};
19+
20+
TEST(postgres, test_boolean_update) {
21+
auto people1 = std::vector<Person>({Person{.id = 0,
22+
.first_name = "Homer",
23+
.last_name = "Simpson",
24+
.has_children = true},
25+
Person{.id = 1,
26+
.first_name = "Bart",
27+
.last_name = "Simpson",
28+
.has_children = false},
29+
Person{.id = 2,
30+
.first_name = "Lisa",
31+
.last_name = "Simpson",
32+
.has_children = false},
33+
Person{.id = 3,
34+
.first_name = "Maggie",
35+
.last_name = "Simpson",
36+
.has_children = false}});
37+
38+
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
39+
.password = "password",
40+
.host = "localhost",
41+
.dbname = "postgres"};
42+
43+
using namespace sqlgen;
44+
using namespace sqlgen::literals;
45+
46+
const auto conn =
47+
postgres::connect(credentials).and_then(drop<Person> | if_exists);
48+
49+
const auto people2 =
50+
sqlgen::write(conn, people1)
51+
.and_then(update<Person>("has_children"_c.set(false)) |
52+
where("has_children"_c == true))
53+
.and_then(sqlgen::read<std::vector<Person>> |
54+
where("has_children"_c == false) | order_by("id"_c))
55+
.value();
56+
57+
people1.at(0).has_children = false;
58+
59+
const auto json1 = rfl::json::write(people1);
60+
const auto json2 = rfl::json::write(people2);
61+
62+
EXPECT_EQ(json1, json2);
63+
}
64+
65+
} // namespace test_boolean_update
66+
67+
#endif

0 commit comments

Comments
 (0)