startet with connection query intermediates
This commit is contained in:
parent
487dfb2eb4
commit
7b6cc121da
|
|
@ -4,11 +4,14 @@
|
|||
#include "matador/sql/basic_condition.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
struct placeholder {};
|
||||
|
||||
const placeholder _;
|
||||
|
||||
/**
|
||||
* @class condition
|
||||
* @brief Represents a sql query condition
|
||||
|
|
@ -29,6 +32,17 @@ class query;
|
|||
template<class L, class R, class Enabled = void>
|
||||
class condition;
|
||||
|
||||
template<>
|
||||
class condition<column, placeholder, typename std::enable_if<true>::type> : public basic_column_condition
|
||||
{
|
||||
public:
|
||||
condition(const column &fld, basic_condition::operand_t op, const placeholder &val);
|
||||
|
||||
placeholder value;
|
||||
|
||||
std::string evaluate(dialect &d) const override;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class condition<column, T, typename std::enable_if<
|
||||
std::is_scalar<T>::value &&
|
||||
|
|
@ -46,13 +60,7 @@ public:
|
|||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
d.add_host_var(field_.name());
|
||||
std::stringstream str;
|
||||
if (d.compile_type() == dialect::compile_type_t::DIRECT) {
|
||||
str << d.prepare_identifier(field_.name()) << " " << operand << " " << value;
|
||||
} else {
|
||||
str << d.prepare_identifier(field_.name()) << " " << operand << " " << d.next_placeholder();
|
||||
}
|
||||
return str.str();
|
||||
return d.prepare_identifier(field_.name()) + " " + operand + " " + std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -72,13 +80,7 @@ public:
|
|||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
d.add_host_var(field_.name());
|
||||
std::stringstream str;
|
||||
if (d.compile_type() == dialect::compile_type_t::DIRECT) {
|
||||
str << d.prepare_identifier(field_.name()) << " " << operand << " '" << value << "'";
|
||||
} else {
|
||||
str << d.prepare_identifier(field_.name()) << " " << operand << " " << d.next_placeholder();
|
||||
}
|
||||
return str.str();
|
||||
return d.prepare_identifier(field_.name()) + " " + operand + " '" + value + "'";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -98,9 +100,7 @@ public:
|
|||
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
std::stringstream str;
|
||||
str << value << " " << operand << " " << d.prepare_identifier(field_.name());
|
||||
return str.str();
|
||||
return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_.name());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -119,9 +119,7 @@ public:
|
|||
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "'" << value << "' " << operand << " " << d.prepare_identifier(field_.name());
|
||||
return str.str();
|
||||
return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_.name());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -138,74 +136,62 @@ public:
|
|||
* @endcode
|
||||
*/
|
||||
template < class V >
|
||||
class condition<column, std::initializer_list<V>> : public basic_in_condition
|
||||
{
|
||||
class condition<column, std::initializer_list<V>> : public basic_in_condition {
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an IN condition
|
||||
*
|
||||
* Creates an IN condition for the given column and
|
||||
* the given list of arguments.
|
||||
*
|
||||
* @param col Column for the IN condition
|
||||
* @param args List of arguments
|
||||
*/
|
||||
condition(const column &col, const std::initializer_list<V> &args)
|
||||
: basic_in_condition(col)
|
||||
, args_(args)
|
||||
{}
|
||||
/**
|
||||
* @brief Creates an IN condition
|
||||
*
|
||||
* Creates an IN condition for the given column and
|
||||
* the given list of arguments.
|
||||
*
|
||||
* @param col Column for the IN condition
|
||||
* @param args List of arguments
|
||||
*/
|
||||
condition(const column &col, const std::initializer_list<V> &args)
|
||||
: basic_in_condition(col), args_(args) {}
|
||||
|
||||
/**
|
||||
* @brief Evaluates the condition
|
||||
*
|
||||
* Evaluates the condition to a part of the
|
||||
* query string based on the given compile type
|
||||
*
|
||||
* @param d The d used to evaluate
|
||||
* @return A condition IN part of the query
|
||||
*/
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
auto count = size();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
d.add_host_var(field_.name());
|
||||
}
|
||||
std::stringstream str;
|
||||
str << d.prepare_identifier(field_.name()) << " IN (";
|
||||
if (args_.size() > 1) {
|
||||
auto first = args_.begin();
|
||||
auto last = args_.end() - 1;
|
||||
while (first != last) {
|
||||
if (d.compile_type() == dialect::compile_type_t::DIRECT) {
|
||||
str << *first++ << ",";
|
||||
} else {
|
||||
++first;
|
||||
str << d.next_placeholder() << ",";
|
||||
/**
|
||||
* @brief Evaluates the condition
|
||||
*
|
||||
* Evaluates the condition to a part of the
|
||||
* query string based on the given compile type
|
||||
*
|
||||
* @param d The d used to evaluate
|
||||
* @return A condition IN part of the query
|
||||
*/
|
||||
std::string evaluate(dialect &d) const override {
|
||||
auto count = size();
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
d.add_host_var(field_.name());
|
||||
}
|
||||
|
||||
|
||||
std::string result = d.prepare_identifier(field_.name()) + " IN (";
|
||||
if (args_.size() < 2) {
|
||||
for (const auto &val : args_) {
|
||||
result.append(std::to_string(val));
|
||||
}
|
||||
} else {
|
||||
auto it = args_.begin();
|
||||
result.append(std::to_string(*it++));
|
||||
for(; it != args_.end(); ++it) {
|
||||
result.append(", " + std::to_string(*it));
|
||||
}
|
||||
}
|
||||
result += ")";
|
||||
return result;
|
||||
}
|
||||
if (!args_.empty()) {
|
||||
if (d.compile_type() == dialect::compile_type_t::DIRECT) {
|
||||
str << args_.back();
|
||||
} else {
|
||||
str << d.next_placeholder();
|
||||
}
|
||||
}
|
||||
str << ")";
|
||||
return str.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of arguments in the list
|
||||
* @return The number of arguments in the list
|
||||
*/
|
||||
size_t size() const override
|
||||
{
|
||||
return args_.size();
|
||||
}
|
||||
/**
|
||||
* @brief Returns the number of arguments in the list
|
||||
* @return The number of arguments in the list
|
||||
*/
|
||||
[[nodiscard]] size_t size() const override {
|
||||
return args_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<V> args_;
|
||||
std::vector<V> args_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -244,23 +230,12 @@ public:
|
|||
* @param d The d used to evaluate
|
||||
* @return A condition IN part of the query
|
||||
*/
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
std::string result(d.prepare_identifier(field_.name()) + " " + operand + " (");
|
||||
// result += d.continue_build(const_cast<query&>(query_), d.compile_type());
|
||||
result += (")");
|
||||
return result;
|
||||
}
|
||||
std::string evaluate(dialect &d) const override;
|
||||
|
||||
private:
|
||||
query &query_;
|
||||
};
|
||||
|
||||
condition<column, query>::condition(column col, basic_condition::operand_t op, query &q)
|
||||
: basic_column_condition(std::move(col), op)
|
||||
, query_(q)
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Between condition.
|
||||
*
|
||||
|
|
@ -270,43 +245,35 @@ condition<column, query>::condition(column col, basic_condition::operand_t op, q
|
|||
* @tparam T The type of the boundary values
|
||||
*/
|
||||
template < class T >
|
||||
class condition<column, std::pair<T, T>> : public basic_condition
|
||||
{
|
||||
class condition<column, std::pair<T, T>> : public basic_condition {
|
||||
public:
|
||||
/**
|
||||
* @brief Create a new between condition
|
||||
*
|
||||
* @param col The column for the range check
|
||||
* @param range The boundary values defining the range
|
||||
*/
|
||||
condition(column col, const std::pair<T, T> &range)
|
||||
: field_(std::move(col)), range_(range) { }
|
||||
/**
|
||||
* @brief Create a new between condition
|
||||
*
|
||||
* @param col The column for the range check
|
||||
* @param range The boundary values defining the range
|
||||
*/
|
||||
condition(column col, const std::pair<T, T> &range)
|
||||
: field_(std::move(col)), range_(range) {}
|
||||
|
||||
/**
|
||||
* @brief Evaluates the condition
|
||||
*
|
||||
* Evaluates the condition to a between part
|
||||
* based on the given compile type
|
||||
*
|
||||
* @param d The d used to evaluate
|
||||
* @return A condition BETWEEN part of the query
|
||||
*/
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
d.add_host_var(field_.name());
|
||||
d.add_host_var(field_.name());
|
||||
std::stringstream str;
|
||||
if (d.compile_type() == dialect::compile_type_t::DIRECT) {
|
||||
str << d.prepare_identifier(field_.name()) << " BETWEEN " << range_.first << " AND " << range_.second;
|
||||
} else {
|
||||
str << d.prepare_identifier(field_.name()) << " BETWEEN " << d.next_placeholder() << " AND " << d.next_placeholder();
|
||||
}
|
||||
return str.str();
|
||||
}
|
||||
/**
|
||||
* @brief Evaluates the condition
|
||||
*
|
||||
* Evaluates the condition to a between part
|
||||
* based on the given compile type
|
||||
*
|
||||
* @param d The d used to evaluate
|
||||
* @return A condition BETWEEN part of the query
|
||||
*/
|
||||
std::string evaluate(dialect &d) const override {
|
||||
d.add_host_var(field_.name());
|
||||
d.add_host_var(field_.name());
|
||||
return d.prepare_identifier(field_.name()) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second);
|
||||
}
|
||||
|
||||
private:
|
||||
column field_;
|
||||
std::pair<T, T> range_;
|
||||
column field_;
|
||||
std::pair<T, T> range_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -331,7 +298,6 @@ public:
|
|||
* @param r right hand operator of the condition
|
||||
* @param op The operand (AND or OR)
|
||||
*/
|
||||
// condition(const condition<L1, R1> &l, const condition<L2, R2> &r, basic_condition::operand_t op)
|
||||
condition(condition<L1, R1> &&l, condition<L2, R2> &&r, basic_condition::operand_t op)
|
||||
: left(std::move(l)), right(std::move(r)), operand(op) { }
|
||||
|
||||
|
|
@ -343,16 +309,14 @@ public:
|
|||
*/
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
std::stringstream str;
|
||||
// ensure the numbering order for host vars
|
||||
auto cl = left.evaluate(d);
|
||||
auto cr = right.evaluate(d);
|
||||
if (operand == basic_condition::operand_t::AND) {
|
||||
str << "(" << cl << " " << basic_condition::operands[operand] << " " << cr << ")";
|
||||
return "(" + cl + " " + basic_condition::operands[operand] + " " + cr + ")";
|
||||
} else {
|
||||
str << cl << " " << basic_condition::operands[operand] << " " << cr;
|
||||
return cl + " " + basic_condition::operands[operand] + " " + cr;
|
||||
}
|
||||
return str.str();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -388,9 +352,7 @@ public:
|
|||
*/
|
||||
std::string evaluate(dialect &d) const override
|
||||
{
|
||||
std::stringstream str;
|
||||
str << operand << " (" << cond.evaluate(d) << ")";
|
||||
return str.str();
|
||||
return operand + " (" + cond.evaluate(d) + ")";
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -466,7 +428,6 @@ condition<column, std::pair<T, T>> between(const column &col, T low, T high)
|
|||
* @return The like condition object
|
||||
*/
|
||||
condition<column, std::string> like(const column &col, const std::string &val);
|
||||
//OOS_SQL_API condition<column, std::string> like(const matador::column &col, const std::string &val);
|
||||
|
||||
/**
|
||||
* @brief Condition equality operator for a column and a value
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef QUERY_CONNECTION_HPP
|
||||
#define QUERY_CONNECTION_HPP
|
||||
|
||||
#include "matador/sql/connection_intermediates.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
#include "matador/sql/query_builder.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
class connection
|
||||
{
|
||||
public:
|
||||
connection();
|
||||
query_select_intermediate select(std::initializer_list<std::string> column_names);
|
||||
|
||||
result execute(const std::string &sql);
|
||||
|
||||
private:
|
||||
dialect dialect_;
|
||||
query_builder query_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_CONNECTION_HPP
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef QUERY_CONNECTION_INTERMEDIATES_HPP
|
||||
#define QUERY_CONNECTION_INTERMEDIATES_HPP
|
||||
|
||||
#include "matador/sql/result.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
class basic_condition;
|
||||
class connection;
|
||||
class query_builder;
|
||||
|
||||
struct query_intermediate
|
||||
{
|
||||
query_intermediate(connection &db, query_builder &query);
|
||||
|
||||
connection &db;
|
||||
query_builder &query;
|
||||
};
|
||||
|
||||
struct query_finish : query_intermediate
|
||||
{
|
||||
using query_intermediate::query_intermediate;
|
||||
|
||||
result fetch_all();
|
||||
result fetch_one();
|
||||
result fetch_value();
|
||||
};
|
||||
|
||||
struct query_order_direction_intermediate : query_finish
|
||||
{
|
||||
using query_finish::query_finish;
|
||||
};
|
||||
|
||||
struct query_group_by_intermediate : query_finish
|
||||
{
|
||||
using query_finish::query_finish;
|
||||
|
||||
|
||||
};
|
||||
struct query_order_by_intermediate : query_intermediate
|
||||
{
|
||||
using query_intermediate::query_intermediate;
|
||||
query_order_direction_intermediate asc();
|
||||
query_order_direction_intermediate desc();
|
||||
|
||||
};
|
||||
|
||||
struct query_where_intermediate : query_finish
|
||||
{
|
||||
using query_finish::query_finish;
|
||||
};
|
||||
|
||||
struct query_from_intermediate : query_finish
|
||||
{
|
||||
using query_finish::query_finish;
|
||||
|
||||
query_where_intermediate where(const basic_condition &cond);
|
||||
query_group_by_intermediate group_by(const std::string &name);
|
||||
query_order_by_intermediate order_by(const std::string &name);
|
||||
};
|
||||
|
||||
struct query_select_intermediate : query_intermediate
|
||||
{
|
||||
using query_intermediate::query_intermediate;
|
||||
|
||||
query_from_intermediate from(const std::string &table, const std::string &as = "");
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_CONNECTION_INTERMEDIATES_HPP
|
||||
|
|
@ -23,7 +23,6 @@ public:
|
|||
SELECT,
|
||||
TABLE,
|
||||
VALUES,
|
||||
VALUE,
|
||||
COLUMNS,
|
||||
COLUMN,
|
||||
FROM,
|
||||
|
|
@ -36,11 +35,10 @@ public:
|
|||
GROUP_BY,
|
||||
ASC,
|
||||
DESC,
|
||||
TOP,
|
||||
LIMIT,
|
||||
AS,
|
||||
OFFSET,
|
||||
DISTINCT,
|
||||
CONDITION,
|
||||
SET,
|
||||
NOT_NULL,
|
||||
PRIMARY_KEY,
|
||||
|
|
@ -53,14 +51,6 @@ public:
|
|||
NONE
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enum representing the compile type
|
||||
*/
|
||||
enum class compile_type_t : uint8_t {
|
||||
PREPARED, /**< Compile type for prepared statements */
|
||||
DIRECT /**< Compile type for direct execute statements */
|
||||
};
|
||||
|
||||
/**
|
||||
* Holding enums concerning escaping identifiers
|
||||
*/
|
||||
|
|
@ -127,7 +117,6 @@ public:
|
|||
*/
|
||||
virtual std::string next_placeholder() const;
|
||||
|
||||
compile_type_t compile_type() const;
|
||||
void add_host_var(const std::string &host_var);
|
||||
void add_column(const std::string &column);
|
||||
|
||||
|
|
@ -137,41 +126,41 @@ public:
|
|||
private:
|
||||
using token_to_string_map = std::unordered_map<token_t, std::string>;
|
||||
|
||||
compile_type_t compile_type_ = compile_type_t::DIRECT;
|
||||
std::vector<std::string> host_vars_;
|
||||
std::vector<std::string> columns_;
|
||||
|
||||
token_to_string_map tokens_ {
|
||||
{token_t::CREATE, "CREATE"},
|
||||
{token_t::DROP, "DROP"},
|
||||
{token_t::REMOVE, "DELETE"},
|
||||
{token_t::INSERT, "INSERT"},
|
||||
{token_t::TABLE, "TABLE"},
|
||||
{token_t::INTO, "INTO"},
|
||||
{token_t::VALUES, "VALUES"},
|
||||
{token_t::UPDATE, "UPDATE"},
|
||||
{token_t::SELECT, "SELECT"},
|
||||
{token_t::COLUMNS, "COLUMNS"},
|
||||
{token_t::COLUMN, "COLUMN"},
|
||||
{token_t::FROM, "FROM"},
|
||||
{token_t::WHERE, "WHERE"},
|
||||
{token_t::AND, "AND"},
|
||||
{token_t::OR, "OR"},
|
||||
{token_t::LIKE, "LIKE"},
|
||||
{token_t::ORDER_BY, "ORDER BY"},
|
||||
{token_t::GROUP_BY, "GROUP BY"},
|
||||
{token_t::ASC, "ASC"},
|
||||
{token_t::DESC, "DESC"},
|
||||
{token_t::TOP, "LIMIT"},
|
||||
{token_t::AS, "AS"},
|
||||
{token_t::OFFSET, "OFFSET"},
|
||||
{token_t::DISTINCT, "DISTINCT"},
|
||||
{token_t::SET, "SET"},
|
||||
{token_t::NOT_NULL, "NOT NULL"},
|
||||
{token_t::CREATE, "CREATE"},
|
||||
{token_t::DROP, "DROP"},
|
||||
{token_t::REMOVE, "DELETE"},
|
||||
{token_t::INSERT, "INSERT"},
|
||||
{token_t::TABLE, "TABLE"},
|
||||
{token_t::INTO, "INTO"},
|
||||
{token_t::VALUES, "VALUES"},
|
||||
{token_t::UPDATE, "UPDATE"},
|
||||
{token_t::SELECT, "SELECT"},
|
||||
{token_t::COLUMNS, "COLUMNS"},
|
||||
{token_t::COLUMN, "COLUMN"},
|
||||
{token_t::FROM, "FROM"},
|
||||
{token_t::WHERE, "WHERE"},
|
||||
{token_t::AND, "AND"},
|
||||
{token_t::OR, "OR"},
|
||||
{token_t::LIKE, "LIKE"},
|
||||
{token_t::ORDER_BY, "ORDER BY"},
|
||||
{token_t::GROUP_BY, "GROUP BY"},
|
||||
{token_t::ASC, "ASC"},
|
||||
{token_t::DESC, "DESC"},
|
||||
{token_t::OFFSET, "OFFSET"},
|
||||
{token_t::LIMIT, "LIMIT"},
|
||||
{token_t::AS, "AS"},
|
||||
{token_t::OFFSET, "OFFSET"},
|
||||
{token_t::DISTINCT, "DISTINCT"},
|
||||
{token_t::SET, "SET"},
|
||||
{token_t::NOT_NULL, "NOT NULL"},
|
||||
{token_t::PRIMARY_KEY, "PRIMARY KEY"},
|
||||
{token_t::BEGIN, "BEGIN TRANSACTION"},
|
||||
{token_t::COMMIT, "COMMIT TRANSACTION"},
|
||||
{token_t::ROLLBACK, "ROLLBACK TRANSACTION"},
|
||||
{token_t::BEGIN, "BEGIN TRANSACTION"},
|
||||
{token_t::COMMIT, "COMMIT TRANSACTION"},
|
||||
{token_t::ROLLBACK, "ROLLBACK TRANSACTION"},
|
||||
{token_t::START_QUOTE, "\""},
|
||||
{token_t::END_QUOTE, "\""},
|
||||
{token_t::STRING_QUOTE, "'"},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
@startuml
|
||||
|
||||
scale 800 width
|
||||
state Query
|
||||
|
||||
state Create
|
||||
Create : Create database table
|
||||
state Drop
|
||||
Drop : Drop database table
|
||||
state Select
|
||||
Select: Query rows
|
||||
Select: Add columns
|
||||
state Insert
|
||||
Insert: Insert rows
|
||||
state Update
|
||||
Update: Update rows
|
||||
Update: Set table name
|
||||
state Delete
|
||||
Delete: Delete items from table
|
||||
|
||||
state Table
|
||||
Table: Set table name
|
||||
state Into
|
||||
Into: Set table name
|
||||
Into: Add columns
|
||||
state From
|
||||
From: Set table name
|
||||
|
||||
state Join
|
||||
Join: Set table
|
||||
Join: Set join type (inner left, right, outer)
|
||||
state Where
|
||||
Where: Add where clause
|
||||
state Set
|
||||
Set: Set column value pairs
|
||||
state Values
|
||||
Values: Set values
|
||||
|
||||
state On:
|
||||
On: Set Expression
|
||||
|
||||
state GroupBy
|
||||
GroupBy: Add column names
|
||||
state OrderBy
|
||||
OrderBy: Add expression
|
||||
state Limit
|
||||
Limit: Add number of max result elements
|
||||
|
||||
[*] --> Query
|
||||
Query --> Create
|
||||
Query --> Drop
|
||||
Query --> Select
|
||||
Query --> Insert
|
||||
Query --> Update
|
||||
Query --> Delete
|
||||
|
||||
Create --> Table
|
||||
Drop --> Table
|
||||
Select --> From
|
||||
Insert --> Into
|
||||
Delete --> From
|
||||
|
||||
Into --> Values
|
||||
Update --> Set
|
||||
Set -> Where
|
||||
From --> Where
|
||||
From --> OrderBy
|
||||
From --> GroupBy
|
||||
From --> Join
|
||||
Join --> On
|
||||
On --> Where
|
||||
|
||||
Where --> GroupBy
|
||||
Where --> OrderBy
|
||||
Where --> Limit
|
||||
|
||||
GroupBy --> OrderBy
|
||||
OrderBy --> Limit
|
||||
|
||||
Table --> [*]
|
||||
Values ---> [*]
|
||||
Where --> [*]
|
||||
Set --> [*]
|
||||
From --> [*]
|
||||
Limit --> [*]
|
||||
OrderBy --> [*]
|
||||
GroupBy --> [*]
|
||||
|
||||
@enduml
|
||||
|
|
@ -17,7 +17,7 @@ class dialect;
|
|||
namespace detail {
|
||||
struct any_type_to_string_visitor
|
||||
{
|
||||
any_type_to_string_visitor(const dialect &d) : d(d) {}
|
||||
explicit any_type_to_string_visitor(const dialect &d) : d(d) {}
|
||||
|
||||
void operator()(char &x) { to_string(x); }
|
||||
void operator()(short &x) { to_string(x); }
|
||||
|
|
@ -49,6 +49,10 @@ struct any_type_to_string_visitor
|
|||
|
||||
}
|
||||
|
||||
enum class join_type_t {
|
||||
INNER, OUTER, LEFT, RIGHT
|
||||
};
|
||||
|
||||
class query_builder
|
||||
{
|
||||
private:
|
||||
|
|
@ -70,6 +74,7 @@ private:
|
|||
QUERY_ORDER_BY,
|
||||
QUERY_ORDER_DIRECTION,
|
||||
QUERY_GROUP_BY,
|
||||
QUERY_OFFSET,
|
||||
QUERY_LIMIT,
|
||||
QUERY_FINISH
|
||||
};
|
||||
|
|
@ -87,20 +92,28 @@ private:
|
|||
public:
|
||||
explicit query_builder(const dialect &d);
|
||||
|
||||
query_builder create();
|
||||
query_builder drop();
|
||||
query_builder select(std::initializer_list<std::string> column_names);
|
||||
query_builder insert();
|
||||
query_builder update(const std::string &table);
|
||||
query_builder remove();
|
||||
query_builder& create();
|
||||
query_builder& drop();
|
||||
query_builder& select(std::initializer_list<std::string> column_names);
|
||||
query_builder& insert();
|
||||
query_builder& update(const std::string &table);
|
||||
query_builder& remove();
|
||||
|
||||
query_builder& table(const std::string &table, std::initializer_list<column> columns);
|
||||
query_builder& table(const std::string &table);
|
||||
query_builder& into(const std::string &table, std::initializer_list<std::string> column_names);
|
||||
query_builder& values(std::initializer_list<any_type> values);
|
||||
query_builder& from(const std::string &table, const std::string &as = "");
|
||||
query_builder& join(const std::string &table, join_type_t);
|
||||
query_builder& on(const std::string &column, const std::string &join_column);
|
||||
query_builder& set(std::initializer_list<key_value_pair> key_values);
|
||||
query_builder& where(const basic_condition &cond);
|
||||
query_builder& order_by(const std::string &column);
|
||||
query_builder& group_by(const std::string &column);
|
||||
query_builder& asc();
|
||||
query_builder& desc();
|
||||
query_builder& offset(size_t count);
|
||||
query_builder& limit(size_t count);
|
||||
|
||||
std::string compile();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef QUERY_RESULT_HPP
|
||||
#define QUERY_RESULT_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
struct result
|
||||
{
|
||||
std::string sql;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_RESULT_HPP
|
||||
|
|
@ -3,7 +3,9 @@ set(SQL_SOURCES
|
|||
sql/query_builder.cpp
|
||||
sql/column.cpp
|
||||
sql/key_value_pair.cpp
|
||||
sql/basic_condition.cpp)
|
||||
sql/basic_condition.cpp
|
||||
sql/connection.cpp
|
||||
sql/connection_intermediates.cpp)
|
||||
|
||||
set(SQL_HEADER
|
||||
../include/matador/sql/dialect.hpp
|
||||
|
|
@ -12,7 +14,10 @@ set(SQL_HEADER
|
|||
../include/matador/sql/types.hpp
|
||||
../include/matador/sql/key_value_pair.hpp
|
||||
../include/matador/sql/basic_condition.hpp
|
||||
../include/matador/sql/condition.hpp)
|
||||
../include/matador/sql/condition.hpp
|
||||
../include/matador/sql/connection.hpp
|
||||
../include/matador/sql/connection_intermediates.hpp
|
||||
../include/matador/sql/result.hpp)
|
||||
|
||||
set(UTILS_HEADER
|
||||
../include/matador/utils/field_attributes.hpp
|
||||
|
|
@ -21,7 +26,8 @@ set(UTILS_HEADER
|
|||
|
||||
set(UTILS_SOURCES
|
||||
utils/field_attributes.cpp
|
||||
utils/string.cpp)
|
||||
utils/string.cpp
|
||||
sql/condition.cpp)
|
||||
|
||||
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
|
||||
set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
#include "matador/sql/condition.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
condition<column, placeholder, std::enable_if<true>::type>::condition(const column &fld, basic_condition::operand_t op, const placeholder &val)
|
||||
: basic_column_condition(fld, op)
|
||||
, value(val)
|
||||
{ }
|
||||
|
||||
std::string condition<column, placeholder, std::enable_if<true>::type>::evaluate(dialect &d) const {
|
||||
d.add_host_var(field_.name());
|
||||
return d.prepare_identifier(field_.name()) + " " + operand + " " + d.next_placeholder();
|
||||
}
|
||||
|
||||
condition<column, query>::condition(column col, basic_condition::operand_t op, query &q)
|
||||
: basic_column_condition(std::move(col), op)
|
||||
, query_(q)
|
||||
{}
|
||||
|
||||
std::string condition<column, query>::evaluate(dialect &d) const {
|
||||
std::string result(d.prepare_identifier(field_.name()) + " " + operand + " (");
|
||||
result += (")");
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#include "matador/sql/connection.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
|
||||
connection::connection()
|
||||
: query_(dialect_) {}
|
||||
|
||||
result connection::execute(const std::string &sql) {
|
||||
return {sql};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#include "matador/sql/connection_intermediates.hpp"
|
||||
#include "matador/sql/connection.hpp"
|
||||
#include "matador/sql/query_builder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
result query_finish::fetch_all()
|
||||
{
|
||||
return db.execute(query.compile());
|
||||
}
|
||||
|
||||
result query_finish::fetch_one()
|
||||
{
|
||||
return db.execute(query.compile());
|
||||
}
|
||||
|
||||
result query_finish::fetch_value()
|
||||
{
|
||||
return db.execute(query.compile());
|
||||
}
|
||||
|
||||
query_intermediate::query_intermediate(connection &db, query_builder &query)
|
||||
: db(db), query(query) {}
|
||||
|
||||
query_order_direction_intermediate query_order_by_intermediate::asc()
|
||||
{
|
||||
return {db, query.asc()};
|
||||
}
|
||||
|
||||
query_order_direction_intermediate query_order_by_intermediate::desc()
|
||||
{
|
||||
return {db, query.desc()};
|
||||
}
|
||||
|
||||
query_group_by_intermediate query_from_intermediate::group_by(const std::string &name)
|
||||
{
|
||||
return {db, query.group_by(name)};
|
||||
}
|
||||
|
||||
query_order_by_intermediate query_from_intermediate::order_by(const std::string &name)
|
||||
{
|
||||
return {db, query.order_by(name)};
|
||||
}
|
||||
|
||||
query_where_intermediate query_from_intermediate::where(const basic_condition &cond)
|
||||
{
|
||||
return query_where_intermediate{db, query.where(cond)};
|
||||
}
|
||||
|
||||
query_from_intermediate query_select_intermediate::from(const std::string &table, const std::string &as)
|
||||
{
|
||||
return {db, query.from(table, as)};
|
||||
}
|
||||
|
||||
query_select_intermediate connection::select(std::initializer_list<std::string> column_names)
|
||||
{
|
||||
return query_select_intermediate{*this, query_.select(column_names)};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -62,11 +62,6 @@ std::string dialect::next_placeholder() const
|
|||
return "?";
|
||||
}
|
||||
|
||||
dialect::compile_type_t dialect::compile_type() const
|
||||
{
|
||||
return compile_type_;
|
||||
}
|
||||
|
||||
void dialect::add_host_var(const std::string &host_var)
|
||||
{
|
||||
host_vars_.emplace_back(host_var);
|
||||
|
|
|
|||
|
|
@ -32,13 +32,14 @@ query_builder::query_state_transition_map query_builder::transitions_{
|
|||
{state_t::QUERY_DELETE, {state_t::QUERY_FROM}},
|
||||
{state_t::QUERY_TABLE_CREATE, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_TABLE_DROP, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_FROM, {state_t::QUERY_WHERE, state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_FROM, {state_t::QUERY_OFFSET, state_t::QUERY_LIMIT, state_t::QUERY_WHERE, state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_SET, {state_t::QUERY_WHERE, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_INTO, {state_t::QUERY_VALUES}},
|
||||
{state_t::QUERY_WHERE, {state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_WHERE, {state_t::QUERY_ORDER_BY, state_t::QUERY_GROUP_BY, state_t::QUERY_OFFSET, state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_ORDER_BY, {state_t::QUERY_ORDER_DIRECTION}},
|
||||
{state_t::QUERY_ORDER_DIRECTION, {state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_ORDER_DIRECTION, {state_t::QUERY_OFFSET, state_t::QUERY_LIMIT, state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_GROUP_BY, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_OFFSET, {state_t::QUERY_LIMIT}},
|
||||
{state_t::QUERY_LIMIT, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_VALUES, {state_t::QUERY_FINISH}},
|
||||
{state_t::QUERY_FINISH, {}},
|
||||
|
|
@ -60,6 +61,7 @@ query_builder::query_state_to_string_map query_builder::state_strings_ {
|
|||
{ state_t::QUERY_WHERE, "where" },
|
||||
{ state_t::QUERY_ORDER_BY, "order_by" },
|
||||
{ state_t::QUERY_GROUP_BY, "group_by" },
|
||||
{ state_t::QUERY_OFFSET, "offset" },
|
||||
{ state_t::QUERY_LIMIT, "limit" },
|
||||
{ state_t::QUERY_FINISH, "finish" },
|
||||
};
|
||||
|
|
@ -78,7 +80,7 @@ query_builder::query_builder(const dialect &d)
|
|||
: dialect_(d)
|
||||
, value_to_string_(d) {}
|
||||
|
||||
query_builder query_builder::create() {
|
||||
query_builder& query_builder::create() {
|
||||
initialize(command_t::CREATE, state_t::QUERY_CREATE);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::CREATE));
|
||||
|
|
@ -86,7 +88,7 @@ query_builder query_builder::create() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder query_builder::drop() {
|
||||
query_builder& query_builder::drop() {
|
||||
initialize(command_t::DROP, state_t::QUERY_DROP);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::DROP));
|
||||
|
|
@ -94,7 +96,7 @@ query_builder query_builder::drop() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder query_builder::select(std::initializer_list<std::string> column_names) {
|
||||
query_builder& query_builder::select(std::initializer_list<std::string> column_names) {
|
||||
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::SELECT) + " ");
|
||||
|
|
@ -107,7 +109,7 @@ query_builder query_builder::select(std::initializer_list<std::string> column_na
|
|||
} else {
|
||||
auto it = column_names.begin();
|
||||
result.append(dialect_.prepare_identifier(*it++));
|
||||
for (it; it != column_names.end(); ++it) {
|
||||
for (; it != column_names.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(dialect_.prepare_identifier(*it));
|
||||
}
|
||||
|
|
@ -117,7 +119,7 @@ query_builder query_builder::select(std::initializer_list<std::string> column_na
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder query_builder::insert() {
|
||||
query_builder& query_builder::insert() {
|
||||
initialize(command_t::INSERT, state_t::QUERY_INSERT);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::INSERT));
|
||||
|
|
@ -125,7 +127,7 @@ query_builder query_builder::insert() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder query_builder::update(const std::string &table) {
|
||||
query_builder& query_builder::update(const std::string &table) {
|
||||
initialize(command_t::UPDATE, state_t::QUERY_UPDATE);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::UPDATE) + " " + dialect_.prepare_identifier(table));
|
||||
|
|
@ -133,7 +135,7 @@ query_builder query_builder::update(const std::string &table) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder query_builder::remove() {
|
||||
query_builder& query_builder::remove() {
|
||||
initialize(command_t::REMOVE, state_t::QUERY_DELETE);
|
||||
|
||||
query_parts_.emplace_back(dialect_.token_at(dialect::token_t::REMOVE));
|
||||
|
|
@ -141,7 +143,7 @@ query_builder query_builder::remove() {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::table(const std::string &table, std::initializer_list<column> columns) {
|
||||
query_builder& query_builder::table(const std::string &table, std::initializer_list<column> columns) {
|
||||
transition_to(state_t::QUERY_TABLE_CREATE);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(table) + " ");
|
||||
|
|
@ -155,7 +157,7 @@ query_builder &query_builder::table(const std::string &table, std::initializer_l
|
|||
} else {
|
||||
auto it = columns.begin();
|
||||
result.append(build_create_column(*it++, dialect_));
|
||||
for (it; it != columns.end(); ++it) {
|
||||
for (; it != columns.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(build_create_column(*it, dialect_));
|
||||
}
|
||||
|
|
@ -166,7 +168,7 @@ query_builder &query_builder::table(const std::string &table, std::initializer_l
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::table(const std::string &table) {
|
||||
query_builder& query_builder::table(const std::string &table) {
|
||||
transition_to(state_t::QUERY_TABLE_DROP);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(table));
|
||||
|
|
@ -174,7 +176,7 @@ query_builder &query_builder::table(const std::string &table) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::into(const std::string &table, std::initializer_list<std::string> column_names) {
|
||||
query_builder& query_builder::into(const std::string &table, std::initializer_list<std::string> column_names) {
|
||||
transition_to(state_t::QUERY_INTO);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::INTO) + " " + dialect_.prepare_identifier(table) + " ");
|
||||
|
|
@ -187,7 +189,7 @@ query_builder &query_builder::into(const std::string &table, std::initializer_li
|
|||
} else {
|
||||
auto it = column_names.begin();
|
||||
result.append(dialect_.prepare_identifier(*it++));
|
||||
for (it; it != column_names.end(); ++it) {
|
||||
for (; it != column_names.end(); ++it) {
|
||||
result.append(", ");
|
||||
result.append(dialect_.prepare_identifier(*it));
|
||||
}
|
||||
|
|
@ -198,7 +200,7 @@ query_builder &query_builder::into(const std::string &table, std::initializer_li
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::values(std::initializer_list<any_type> values) {
|
||||
query_builder& query_builder::values(std::initializer_list<any_type> values) {
|
||||
transition_to(state_t::QUERY_VALUES);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::VALUES) + " ");
|
||||
|
|
@ -227,7 +229,7 @@ query_builder &query_builder::values(std::initializer_list<any_type> values) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::from(const std::string &table, const std::string &as) {
|
||||
query_builder& query_builder::from(const std::string &table, const std::string &as) {
|
||||
transition_to(state_t::QUERY_FROM);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::FROM) + " " + dialect_.prepare_identifier(table) + (as.empty() ? "" : " " + as));
|
||||
|
|
@ -235,7 +237,17 @@ query_builder &query_builder::from(const std::string &table, const std::string &
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::set(std::initializer_list<key_value_pair> key_values) {
|
||||
query_builder &query_builder::join(const std::string &table, join_type_t)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::on(const std::string &column, const std::string &join_column)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::set(std::initializer_list<key_value_pair> key_values) {
|
||||
transition_to(state_t::QUERY_SET);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::SET) + " ");
|
||||
|
|
@ -267,7 +279,7 @@ query_builder &query_builder::set(std::initializer_list<key_value_pair> key_valu
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder &query_builder::where(const basic_condition &cond) {
|
||||
query_builder& query_builder::where(const basic_condition &cond) {
|
||||
transition_to(state_t::QUERY_WHERE);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::WHERE) + " ");
|
||||
|
|
@ -276,6 +288,53 @@ query_builder &query_builder::where(const basic_condition &cond) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::order_by(const std::string& column) {
|
||||
transition_to(state_t::QUERY_ORDER_BY);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::ORDER_BY) + " " + dialect_.prepare_identifier(column));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::group_by(const std::string& column) {
|
||||
transition_to(state_t::QUERY_GROUP_BY);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::GROUP_BY) + " " + dialect_.prepare_identifier(column));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::asc() {
|
||||
transition_to(state_t::QUERY_ORDER_DIRECTION);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::ASC));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::desc() {
|
||||
transition_to(state_t::QUERY_ORDER_DIRECTION);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::DESC));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::offset( size_t count ) {
|
||||
transition_to(state_t::QUERY_OFFSET);
|
||||
|
||||
query_parts_.emplace_back(" " + dialect_.token_at(dialect::token_t::OFFSET) + " " + std::to_string(count));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
query_builder& query_builder::limit( size_t count ) {
|
||||
transition_to(state_t::QUERY_LIMIT);
|
||||
|
||||
query_parts_.emplace_back( " " + dialect_.token_at(dialect::token_t::LIMIT) + " " + std::to_string( count));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string query_builder::compile() {
|
||||
std::string result;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ FetchContent_Declare(
|
|||
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
|
||||
add_executable(tests builder.cpp)
|
||||
add_executable(tests builder.cpp
|
||||
connection.cpp)
|
||||
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain matador)
|
||||
target_include_directories(tests PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>/include)
|
||||
|
|
@ -66,12 +66,53 @@ TEST_CASE("Delete", "[query]") {
|
|||
}
|
||||
|
||||
TEST_CASE("Where", "[query]") {
|
||||
dialect d;
|
||||
query_builder query(d);
|
||||
auto sql = query.select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.where("id"_col == 8 && "age"_col > 50)
|
||||
.compile();
|
||||
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" WHERE ("id" = 8 AND "age" > 50))");
|
||||
|
||||
sql = query.select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.where("id"_col == _ && "age"_col > 50)
|
||||
.compile();
|
||||
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" WHERE ("id" = ? AND "age" > 50))");
|
||||
}
|
||||
|
||||
TEST_CASE("OrderBy", "[query]") {
|
||||
dialect d;
|
||||
query_builder query(d);
|
||||
const auto sql = query.select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.order_by("name").asc()
|
||||
.compile();
|
||||
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" ORDER BY "name" ASC)");
|
||||
}
|
||||
|
||||
TEST_CASE("GroupBy", "[query]") {
|
||||
dialect d;
|
||||
query_builder query(d);
|
||||
const auto sql = query.select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.group_by("age")
|
||||
.compile();
|
||||
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" GROUP BY "age")");
|
||||
}
|
||||
|
||||
TEST_CASE("Limit", "[query]") {
|
||||
dialect d;
|
||||
query_builder query(d);
|
||||
const auto sql = query.select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.where("id"_col == 8)
|
||||
.offset(10)
|
||||
.limit(20)
|
||||
.compile();
|
||||
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" WHERE "id" = 8)");
|
||||
REQUIRE(sql == R"(SELECT "id", "name", "age" FROM "person" OFFSET 10 LIMIT 20)");
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <matador/sql/column.hpp>
|
||||
#include <matador/sql/condition.hpp>
|
||||
#include <matador/sql/connection.hpp>
|
||||
|
||||
using namespace matador::sql;
|
||||
|
||||
TEST_CASE("CSelect", "[connection]") {
|
||||
connection c;
|
||||
|
||||
auto res = c.select({"id", "name", "color"})
|
||||
.from("person")
|
||||
.where("id"_col == 8)
|
||||
.fetch_all();
|
||||
|
||||
REQUIRE(res.sql == R"(SELECT "id", "name", "color" FROM "person" WHERE "id" = 8)");
|
||||
}
|
||||
Loading…
Reference in New Issue