Last active
April 8, 2024 21:46
-
-
Save varqox/db3999feac551913596e299f5d3dd78b to your computer and use it in GitHub Desktop.
Constructing SQL queries in compile time
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
// #include <simlib/meta/concated_to_cstr.hh> | |
#include <array> | |
#include <cstddef> | |
#include <utility> | |
namespace meta { | |
template <char... chars> | |
constexpr inline char static_chars[] = {chars...}; | |
template <class Func, size_t... I> | |
constexpr const char* | |
char_array_to_static_chars(Func func, std::index_sequence<I...> /**/) noexcept { | |
constexpr auto arr = func(); | |
return static_chars<arr[I]...>; | |
} | |
constexpr inline size_t cstr_length(const char* str) noexcept { | |
auto orig_str = str; | |
while (*str) { | |
++str; | |
} | |
return str - orig_str; | |
} | |
template <const char*... str> | |
constexpr inline auto concated_to_cstr = [] { | |
constexpr auto lam = [] { | |
std::array<char, (cstr_length(str) + ... + 1)> res{}; | |
size_t idx = 0; | |
[[maybe_unused]] auto append = [&res, &idx](const char* s) { | |
while (*s) { | |
res[idx++] = *s++; | |
} | |
}; | |
(append(str), ...); | |
res[idx] = '\0'; | |
return res; | |
}; | |
return char_array_to_static_chars( | |
lam, std::make_index_sequence<(cstr_length(str) + ... + 1)>{} | |
); | |
}(); | |
} // namespace meta | |
// #include <simlib/meta/count.hh> | |
#include <cstddef> | |
namespace meta { | |
template <class T, class E> | |
constexpr size_t count(const T& container, const E& elem) noexcept { | |
size_t res = 0; | |
for (const auto& x : container) { | |
res += x == elem; | |
} | |
return res; | |
} | |
constexpr size_t count(const char* str, char c) noexcept { | |
size_t res = 0; | |
while (*str) { | |
res += *str == c; | |
++str; | |
} | |
return res; | |
} | |
} // namespace meta | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
namespace sim::sqlv2 { | |
template <class ParamsTuple, const char*... sqls> | |
struct SqlWithParams { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
static constexpr const char* sql = meta::concated_to_cstr<sqls...>; | |
template <std::enable_if_t<(sizeof...(sqls) > 0), int> = 0> | |
explicit SqlWithParams(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define SQL_WITH_PARAMS(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = sql_str; \ | |
return ::sim::sqlv2::SqlWithParams<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template <class ParamsTuple, const char* sql> | |
struct Select { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == meta::count(sql, '?')); | |
explicit Select(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define SELECT(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = "SELECT " sql_str; \ | |
return ::sim::sqlv2::Select<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template <const char* sql> | |
struct From { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit From() noexcept = default; | |
}; | |
#define FROM(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "FROM " sql_str; \ | |
return ::sim::sqlv2::From<str>{}; \ | |
}() | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectFrom { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectFrom(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectFrom<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <class SelectParamsTuple, const char* select_sql, const char* from_str> | |
auto operator+(Select<SelectParamsTuple, select_sql>&& select, From<from_str>&& /**/) noexcept { | |
static constexpr char space[] = " "; | |
return SelectFrom<SelectParamsTuple, select_sql, space, from_str>{std::move(select).params}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct Condition { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit Condition(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define CONDITION(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = sql_str; \ | |
return ::sim::sqlv2::Condition<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template < | |
class Cond1ParamsTuple, | |
const char*... cond1_sqls, | |
class Cond2ParamsTuple, | |
const char*... cond2_sqls> | |
auto operator&&( | |
Condition<Cond1ParamsTuple, cond1_sqls...>&& cond1, | |
Condition<Cond2ParamsTuple, cond2_sqls...>&& cond2 | |
) noexcept { | |
static constexpr char and_str[] = " AND "; | |
auto concated_params = std::tuple_cat(std::move(cond1).params, std::move(cond2).params); | |
return Condition<decltype(concated_params), cond1_sqls..., and_str, cond2_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class Cond1ParamsTuple, | |
const char*... cond1_sqls, | |
class Cond2ParamsTuple, | |
const char*... cond2_sqls> | |
auto operator||( | |
Condition<Cond1ParamsTuple, cond1_sqls...>&& cond1, | |
Condition<Cond2ParamsTuple, cond2_sqls...>&& cond2 | |
) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char or_str[] = " OR "; | |
static constexpr char rparen[] = ")"; | |
auto concated_params = std::tuple_cat(std::move(cond1).params, std::move(cond2).params); | |
return Condition< | |
decltype(concated_params), | |
lparen, | |
cond1_sqls..., | |
or_str, | |
cond2_sqls..., | |
rparen>{std::move(concated_params)}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct Join { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit Join(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectFromParamsTuple, | |
const char*... select_from_sqls> | |
auto to_join(SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectFromParamsTuple, | |
join_str, | |
lparen, | |
select_from_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_from).params}; | |
} | |
// Use like this: JOIN("abc") | |
#define JOIN(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "JOIN " sql_str; \ | |
return ::sim::sqlv2::Join<std::tuple<>, str>{{}}; \ | |
}() | |
// Use like this: JOIN_QUERY(SELECT("x, y") + FROM("xyz"), "xy") | |
#define JOIN_QUERY(select, new_table_name) \ | |
[](auto&& select_query) { \ | |
static constexpr char join[] = "JOIN "; \ | |
static constexpr char new_table_name_str[] = new_table_name; \ | |
return ::sim::sqlv2::to_join<join, new_table_name_str>( \ | |
std::forward<decltype(select_query)>(select_query) \ | |
); \ | |
}(select) | |
// Use like this: LEFT_JOIN("abc") | |
#define LEFT_JOIN(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "LEFT JOIN " sql_str; \ | |
return ::sim::sqlv2::Join<std::tuple<>, str>{{}}; \ | |
}() | |
// Use like this: LEFT_JOIN_QUERY(SELECT("x, y") + FROM("xyz"), "xy") | |
#define LEFT_JOIN_QUERY(select, new_table_name) \ | |
[](auto&& select_query) { \ | |
static constexpr char join[] = "LEFT JOIN "; \ | |
static constexpr char new_table_name_str[] = new_table_name; \ | |
return ::sim::sqlv2::to_join<join, new_table_name_str>( \ | |
std::forward<decltype(select_query)>(select_query) \ | |
); \ | |
}(select) | |
// Use like this: RIGHT_JOIN("abc") | |
#define RIGHT_JOIN(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "RIGHT JOIN " sql_str; \ | |
return ::sim::sqlv2::Join<std::tuple<>, str>{{}}; \ | |
}() | |
// Use like this: RIGHT_JOIN_QUERY(SELECT("x, y") + FROM("xyz"), "xy") | |
#define RIGHT_JOIN_QUERY(select, new_table_name) \ | |
[](auto&& select_query) { \ | |
static constexpr char join[] = "RIGHT JOIN "; \ | |
static constexpr char new_table_name_str[] = new_table_name; \ | |
return ::sim::sqlv2::to_join<join, new_table_name_str>( \ | |
std::forward<decltype(select_query)>(select_query) \ | |
); \ | |
}(select) | |
// Use like this: INNER_JOIN("abc") | |
#define INNER_JOIN(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "INNER JOIN " sql_str; \ | |
return ::sim::sqlv2::Join<std::tuple<>, str>{{}}; \ | |
}() | |
// Use like this: INNER_JOIN_QUERY(SELECT("x, y") + FROM("xyz"), "xy") | |
#define INNER_JOIN_QUERY(select, new_table_name) \ | |
[](auto&& select_query) { \ | |
static constexpr char join[] = "INNER JOIN "; \ | |
static constexpr char new_table_name_str[] = new_table_name; \ | |
return ::sim::sqlv2::to_join<join, new_table_name_str>( \ | |
std::forward<decltype(select_query)>(select_query) \ | |
); \ | |
}(select) | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectJoin { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectJoin(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
template < | |
class SelectFromParamsTuple, | |
const char*... select_from_sqls, | |
class JoinParamsTuple, | |
const char*... join_sqls> | |
auto operator+( | |
SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from, | |
Join<JoinParamsTuple, join_sqls...>&& join | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_from).params, std::move(join).params); | |
return SelectJoin<decltype(concated_params), select_from_sqls..., space, join_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct On { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit On(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
auto to_on(Condition<ParamsTuple, sqls...>&& condition) noexcept { | |
static constexpr char on[] = "ON "; | |
return On<ParamsTuple, on, sqls...>(std::move(condition).params); | |
} | |
// Use like this: | |
// - ON("a=b") | |
// - ON("a=? AND b=?", 1, false) | |
// - ON(CONDITION("a=?", 1) && CONDITION("b=?", false)) | |
#define ON(string_literal_or_condition, ...) \ | |
[](auto&& first_arg) { \ | |
/* if the first argument is a string literal */ \ | |
if constexpr (std::is_same_v<decltype(first_arg), const char(&)[sizeof(first_arg)]>) { \ | |
return [](auto&&... params) { \ | |
static constexpr char on[] = "ON "; \ | |
static constexpr decltype(first_arg, 'x') sql[] = string_literal_or_condition; \ | |
return ::sim::sqlv2::On<std::tuple<decltype(params)...>, on, sql>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}; \ | |
} else { \ | |
return [cond = std::forward<decltype(first_arg)>(first_arg \ | |
)]([[maybe_unused]] auto&&... params) mutable { \ | |
static_assert( \ | |
sizeof...(params) == 0, "Cannot specify params with non-string-literal" \ | |
); \ | |
return ::sim::sqlv2::to_on(std::forward<decltype(cond)>(cond)); \ | |
}; \ | |
} \ | |
}(string_literal_or_condition)(__VA_ARGS__) | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectJoinOn { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectJoinOn(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectJoinOn<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class SelectJoinParamsTuple, | |
const char*... select_join_sqls, | |
class OnParamsTuple, | |
const char*... on_sqls> | |
auto operator+( | |
SelectJoin<SelectJoinParamsTuple, select_join_sqls...>&& select_join, | |
On<OnParamsTuple, on_sqls...>&& on | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_join).params, std::move(on).params); | |
return SelectJoinOn<decltype(concated_params), select_join_sqls..., space, on_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls, | |
class JoinParamsTuple, | |
const char*... join_sqls> | |
auto operator+( | |
SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on, | |
Join<JoinParamsTuple, join_sqls...>&& join | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_join_on).params, std::move(join).params); | |
return SelectJoin<decltype(concated_params), select_join_on_sqls..., space, join_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls> | |
auto to_join(SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on | |
) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectJoinOnParamsTuple, | |
join_str, | |
lparen, | |
select_join_on_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_join_on).params}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct Where { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit Where(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
auto to_where(Condition<ParamsTuple, sqls...>&& condition) noexcept { | |
static constexpr char where[] = "WHERE "; | |
return Where<ParamsTuple, where, sqls...>(std::move(condition).params); | |
} | |
// Use like this: | |
// - WHERE("a=b") | |
// - WHERE("a=? AND b=?", 1, false) | |
// - WHERE(CONDITION("a=?", 1) && CONDITION("b=?", false)) | |
#define WHERE(string_literal_or_condition, ...) \ | |
[](auto&& first_arg) { \ | |
/* if the first argument is a string literal */ \ | |
if constexpr (std::is_same_v<decltype(first_arg), const char(&)[sizeof(first_arg)]>) { \ | |
return [](auto&&... params) { \ | |
static constexpr char where[] = "WHERE "; \ | |
static constexpr decltype(first_arg, 'x') sql[] = string_literal_or_condition; \ | |
return ::sim::sqlv2::Where<std::tuple<decltype(params)...>, where, sql>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}; \ | |
} else { \ | |
return [cond = std::forward<decltype(first_arg)>(first_arg \ | |
)]([[maybe_unused]] auto&&... params) mutable { \ | |
static_assert( \ | |
sizeof...(params) == 0, "Cannot specify params with non-string-literal" \ | |
); \ | |
return ::sim::sqlv2::to_where(std::forward<decltype(cond)>(cond)); \ | |
}; \ | |
} \ | |
}(string_literal_or_condition)(__VA_ARGS__) | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectWhere { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectWhere(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectWhere<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class SelectFromParamsTuple, | |
const char*... select_from_sqls, | |
class WhereParamsTuple, | |
const char*... where_sqls> | |
auto operator+( | |
SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from, | |
Where<WhereParamsTuple, where_sqls...>&& where | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_from).params, std::move(where).params); | |
return SelectWhere<decltype(concated_params), select_from_sqls..., space, where_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls, | |
class WhereParamsTuple, | |
const char*... where_sqls> | |
auto operator+( | |
SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on, | |
Where<WhereParamsTuple, where_sqls...>&& where | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = | |
std::tuple_cat(std::move(select_join_on).params, std::move(where).params); | |
return SelectWhere<decltype(concated_params), select_join_on_sqls..., space, where_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectWhereParamsTuple, | |
const char*... select_where_sqls> | |
auto to_join(SelectWhere<SelectWhereParamsTuple, select_where_sqls...>&& select_where) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectWhereParamsTuple, | |
join_str, | |
lparen, | |
select_where_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_where).params}; | |
} | |
template <const char* sql> | |
struct GroupBy { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit GroupBy() noexcept = default; | |
}; | |
#define GROUP_BY(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "GROUP BY " sql_str; \ | |
return ::sim::sqlv2::GroupBy<str>{}; \ | |
}() | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectGroupBy { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectGroupBy(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectGroupBy<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <class SelectFromParamsTuple, const char*... select_from_sqls, const char* group_by_sql> | |
auto operator+( | |
SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from, | |
GroupBy<group_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectGroupBy<SelectFromParamsTuple, select_from_sqls..., space, group_by_sql>{ | |
std::move(select_from).params | |
}; | |
} | |
template < | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls, | |
const char* group_by_sql> | |
auto operator+( | |
SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on, | |
GroupBy<group_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectGroupBy<SelectJoinOnParamsTuple, select_join_on_sqls..., space, group_by_sql>{ | |
std::move(select_join_on).params | |
}; | |
} | |
template <class SelectWhereParamsTuple, const char*... select_where_sqls, const char* group_by_sql> | |
auto operator+( | |
SelectWhere<SelectWhereParamsTuple, select_where_sqls...>&& select_where, | |
GroupBy<group_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectGroupBy<SelectWhereParamsTuple, select_where_sqls..., space, group_by_sql>{ | |
std::move(select_where).params | |
}; | |
} | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectGroupByParamsTuple, | |
const char*... select_group_by_sqls> | |
auto to_join(SelectGroupBy<SelectGroupByParamsTuple, select_group_by_sqls...>&& select_group_by | |
) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectGroupByParamsTuple, | |
join_str, | |
lparen, | |
select_group_by_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_group_by).params}; | |
} | |
template <const char* sql> | |
struct OrderBy { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit OrderBy() noexcept = default; | |
}; | |
#define ORDER_BY(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "ORDER BY " sql_str; \ | |
return ::sim::sqlv2::OrderBy<str>{}; \ | |
}() | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectOrderBy { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectOrderBy(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectOrderBy<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <class SelectFromParamsTuple, const char*... select_from_sqls, const char* order_by_sql> | |
auto operator+( | |
SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectOrderBy<SelectFromParamsTuple, select_from_sqls..., space, order_by_sql>{ | |
std::move(select_from).params | |
}; | |
} | |
template < | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectOrderBy<SelectJoinOnParamsTuple, select_join_on_sqls..., space, order_by_sql>{ | |
std::move(select_join_on).params | |
}; | |
} | |
template <class SelectWhereParamsTuple, const char*... select_where_sqls, const char* order_by_sql> | |
auto operator+( | |
SelectWhere<SelectWhereParamsTuple, select_where_sqls...>&& select_where, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectOrderBy<SelectWhereParamsTuple, select_where_sqls..., space, order_by_sql>{ | |
std::move(select_where).params | |
}; | |
} | |
template < | |
class SelectGroupByParamsTuple, | |
const char*... select_group_by_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
SelectGroupBy<SelectGroupByParamsTuple, select_group_by_sqls...>&& select_group_by, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return SelectOrderBy<SelectGroupByParamsTuple, select_group_by_sqls..., space, order_by_sql>{ | |
std::move(select_group_by).params | |
}; | |
} | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectOrderByParamsTuple, | |
const char*... select_order_by_sqls> | |
auto to_join(SelectOrderBy<SelectOrderByParamsTuple, select_order_by_sqls...>&& select_order_by | |
) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectOrderByParamsTuple, | |
join_str, | |
lparen, | |
select_order_by_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_order_by).params}; | |
} | |
template <class ParamsTuple, const char* sql> | |
struct Limit { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == meta::count(sql, '?')); | |
explicit Limit(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define LIMIT(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = "LIMIT " sql_str; \ | |
return ::sim::sqlv2::Limit<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template <class ParamsTuple, const char*... sqls> | |
struct SelectLimit { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit SelectLimit(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(SelectLimit<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class SelectFromParamsTuple, | |
const char*... select_from_sqls, | |
class LimitParamsTuple, | |
const char* limit_sql> | |
auto operator+( | |
SelectFrom<SelectFromParamsTuple, select_from_sqls...>&& select_from, | |
Limit<LimitParamsTuple, limit_sql>&& limit | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_from).params, std::move(limit).params); | |
return SelectLimit<decltype(concated_params), select_from_sqls..., space, limit_sql>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectJoinOnParamsTuple, | |
const char*... select_join_on_sqls, | |
class LimitParamsTuple, | |
const char* limit_sql> | |
auto operator+( | |
SelectJoinOn<SelectJoinOnParamsTuple, select_join_on_sqls...>&& select_join_on, | |
Limit<LimitParamsTuple, limit_sql>&& limit | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = | |
std::tuple_cat(std::move(select_join_on).params, std::move(limit).params); | |
return SelectLimit<decltype(concated_params), select_join_on_sqls..., space, limit_sql>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectWhereParamsTuple, | |
const char*... select_where_sqls, | |
class LimitParamsTuple, | |
const char* limit_sql> | |
auto operator+( | |
SelectWhere<SelectWhereParamsTuple, select_where_sqls...>&& select_where, | |
Limit<LimitParamsTuple, limit_sql>&& limit | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(select_where).params, std::move(limit).params); | |
return SelectLimit<decltype(concated_params), select_where_sqls..., space, limit_sql>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectGroupByParamsTuple, | |
const char*... select_group_by_sqls, | |
class LimitParamsTuple, | |
const char* limit_sql> | |
auto operator+( | |
SelectGroupBy<SelectGroupByParamsTuple, select_group_by_sqls...>&& select_group_by, | |
Limit<LimitParamsTuple, limit_sql>&& limit | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = | |
std::tuple_cat(std::move(select_group_by).params, std::move(limit).params); | |
return SelectLimit<decltype(concated_params), select_group_by_sqls..., space, limit_sql>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
class SelectOrderByParamsTuple, | |
const char*... select_order_by_sqls, | |
class LimitParamsTuple, | |
const char* limit_sql> | |
auto operator+( | |
SelectOrderBy<SelectOrderByParamsTuple, select_order_by_sqls...>&& select_order_by, | |
Limit<LimitParamsTuple, limit_sql>&& limit | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = | |
std::tuple_cat(std::move(select_order_by).params, std::move(limit).params); | |
return SelectLimit<decltype(concated_params), select_order_by_sqls..., space, limit_sql>{ | |
std::move(concated_params) | |
}; | |
} | |
template < | |
const char* join_str, | |
const char* new_table_name, | |
class SelectLimitParamsTuple, | |
const char*... select_limit_sqls> | |
auto to_join(SelectLimit<SelectLimitParamsTuple, select_limit_sqls...>&& select_limit) noexcept { | |
static constexpr char lparen[] = "("; | |
static constexpr char rparen_space[] = ") "; | |
return Join< | |
SelectLimitParamsTuple, | |
join_str, | |
lparen, | |
select_limit_sqls..., | |
rparen_space, | |
new_table_name>{std::move(select_limit).params}; | |
} | |
template <const char* sql> | |
struct Update { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit Update() noexcept = default; | |
}; | |
#define UPDATE(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "UPDATE " sql_str; \ | |
return ::sim::sqlv2::Update<str>{}; \ | |
}() | |
template <class ParamsTuple, const char* sql> | |
struct Set { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == meta::count(sql, '?')); | |
explicit Set(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define SET(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = "SET " sql_str; \ | |
return ::sim::sqlv2::Set<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template <class ParamsTuple, const char*... sqls> | |
struct UpdateSet { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit UpdateSet(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(UpdateSet<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <const char* update_str, class SetParamsTuple, const char* set_str> | |
auto operator+(Update<update_str>&& /**/, Set<SetParamsTuple, set_str>&& set) noexcept { | |
static constexpr char space[] = " "; | |
return UpdateSet<SetParamsTuple, update_str, space, set_str>{std::move(set).params}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct UpdateWhere { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit UpdateWhere(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(UpdateWhere<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class UpdateSetParamsTuple, | |
const char*... update_set_sqls, | |
class WhereParamsTuple, | |
const char*... where_sqls> | |
auto operator+( | |
UpdateSet<UpdateSetParamsTuple, update_set_sqls...>&& update_set, | |
Where<WhereParamsTuple, where_sqls...>&& where | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = std::tuple_cat(std::move(update_set).params, std::move(where).params); | |
return UpdateWhere<decltype(concated_params), update_set_sqls..., space, where_sqls...>{ | |
std::move(concated_params) | |
}; | |
} | |
template <const char* sql> | |
struct DeleteFrom { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit DeleteFrom() noexcept = default; | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<std::tuple<>, sql>() && noexcept { | |
return SqlWithParams<std::tuple<>, sql>{std::tuple{}}; | |
} | |
}; | |
template <const char* sql> | |
SqlWithParams(DeleteFrom<sql>&&) -> SqlWithParams<std::tuple<>, sql>; | |
#define DELETE_FROM(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "DELETE FROM " sql_str; \ | |
return ::sim::sqlv2::DeleteFrom<str>{}; \ | |
}() | |
template <class ParamsTuple, const char*... sqls> | |
struct DeleteWhere { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit DeleteWhere(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(DeleteWhere<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <const char* delete_from_sql, class WhereParamsTuple, const char*... where_sqls> | |
auto operator+( | |
DeleteFrom<delete_from_sql>&& /**/, Where<WhereParamsTuple, where_sqls...>&& where | |
) noexcept { | |
static constexpr char space[] = " "; | |
return DeleteWhere<WhereParamsTuple, delete_from_sql, space, where_sqls...>{ | |
std::move(where).params | |
}; | |
} | |
template <const char* sql> | |
struct InsertInto { | |
static_assert(meta::count(sql, '?') == 0); | |
explicit InsertInto() noexcept = default; | |
}; | |
#define INSERT_INTO(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "INSERT INTO " sql_str; \ | |
return ::sim::sqlv2::InsertInto<str>{}; \ | |
}() | |
#define INSERT_IGNORE_INTO(sql_str) \ | |
[] { \ | |
static constexpr char str[] = "INSERT IGNORE INTO " sql_str; \ | |
return ::sim::sqlv2::InsertInto<str>{}; \ | |
}() | |
template <class ParamsTuple, const char* sql> | |
struct Values { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == meta::count(sql, '?')); | |
explicit Values(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
#define VALUES(sql_str, ...) \ | |
[](auto&&... params) { \ | |
static constexpr char str[] = "VALUES(" sql_str ")"; \ | |
return ::sim::sqlv2::Values<std::tuple<decltype(params)...>, str>{ \ | |
{std::forward<decltype(params)>(params)...} \ | |
}; \ | |
}(__VA_ARGS__) | |
template <class ParamsTuple, const char*... sqls> | |
struct InsertValues { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit InsertValues(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(InsertValues<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <const char* insert_into_sql, class ValuesParamsTuple, const char* values_sql> | |
auto operator+( | |
InsertInto<insert_into_sql>&& /**/, Values<ValuesParamsTuple, values_sql>&& values | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertValues<ValuesParamsTuple, insert_into_sql, space, values_sql>{ | |
std::move(values).params | |
}; | |
} | |
template <class ParamsTuple, const char*... sql> | |
struct InsertSelect { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sql, '?') + ...)); | |
explicit InsertSelect(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
}; | |
template <const char* insert_into_sql, class SelectParamsTuple, const char* select_sql> | |
auto operator+( | |
InsertInto<insert_into_sql>&& /**/, Select<SelectParamsTuple, select_sql>&& select | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelect<SelectParamsTuple, insert_into_sql, space, select_sql>{ | |
std::move(select).params | |
}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct InsertSelectFrom { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit InsertSelectFrom(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(InsertSelectFrom<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template <class InsertSelectParamsTuple, const char*... insert_select_sqls, const char* from_str> | |
auto operator+( | |
InsertSelect<InsertSelectParamsTuple, insert_select_sqls...>&& insert_select, | |
From<from_str>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectFrom<InsertSelectParamsTuple, insert_select_sqls..., space, from_str>{ | |
std::move(insert_select).params | |
}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct InsertSelectWhere { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit InsertSelectWhere(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(InsertSelectWhere<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class InsertSelectFromParamsTuple, | |
const char*... insert_select_from_sqls, | |
class WhereParamsTuple, | |
const char*... where_sqls> | |
auto operator+( | |
InsertSelectFrom<InsertSelectFromParamsTuple, insert_select_from_sqls...>&& insert_select_from, | |
Where<WhereParamsTuple, where_sqls...>&& where | |
) noexcept { | |
static constexpr char space[] = " "; | |
auto concated_params = | |
std::tuple_cat(std::move(insert_select_from).params, std::move(where).params); | |
return InsertSelectWhere< | |
decltype(concated_params), | |
insert_select_from_sqls..., | |
space, | |
where_sqls...>{std::move(concated_params)}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct InsertSelectGroupBy { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit InsertSelectGroupBy(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(InsertSelectGroupBy<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class InsertSelectFromParamsTuple, | |
const char*... insert_select_from_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
InsertSelectFrom<InsertSelectFromParamsTuple, insert_select_from_sqls...>&& insert_select_from, | |
GroupBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectGroupBy< | |
InsertSelectFromParamsTuple, | |
insert_select_from_sqls..., | |
space, | |
order_by_sql>{std::move(insert_select_from).params}; | |
} | |
template < | |
class InsertSelectWhereParamsTuple, | |
const char*... insert_select_where_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
InsertSelectWhere<InsertSelectWhereParamsTuple, insert_select_where_sqls...>&& | |
insert_select_where, | |
GroupBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectGroupBy< | |
InsertSelectWhereParamsTuple, | |
insert_select_where_sqls..., | |
space, | |
order_by_sql>{std::move(insert_select_where).params}; | |
} | |
template <class ParamsTuple, const char*... sqls> | |
struct InsertSelectOrderBy { | |
ParamsTuple params; | |
static_assert(std::tuple_size_v<ParamsTuple> == (meta::count(sqls, '?') + ...)); | |
explicit InsertSelectOrderBy(ParamsTuple&& params) noexcept : params{std::move(params)} {} | |
// NOLINTNEXTLINE(google-explicit-constructor) | |
operator SqlWithParams<ParamsTuple, sqls...>() && noexcept { | |
return SqlWithParams<ParamsTuple, sqls...>{std::move(params)}; | |
} | |
}; | |
template <class ParamsTuple, const char*... sqls> | |
SqlWithParams(InsertSelectOrderBy<ParamsTuple, sqls...>&&) -> SqlWithParams<ParamsTuple, sqls...>; | |
template < | |
class InsertSelectFromParamsTuple, | |
const char*... insert_select_from_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
InsertSelectFrom<InsertSelectFromParamsTuple, insert_select_from_sqls...>&& insert_select_from, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectOrderBy< | |
InsertSelectFromParamsTuple, | |
insert_select_from_sqls..., | |
space, | |
order_by_sql>{std::move(insert_select_from).params}; | |
} | |
template < | |
class InsertSelectWhereParamsTuple, | |
const char*... insert_select_where_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
InsertSelectWhere<InsertSelectWhereParamsTuple, insert_select_where_sqls...>&& | |
insert_select_where, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectOrderBy< | |
InsertSelectWhereParamsTuple, | |
insert_select_where_sqls..., | |
space, | |
order_by_sql>{std::move(insert_select_where).params}; | |
} | |
template < | |
class InsertSelectGroupByParamsTuple, | |
const char*... insert_select_group_by_sqls, | |
const char* order_by_sql> | |
auto operator+( | |
InsertSelectGroupBy<InsertSelectGroupByParamsTuple, insert_select_group_by_sqls...>&& | |
insert_select_group_by, | |
OrderBy<order_by_sql>&& /**/ | |
) noexcept { | |
static constexpr char space[] = " "; | |
return InsertSelectOrderBy< | |
InsertSelectGroupByParamsTuple, | |
insert_select_group_by_sqls..., | |
space, | |
order_by_sql>{std::move(insert_select_group_by).params}; | |
} | |
} // namespace sim::sqlv2 | |
/************************ TESTS *****************************/ | |
#include <gtest/gtest.h> | |
// #include <sim/sqlv2/sqlv2.hh> | |
#include <string_view> | |
#define SQL_EQ(sql_expr, sql_str) \ | |
[] { \ | |
auto s = ::sim::sqlv2::SqlWithParams{sql_expr}; \ | |
static_assert(decltype(s)::sql == std::string_view{sql_str}); \ | |
}() | |
// NOLINTNEXTLINE | |
TEST(sql, constructing_sqls) { | |
SQL_EQ(SQL_WITH_PARAMS("SELECT ?", 1), "SELECT ?"); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc"), "SELECT a, b, c FROM abc"); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xyz") + ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN xyz ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + LEFT_JOIN("xyz") + ON("x=?", 1), | |
"SELECT a, b, c FROM abc LEFT JOIN xyz ON x=?" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + RIGHT_JOIN("xyz") + ON("x=? AND y=?", 1, false), | |
"SELECT a, b, c FROM abc RIGHT JOIN xyz ON x=? AND y=?" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + INNER_JOIN("xyz") + ON(CONDITION("x=a")), | |
"SELECT a, b, c FROM abc INNER JOIN xyz ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xx") + ON("x=a") + JOIN("yy") + ON("y=b"), | |
"SELECT a, b, c FROM abc JOIN xx ON x=a JOIN yy ON y=b" | |
); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc") + WHERE("a=42"), "SELECT a, b, c FROM abc WHERE a=42"); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc") + WHERE("a=?", 42), "SELECT a, b, c FROM abc WHERE a=?"); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + WHERE("a=? AND b=?", 42, false), | |
"SELECT a, b, c FROM abc WHERE a=? AND b=?" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + WHERE(CONDITION("a=42")), | |
"SELECT a, b, c FROM abc WHERE a=42" | |
); | |
SQL_EQ( | |
SELECT("a") + FROM("abc") + WHERE(CONDITION("b=42") && CONDITION("c=7")), | |
"SELECT a FROM abc WHERE b=42 AND c=7" | |
); | |
SQL_EQ( | |
SELECT("a") + FROM("abc") + WHERE(CONDITION("b=42") || CONDITION("c=7")), | |
"SELECT a FROM abc WHERE (b=42 OR c=7)" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xyz") + ON(CONDITION("x=a")) + | |
WHERE(CONDITION("b=42")), | |
"SELECT a, b, c FROM abc JOIN xyz ON x=a WHERE b=42" | |
); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc") + GROUP_BY("x"), "SELECT a, b, c FROM abc GROUP BY x"); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xyz") + ON("x=a") + GROUP_BY("y"), | |
"SELECT a, b, c FROM abc JOIN xyz ON x=a GROUP BY y" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + WHERE("a=1") + GROUP_BY("x"), | |
"SELECT a, b, c FROM abc WHERE a=1 GROUP BY x" | |
); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc") + ORDER_BY("x"), "SELECT a, b, c FROM abc ORDER BY x"); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xyz") + ON("x=a") + ORDER_BY("x"), | |
"SELECT a, b, c FROM abc JOIN xyz ON x=a ORDER BY x" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + WHERE("b=42") + ORDER_BY("x"), | |
"SELECT a, b, c FROM abc WHERE b=42 ORDER BY x" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + GROUP_BY("b") + ORDER_BY("x"), | |
"SELECT a, b, c FROM abc GROUP BY b ORDER BY x" | |
); | |
SQL_EQ(SELECT("a, b, c") + FROM("abc") + LIMIT("10"), "SELECT a, b, c FROM abc LIMIT 10"); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN("xyz") + ON("x=a") + LIMIT("10"), | |
"SELECT a, b, c FROM abc JOIN xyz ON x=a LIMIT 10" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + WHERE("b=42") + LIMIT("10"), | |
"SELECT a, b, c FROM abc WHERE b=42 LIMIT 10" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + GROUP_BY("x") + LIMIT("10"), | |
"SELECT a, b, c FROM abc GROUP BY x LIMIT 10" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + ORDER_BY("x") + LIMIT("10"), | |
"SELECT a, b, c FROM abc ORDER BY x LIMIT 10" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + JOIN_QUERY(SELECT("x, y") + FROM("xyz"), "xy") + | |
ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz) xy ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + | |
JOIN_QUERY(SELECT("x, y") + FROM("xyz") + JOIN("aaa") + ON("aaa.a=x"), "xy") + | |
ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz JOIN aaa ON aaa.a=x) xy ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + | |
JOIN_QUERY(SELECT("x, y") + FROM("xyz") + WHERE("z=42"), "xy") + ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz WHERE z=42) xy ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + | |
JOIN_QUERY(SELECT("x, y") + FROM("xyz") + GROUP_BY("x, y"), "xy") + ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz GROUP BY x, y) xy ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + | |
JOIN_QUERY(SELECT("x, y") + FROM("xyz") + ORDER_BY("x, y"), "xy") + ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz ORDER BY x, y) xy ON x=a" | |
); | |
SQL_EQ( | |
SELECT("a, b, c") + FROM("abc") + | |
JOIN_QUERY(SELECT("x, y") + FROM("xyz") + LIMIT("?", 10), "xy") + ON("x=a"), | |
"SELECT a, b, c FROM abc JOIN (SELECT x, y FROM xyz LIMIT ?) xy ON x=a" | |
); | |
SQL_EQ(UPDATE("abc") + SET("a=42"), "UPDATE abc SET a=42"); | |
SQL_EQ(UPDATE("abc") + SET("a=42") + WHERE("b=7"), "UPDATE abc SET a=42 WHERE b=7"); | |
SQL_EQ(DELETE_FROM("abc"), "DELETE FROM abc"); | |
SQL_EQ(DELETE_FROM("abc") + WHERE("b=7"), "DELETE FROM abc WHERE b=7"); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + VALUES("?, ?, 1", false, 42), | |
"INSERT INTO abc(a, b, c) VALUES(?, ?, 1)" | |
); | |
SQL_EQ( | |
INSERT_IGNORE_INTO("abc(a, b, c)") + VALUES("?, ?, 1", false, 42), | |
"INSERT IGNORE INTO abc(a, b, c) VALUES(?, ?, 1)" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + WHERE("x=42"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz WHERE x=42" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + GROUP_BY("x"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz GROUP BY x" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + WHERE("x=42") + | |
GROUP_BY("y"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz WHERE x=42 GROUP BY y" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + ORDER_BY("y"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz ORDER BY y" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + WHERE("x=42") + | |
ORDER_BY("y"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz WHERE x=42 ORDER BY y" | |
); | |
SQL_EQ( | |
INSERT_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + GROUP_BY("x") + | |
ORDER_BY("y"), | |
"INSERT INTO abc(a, b, c) SELECT ?, x, y FROM xyz GROUP BY x ORDER BY y" | |
); | |
SQL_EQ( | |
INSERT_IGNORE_INTO("abc(a, b, c)") + SELECT("?, x, y", 1) + FROM("xyz") + GROUP_BY("x") + | |
ORDER_BY("y"), | |
"INSERT IGNORE INTO abc(a, b, c) SELECT ?, x, y FROM xyz GROUP BY x ORDER BY y" | |
); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment