mirror of
https://github.com/getml/sqlgen.git
synced 2026-01-04 16:40:07 -06:00
committed by
GitHub
parent
8649e41861
commit
45c1a52177
51
docs/col.md
51
docs/col.md
@@ -113,6 +113,57 @@ FROM "Person"
|
||||
WHERE "first_name" NOT LIKE 'H%';
|
||||
```
|
||||
|
||||
#### IN and NOT IN Operations
|
||||
|
||||
Use IN and NOT IN to check if a column value matches any value in a list:
|
||||
|
||||
```cpp
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
// Find people with specific first names (variadic arguments)
|
||||
const auto query1 = read<std::vector<Person>> |
|
||||
where("first_name"_c.in("Bart", "Lisa", "Maggie"));
|
||||
|
||||
// Find people NOT with specific first names (variadic arguments)
|
||||
const auto query2 = read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in("Homer", "Hugo"));
|
||||
|
||||
// Find people with specific first names (using vector)
|
||||
const auto names = std::vector<std::string>({"Bart", "Lisa", "Maggie"});
|
||||
const auto query3 = read<std::vector<Person>> |
|
||||
where("first_name"_c.in(names));
|
||||
|
||||
// Find people NOT with specific first names (using vector)
|
||||
const auto excluded_names = std::vector<std::string>({"Homer", "Hugo"});
|
||||
const auto query4 = read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in(excluded_names));
|
||||
```
|
||||
|
||||
This generates SQL like:
|
||||
|
||||
```sql
|
||||
-- For query1
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE "first_name" IN ('Bart', 'Lisa', 'Maggie');
|
||||
|
||||
-- For query2
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE "first_name" NOT IN ('Homer', 'Hugo');
|
||||
|
||||
-- For query3
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE "first_name" IN ('Bart', 'Lisa', 'Maggie');
|
||||
|
||||
-- For query4
|
||||
SELECT "id", "first_name", "last_name", "age"
|
||||
FROM "Person"
|
||||
WHERE "first_name" NOT IN ('Homer', 'Hugo');
|
||||
```
|
||||
|
||||
#### Ordering
|
||||
|
||||
Specify column ordering in queries:
|
||||
|
||||
@@ -40,6 +40,13 @@ struct Col {
|
||||
/// Returns the column name.
|
||||
std::string name() const noexcept { return Name().str(); }
|
||||
|
||||
/// Returns an IN condition.
|
||||
template <class... Ts>
|
||||
auto in(const Ts&... _ts) const noexcept {
|
||||
return transpilation::make_condition(transpilation::conditions::in(
|
||||
transpilation::Col<_name, _alias>{}, _ts...));
|
||||
}
|
||||
|
||||
/// Returns an IS NULL condition.
|
||||
auto is_null() const noexcept {
|
||||
return transpilation::make_condition(transpilation::conditions::is_null(
|
||||
@@ -64,6 +71,13 @@ struct Col {
|
||||
transpilation::Col<_name, _alias>{}, _pattern));
|
||||
}
|
||||
|
||||
/// Returns a NOT IN condition.
|
||||
template <class... Ts>
|
||||
auto not_in(const Ts&... _ts) const noexcept {
|
||||
return transpilation::make_condition(transpilation::conditions::not_in(
|
||||
transpilation::Col<_name, _alias>{}, _ts...));
|
||||
}
|
||||
|
||||
/// Returns a SET clause in an UPDATE statement.
|
||||
template <class T>
|
||||
auto set(const T& _to) const noexcept {
|
||||
|
||||
@@ -31,6 +31,11 @@ struct Condition {
|
||||
Operation op2;
|
||||
};
|
||||
|
||||
struct In {
|
||||
Operation op;
|
||||
std::vector<dynamic::Value> patterns;
|
||||
};
|
||||
|
||||
struct IsNotNull {
|
||||
Operation op;
|
||||
};
|
||||
@@ -68,15 +73,20 @@ struct Condition {
|
||||
dynamic::Value pattern;
|
||||
};
|
||||
|
||||
struct NotIn {
|
||||
Operation op;
|
||||
std::vector<dynamic::Value> patterns;
|
||||
};
|
||||
|
||||
struct Or {
|
||||
Ref<Condition> cond1;
|
||||
Ref<Condition> cond2;
|
||||
};
|
||||
|
||||
using ReflectionType =
|
||||
rfl::TaggedUnion<"what", And, Equal, GreaterEqual, GreaterThan, IsNull,
|
||||
IsNotNull, LesserEqual, LesserThan, Like, Not, NotEqual,
|
||||
NotLike, Or>;
|
||||
rfl::TaggedUnion<"what", And, Equal, GreaterEqual, GreaterThan, In,
|
||||
IsNull, IsNotNull, LesserEqual, LesserThan, Like, Not,
|
||||
NotEqual, NotIn, NotLike, Or>;
|
||||
|
||||
const ReflectionType& reflection() const { return val; }
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef SQLGEN_TRANSPILATION_CONDITIONS_HPP_
|
||||
#define SQLGEN_TRANSPILATION_CONDITIONS_HPP_
|
||||
|
||||
#include <rfl.hpp>
|
||||
|
||||
#include "string_t.hpp"
|
||||
|
||||
namespace sqlgen::transpilation::conditions {
|
||||
|
||||
template <class CondType1, class CondType2>
|
||||
@@ -53,6 +57,33 @@ auto greater_than(const OpType1& _op1, const OpType2& _op2) {
|
||||
std::remove_cvref_t<OpType2>>{.op1 = _op1, .op2 = _op2};
|
||||
}
|
||||
|
||||
template <class OpType, class... Ts>
|
||||
struct In {
|
||||
using ResultType = bool;
|
||||
|
||||
OpType op;
|
||||
rfl::Tuple<Ts...> patterns;
|
||||
};
|
||||
|
||||
template <class OpType, class... Ts>
|
||||
auto in(const OpType& _op, const Ts&... _ts) {
|
||||
return In<OpType, string_t<Ts>...>{
|
||||
.op = _op, .patterns = rfl::Tuple<string_t<Ts>...>(_ts...)};
|
||||
}
|
||||
|
||||
template <class OpType, class T>
|
||||
struct InVec {
|
||||
using ResultType = bool;
|
||||
|
||||
OpType op;
|
||||
std::vector<T> patterns;
|
||||
};
|
||||
|
||||
template <class OpType, class T>
|
||||
auto in(const OpType& _op, const std::vector<T>& _patterns) {
|
||||
return InVec<OpType, T>{.op = _op, .patterns = _patterns};
|
||||
}
|
||||
|
||||
template <class OpType>
|
||||
struct IsNull {
|
||||
using ResultType = bool;
|
||||
@@ -139,6 +170,33 @@ auto not_equal(const OpType1& _op1, const OpType2& _op2) {
|
||||
.op1 = _op1, .op2 = _op2};
|
||||
}
|
||||
|
||||
template <class OpType, class... Ts>
|
||||
struct NotIn {
|
||||
using ResultType = bool;
|
||||
|
||||
OpType op;
|
||||
rfl::Tuple<Ts...> patterns;
|
||||
};
|
||||
|
||||
template <class OpType, class... Ts>
|
||||
auto not_in(const OpType& _op, const Ts&... _ts) {
|
||||
return NotIn<OpType, string_t<Ts>...>{
|
||||
.op = _op, .patterns = rfl::Tuple<string_t<Ts>...>(_ts...)};
|
||||
}
|
||||
|
||||
template <class OpType, class T>
|
||||
struct NotInVec {
|
||||
using ResultType = bool;
|
||||
|
||||
OpType op;
|
||||
std::vector<T> patterns;
|
||||
};
|
||||
|
||||
template <class OpType, class T>
|
||||
auto not_in(const OpType& _op, const std::vector<T>& _patterns) {
|
||||
return NotInVec<OpType, T>{.op = _op, .patterns = _patterns};
|
||||
}
|
||||
|
||||
template <class OpType>
|
||||
struct NotLike {
|
||||
using ResultType = bool;
|
||||
|
||||
28
include/sqlgen/transpilation/string_t.hpp
Normal file
28
include/sqlgen/transpilation/string_t.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef SQLGEN_TRANSPILATION_STRINGT_HPP_
|
||||
#define SQLGEN_TRANSPILATION_STRINGT_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace sqlgen::transpilation {
|
||||
|
||||
template <class T>
|
||||
struct StringType;
|
||||
|
||||
template <class T>
|
||||
struct StringType {
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
requires std::is_convertible_v<T, std::string>
|
||||
struct StringType<T> {
|
||||
using Type = std::string;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using string_t = typename StringType<std::remove_cvref_t<T>>::Type;
|
||||
|
||||
} // namespace sqlgen::transpilation
|
||||
|
||||
#endif
|
||||
@@ -3,17 +3,20 @@
|
||||
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "../Ref.hpp"
|
||||
#include "../Result.hpp"
|
||||
#include "../dynamic/Condition.hpp"
|
||||
#include "../internal/collect/vector.hpp"
|
||||
#include "Condition.hpp"
|
||||
#include "all_columns_exist.hpp"
|
||||
#include "conditions.hpp"
|
||||
#include "is_timestamp.hpp"
|
||||
#include "make_field.hpp"
|
||||
#include "remove_nullable_t.hpp"
|
||||
#include "to_transpilation_type.hpp"
|
||||
#include "underlying_t.hpp"
|
||||
|
||||
@@ -141,6 +144,47 @@ struct ToCondition<T, conditions::Like<OpType>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class OpType, class... PatternTypes>
|
||||
struct ToCondition<T, conditions::In<OpType, PatternTypes...>> {
|
||||
using UnderlyingT = remove_nullable_t<underlying_t<T, OpType>>;
|
||||
|
||||
static constexpr bool is_equality_comparable =
|
||||
(true && ... && std::equality_comparable_with<UnderlyingT, PatternTypes>);
|
||||
|
||||
static_assert(is_equality_comparable, "Must be equality comparable.");
|
||||
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
return dynamic::Condition{
|
||||
.val = dynamic::Condition::In{.op = make_field<T>(_cond.op).val,
|
||||
.patterns = rfl::apply(
|
||||
[](const auto&... _p) {
|
||||
return std::vector<dynamic::Value>(
|
||||
{to_value(_p)...});
|
||||
},
|
||||
_cond.patterns)}};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class OpType, class PatternType>
|
||||
struct ToCondition<T, conditions::InVec<OpType, PatternType>> {
|
||||
using UnderlyingT = remove_nullable_t<underlying_t<T, OpType>>;
|
||||
|
||||
static constexpr bool is_equality_comparable =
|
||||
std::equality_comparable_with<UnderlyingT, PatternType>;
|
||||
|
||||
static_assert(is_equality_comparable, "Must be equality comparable.");
|
||||
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
using namespace std::ranges::views;
|
||||
return dynamic::Condition{
|
||||
.val = dynamic::Condition::In{
|
||||
.op = make_field<T>(_cond.op).val,
|
||||
.patterns = sqlgen::internal::collect::vector(
|
||||
_cond.patterns |
|
||||
transform([](const auto& _v) { return to_value(_v); }))}};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class OpType>
|
||||
struct ToCondition<T, conditions::IsNotNull<OpType>> {
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
@@ -198,6 +242,47 @@ struct ToCondition<T, conditions::NotLike<OpType>> {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class OpType, class... PatternTypes>
|
||||
struct ToCondition<T, conditions::NotIn<OpType, PatternTypes...>> {
|
||||
using UnderlyingT = remove_nullable_t<underlying_t<T, OpType>>;
|
||||
|
||||
static constexpr bool is_equality_comparable =
|
||||
(true && ... && std::equality_comparable_with<UnderlyingT, PatternTypes>);
|
||||
|
||||
static_assert(is_equality_comparable, "Must be equality comparable.");
|
||||
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
return dynamic::Condition{.val = dynamic::Condition::NotIn{
|
||||
.op = make_field<T>(_cond.op).val,
|
||||
.patterns = rfl::apply(
|
||||
[](const auto&... _p) {
|
||||
return std::vector<dynamic::Value>(
|
||||
{to_value(_p)...});
|
||||
},
|
||||
_cond.patterns)}};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class OpType, class PatternType>
|
||||
struct ToCondition<T, conditions::NotInVec<OpType, PatternType>> {
|
||||
using UnderlyingT = remove_nullable_t<underlying_t<T, OpType>>;
|
||||
|
||||
static constexpr bool is_equality_comparable =
|
||||
std::equality_comparable_with<UnderlyingT, PatternType>;
|
||||
|
||||
static_assert(is_equality_comparable, "Must be equality comparable.");
|
||||
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
using namespace std::ranges::views;
|
||||
return dynamic::Condition{
|
||||
.val = dynamic::Condition::NotIn{
|
||||
.op = make_field<T>(_cond.op).val,
|
||||
.patterns = sqlgen::internal::collect::vector(
|
||||
_cond.patterns |
|
||||
transform([](const auto& _v) { return to_value(_v); }))}};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class CondType1, class CondType2>
|
||||
struct ToCondition<T, conditions::Or<CondType1, CondType2>> {
|
||||
dynamic::Condition operator()(const auto& _cond) const {
|
||||
|
||||
@@ -209,6 +209,8 @@ std::string condition_to_sql(const dynamic::Condition& _cond) noexcept {
|
||||
|
||||
template <class ConditionType>
|
||||
std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
using namespace std::ranges::views;
|
||||
|
||||
using C = std::remove_cvref_t<ConditionType>;
|
||||
|
||||
std::stringstream stream;
|
||||
@@ -229,6 +231,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << operation_to_sql(_condition.op1) << " > "
|
||||
<< operation_to_sql(_condition.op2);
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::In>) {
|
||||
stream << operation_to_sql(_condition.op) << " IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::IsNull>) {
|
||||
stream << operation_to_sql(_condition.op) << " IS NULL";
|
||||
|
||||
@@ -262,6 +272,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << "(" << condition_to_sql(*_condition.cond1) << ") OR ("
|
||||
<< condition_to_sql(*_condition.cond2) << ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::NotIn>) {
|
||||
stream << operation_to_sql(_condition.op) << " NOT IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else {
|
||||
static_assert(rfl::always_false_v<C>, "Not all cases were covered.");
|
||||
}
|
||||
|
||||
@@ -161,6 +161,8 @@ std::string condition_to_sql(const dynamic::Condition& _cond) noexcept {
|
||||
|
||||
template <class ConditionType>
|
||||
std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
using namespace std::ranges::views;
|
||||
|
||||
using C = std::remove_cvref_t<ConditionType>;
|
||||
|
||||
std::stringstream stream;
|
||||
@@ -181,6 +183,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << operation_to_sql(_condition.op1) << " > "
|
||||
<< operation_to_sql(_condition.op2);
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::In>) {
|
||||
stream << operation_to_sql(_condition.op) << " IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::IsNull>) {
|
||||
stream << operation_to_sql(_condition.op) << " IS NULL";
|
||||
|
||||
@@ -210,6 +220,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << operation_to_sql(_condition.op) << " NOT LIKE "
|
||||
<< column_or_value_to_sql(_condition.pattern);
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::NotIn>) {
|
||||
stream << operation_to_sql(_condition.op) << " NOT IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::Or>) {
|
||||
stream << "(" << condition_to_sql(*_condition.cond1) << ") OR ("
|
||||
<< condition_to_sql(*_condition.cond2) << ")";
|
||||
|
||||
@@ -169,6 +169,8 @@ std::string condition_to_sql(const dynamic::Condition& _cond) noexcept {
|
||||
|
||||
template <class ConditionType>
|
||||
std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
using namespace std::ranges::views;
|
||||
|
||||
using C = std::remove_cvref_t<ConditionType>;
|
||||
|
||||
std::stringstream stream;
|
||||
@@ -189,6 +191,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << operation_to_sql(_condition.op1) << " > "
|
||||
<< operation_to_sql(_condition.op2);
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::In>) {
|
||||
stream << operation_to_sql(_condition.op) << " IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::IsNull>) {
|
||||
stream << operation_to_sql(_condition.op) << " IS NULL";
|
||||
|
||||
@@ -218,6 +228,14 @@ std::string condition_to_sql_impl(const ConditionType& _condition) noexcept {
|
||||
stream << operation_to_sql(_condition.op) << " NOT LIKE "
|
||||
<< column_or_value_to_sql(_condition.pattern);
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::NotIn>) {
|
||||
stream << operation_to_sql(_condition.op) << " NOT IN ("
|
||||
<< internal::strings::join(
|
||||
", ",
|
||||
internal::collect::vector(_condition.patterns |
|
||||
transform(column_or_value_to_sql)))
|
||||
<< ")";
|
||||
|
||||
} else if constexpr (std::is_same_v<C, dynamic::Condition::Or>) {
|
||||
stream << "(" << condition_to_sql(*_condition.cond1) << ") OR ("
|
||||
<< condition_to_sql(*_condition.cond2) << ")";
|
||||
|
||||
56
tests/mysql/test_in.cpp
Normal file
56
tests/mysql/test_in.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/mysql.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(mysql, test_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
|
||||
.user = "sqlgen",
|
||||
.password = "password",
|
||||
.dbname = "mysql"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
mysql::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in("Bart", "Lisa", "Maggie")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in
|
||||
|
||||
#endif
|
||||
57
tests/mysql/test_in_vec.cpp
Normal file
57
tests/mysql/test_in_vec.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/mysql.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(mysql, test_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
|
||||
.user = "sqlgen",
|
||||
.password = "password",
|
||||
.dbname = "mysql"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
mysql::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in(
|
||||
std::vector<std::string>({"Bart", "Lisa", "Maggie"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in_vec
|
||||
|
||||
#endif
|
||||
56
tests/mysql/test_not_in.cpp
Normal file
56
tests/mysql/test_not_in.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/mysql.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(mysql, test_not_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
|
||||
.user = "sqlgen",
|
||||
.password = "password",
|
||||
.dbname = "mysql"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
mysql::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in("Homer", "Hugo")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in
|
||||
|
||||
#endif
|
||||
57
tests/mysql/test_not_in_vec.cpp
Normal file
57
tests/mysql/test_not_in_vec.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/mysql.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(mysql, test_not_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::mysql::Credentials{.host = "localhost",
|
||||
.user = "sqlgen",
|
||||
.password = "password",
|
||||
.dbname = "mysql"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
mysql::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in(
|
||||
std::vector<std::string>({"Homer", "Hugo"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in_vec
|
||||
|
||||
#endif
|
||||
56
tests/postgres/test_in.cpp
Normal file
56
tests/postgres/test_in.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(postgres, test_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
|
||||
.password = "password",
|
||||
.host = "localhost",
|
||||
.dbname = "postgres"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
postgres::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in("Bart", "Lisa", "Maggie")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in
|
||||
|
||||
#endif
|
||||
57
tests/postgres/test_in_vec.cpp
Normal file
57
tests/postgres/test_in_vec.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(postgres, test_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
|
||||
.password = "password",
|
||||
.host = "localhost",
|
||||
.dbname = "postgres"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
postgres::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in(
|
||||
std::vector<std::string>({"Bart", "Lisa", "Maggie"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in_vec
|
||||
|
||||
#endif
|
||||
56
tests/postgres/test_not_in.cpp
Normal file
56
tests/postgres/test_not_in.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(postgres, test_not_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
|
||||
.password = "password",
|
||||
.host = "localhost",
|
||||
.dbname = "postgres"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
postgres::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in("Homer", "Hugo")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in
|
||||
|
||||
#endif
|
||||
57
tests/postgres/test_not_in_vec.cpp
Normal file
57
tests/postgres/test_not_in_vec.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef SQLGEN_BUILD_DRY_TESTS_ONLY
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/postgres.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(postgres, test_not_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
const auto credentials = sqlgen::postgres::Credentials{.user = "postgres",
|
||||
.password = "password",
|
||||
.host = "localhost",
|
||||
.dbname = "postgres"};
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
postgres::connect(credentials)
|
||||
.and_then(drop<Person> | if_exists)
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in(
|
||||
std::vector<std::string>({"Homer", "Hugo"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in_vec
|
||||
|
||||
#endif
|
||||
48
tests/sqlite/test_in.cpp
Normal file
48
tests/sqlite/test_in.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/sqlite.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(sqlite, test_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
sqlite::connect()
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in("Bart", "Lisa", "Maggie")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in
|
||||
|
||||
49
tests/sqlite/test_in_vec.cpp
Normal file
49
tests/sqlite/test_in_vec.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/sqlite.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(sqlite, test_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
sqlite::connect()
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.in(
|
||||
std::vector<std::string>({"Bart", "Lisa", "Maggie"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_in_vec
|
||||
|
||||
48
tests/sqlite/test_not_in.cpp
Normal file
48
tests/sqlite/test_not_in.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/sqlite.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(sqlite, test_not_in) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
sqlite::connect()
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in("Homer", "Hugo")) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in
|
||||
|
||||
49
tests/sqlite/test_not_in_vec.cpp
Normal file
49
tests/sqlite/test_not_in_vec.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rfl.hpp>
|
||||
#include <rfl/json.hpp>
|
||||
#include <sqlgen.hpp>
|
||||
#include <sqlgen/sqlite.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace test_not_in_vec {
|
||||
|
||||
struct Person {
|
||||
sqlgen::PrimaryKey<uint32_t> id;
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
int age;
|
||||
};
|
||||
|
||||
TEST(sqlite, test_not_in_vec) {
|
||||
const auto people1 = std::vector<Person>(
|
||||
{Person{
|
||||
.id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45},
|
||||
Person{.id = 1, .first_name = "Bart", .last_name = "Simpson", .age = 10},
|
||||
Person{.id = 2, .first_name = "Lisa", .last_name = "Simpson", .age = 8},
|
||||
Person{
|
||||
.id = 3, .first_name = "Maggie", .last_name = "Simpson", .age = 0},
|
||||
Person{
|
||||
.id = 4, .first_name = "Hugo", .last_name = "Simpson", .age = 10}});
|
||||
|
||||
using namespace sqlgen;
|
||||
using namespace sqlgen::literals;
|
||||
|
||||
const auto people2 =
|
||||
sqlite::connect()
|
||||
.and_then(write(std::ref(people1)))
|
||||
.and_then(sqlgen::read<std::vector<Person>> |
|
||||
where("first_name"_c.not_in(
|
||||
std::vector<std::string>({"Homer", "Hugo"}))) |
|
||||
order_by("age"_c))
|
||||
.value();
|
||||
|
||||
const std::string expected1 =
|
||||
R"([{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10}])";
|
||||
|
||||
EXPECT_EQ(rfl::json::write(people2), expected1);
|
||||
}
|
||||
|
||||
} // namespace test_not_in_vec
|
||||
|
||||
Reference in New Issue
Block a user