Skip to content

Instantly share code, notes, and snippets.

@varqox
Last active April 8, 2024 21:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save varqox/db3999feac551913596e299f5d3dd78b to your computer and use it in GitHub Desktop.
Save varqox/db3999feac551913596e299f5d3dd78b to your computer and use it in GitHub Desktop.
Constructing SQL queries in compile time
#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