added sql function and alias
This commit is contained in:
parent
145c4dc0a3
commit
72f9d28d0d
|
|
@ -270,7 +270,7 @@ void sqlite_query_result::read_value(const char *id, size_t index, sql::any_type
|
||||||
throw std::logic_error("data type blob not supported");
|
throw std::logic_error("data type blob not supported");
|
||||||
}
|
}
|
||||||
case sql::data_type_t::type_unknown: {
|
case sql::data_type_t::type_unknown: {
|
||||||
value = result_[row_index_][index];
|
value = std::string(result_[row_index_][index]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,11 @@
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
class column {
|
class column {
|
||||||
public:
|
public:
|
||||||
explicit column(std::string name)
|
column(sql_function_t func, std::string name);
|
||||||
: name_(std::move(name))
|
column(const char *name, std::string alias = ""); // NOLINT(*-explicit-constructor)
|
||||||
, attributes_(utils::null_attributes) {}
|
column(std::string name, std::string alias = ""); // NOLINT(*-explicit-constructor)
|
||||||
|
|
||||||
column(const column&) = default;
|
column(const column&) = default;
|
||||||
column& operator=(const column&) = default;
|
column& operator=(const column&) = default;
|
||||||
|
|
@ -50,9 +46,12 @@ public:
|
||||||
[[nodiscard]] size_t index() const;
|
[[nodiscard]] size_t index() const;
|
||||||
[[nodiscard]] const utils::field_attributes& attributes() const;
|
[[nodiscard]] const utils::field_attributes& attributes() const;
|
||||||
[[nodiscard]] data_type_t type() const;
|
[[nodiscard]] data_type_t type() const;
|
||||||
|
[[nodiscard]] const std::string& alias() const;
|
||||||
[[nodiscard]] const std::string& ref_table() const;
|
[[nodiscard]] const std::string& ref_table() const;
|
||||||
[[nodiscard]] const std::string& ref_column() const;
|
[[nodiscard]] const std::string& ref_column() const;
|
||||||
|
|
||||||
|
void alias(const std::string &as);
|
||||||
|
|
||||||
template< typename Type >
|
template< typename Type >
|
||||||
[[nodiscard]] bool is_type_of() const {
|
[[nodiscard]] bool is_type_of() const {
|
||||||
return std::holds_alternative<Type>(value_);
|
return std::holds_alternative<Type>(value_);
|
||||||
|
|
@ -94,6 +93,9 @@ public:
|
||||||
return visitor.result;
|
return visitor.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_function() const;
|
||||||
|
[[nodiscard]] sql_function_t function() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op)
|
void process(Operator &op)
|
||||||
|
|
@ -113,6 +115,8 @@ private:
|
||||||
utils::field_attributes attributes_;
|
utils::field_attributes attributes_;
|
||||||
data_type_t type_{data_type_t::type_unknown};
|
data_type_t type_{data_type_t::type_unknown};
|
||||||
any_type value_;
|
any_type value_;
|
||||||
|
sql_function_t function_{sql_function_t::NONE};
|
||||||
|
std::string alias_;
|
||||||
std::string ref_table_;
|
std::string ref_table_;
|
||||||
std::string ref_column_;
|
std::string ref_column_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
#include "matador/utils/access.hpp"
|
#include "matador/utils/access.hpp"
|
||||||
#include "matador/utils/field_attributes.hpp"
|
#include "matador/utils/field_attributes.hpp"
|
||||||
#include "matador/utils/identifier.hpp"
|
|
||||||
|
|
||||||
|
#include <typeindex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,13 @@ public:
|
||||||
[[nodiscard]] const connection_info& info() const;
|
[[nodiscard]] const connection_info& info() const;
|
||||||
|
|
||||||
[[nodiscard]] record describe(const std::string &table_name) const;
|
[[nodiscard]] record describe(const std::string &table_name) const;
|
||||||
bool exists(const std::string &table_name) const;
|
[[nodiscard]] bool exists(const std::string &table_name) const;
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
query_result<Type> fetch(const std::string &sql)
|
query_result<Type> fetch(const std::string &sql)
|
||||||
{
|
{
|
||||||
return query_result<Type>(connection_->fetch(sql));
|
return query_result<Type>(connection_->fetch(sql));
|
||||||
}
|
}
|
||||||
[[nodiscard]] query_result<record> fetch(const std::string &sql) const;
|
|
||||||
[[nodiscard]] std::pair<size_t, std::string> execute(const std::string &sql) const;
|
[[nodiscard]] std::pair<size_t, std::string> execute(const std::string &sql) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
|
class column;
|
||||||
|
|
||||||
class dialect
|
class dialect
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -61,6 +63,7 @@ public:
|
||||||
|
|
||||||
using token_to_string_map = std::unordered_map<token_t, std::string>;
|
using token_to_string_map = std::unordered_map<token_t, std::string>;
|
||||||
using data_type_to_string_map = std::unordered_map<data_type_t, std::string>;
|
using data_type_to_string_map = std::unordered_map<data_type_t, std::string>;
|
||||||
|
using sql_func_to_string_map = std::unordered_map<sql_function_t, std::string>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dialect() = default;
|
dialect() = default;
|
||||||
|
|
@ -79,7 +82,7 @@ public:
|
||||||
* @param str The identifier string to be prepared
|
* @param str The identifier string to be prepared
|
||||||
* @return The prepared string
|
* @return The prepared string
|
||||||
*/
|
*/
|
||||||
std::string prepare_identifier(const std::string &str) const;
|
std::string prepare_identifier(const column &col) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare string literal
|
* Prepare string literal
|
||||||
|
|
@ -196,6 +199,15 @@ private:
|
||||||
{data_type_t::type_null, "NULL"},
|
{data_type_t::type_null, "NULL"},
|
||||||
{data_type_t::type_unknown, "UNKNOWN"}
|
{data_type_t::type_unknown, "UNKNOWN"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sql_func_to_string_map sql_func_map_ {
|
||||||
|
{sql_function_t::NONE, "NONE" },
|
||||||
|
{sql_function_t::COUNT, "COUNT" },
|
||||||
|
{sql_function_t::AVG, "AVG" },
|
||||||
|
{sql_function_t::SUM, "SUM" },
|
||||||
|
{sql_function_t::MIN, "MIN" },
|
||||||
|
{sql_function_t::MAX, "MAX" },
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ struct any_type_to_string_visitor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
column alias(const std::string &column, const std::string &as);
|
||||||
|
column alias(column &&col, const std::string &as);
|
||||||
|
column count(const std::string &column);
|
||||||
|
|
||||||
enum class join_type_t {
|
enum class join_type_t {
|
||||||
INNER, OUTER, LEFT, RIGHT
|
INNER, OUTER, LEFT, RIGHT
|
||||||
};
|
};
|
||||||
|
|
@ -103,8 +107,8 @@ public:
|
||||||
|
|
||||||
query_builder& create();
|
query_builder& create();
|
||||||
query_builder& drop();
|
query_builder& drop();
|
||||||
query_builder& select(std::initializer_list<std::string> column_names);
|
query_builder& select(std::initializer_list<column> columns);
|
||||||
query_builder& select(const std::vector<std::string> &column_names);
|
query_builder& select(const std::vector<column> &columns);
|
||||||
query_builder& insert();
|
query_builder& insert();
|
||||||
query_builder& update(const std::string &table);
|
query_builder& update(const std::string &table);
|
||||||
query_builder& remove();
|
query_builder& remove();
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ protected:
|
||||||
class query_select_intermediate : public query_start_intermediate
|
class query_select_intermediate : public query_start_intermediate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
query_select_intermediate(session &s, std::vector<std::string> column_names);
|
query_select_intermediate(session &s, const std::vector<column>& columns);
|
||||||
|
|
||||||
query_from_intermediate from(const std::string &table, const std::string &as = "");
|
query_from_intermediate from(const std::string &table, const std::string &as = "");
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,19 @@ private:
|
||||||
query_result<Type> *result_{nullptr};
|
query_result<Type> *result_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template < typename Type >
|
||||||
|
Type* create_prototype(const record &/*prototype*/)
|
||||||
|
{
|
||||||
|
return new Type{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
record* create_prototype<record>(const record &prototype);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
template < typename Type >
|
template < typename Type >
|
||||||
class query_result
|
class query_result
|
||||||
{
|
{
|
||||||
|
|
@ -116,8 +129,8 @@ public:
|
||||||
explicit query_result(std::unique_ptr<query_result_impl> impl)
|
explicit query_result(std::unique_ptr<query_result_impl> impl)
|
||||||
: impl_(std::move(impl)) {}
|
: impl_(std::move(impl)) {}
|
||||||
|
|
||||||
query_result(std::unique_ptr<query_result_impl> impl, creator_func creator)
|
query_result(std::unique_ptr<query_result_impl> impl, record record_prototype)
|
||||||
: creator_(creator)
|
: record_prototype_(std::move(record_prototype))
|
||||||
, impl_(std::move(impl)) {}
|
, impl_(std::move(impl)) {}
|
||||||
|
|
||||||
iterator begin() { return std::move(++iterator(this)); }
|
iterator begin() { return std::move(++iterator(this)); }
|
||||||
|
|
@ -126,7 +139,7 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class query_result_iterator<Type>;
|
friend class query_result_iterator<Type>;
|
||||||
|
|
||||||
Type* create() { return creator_(); }
|
Type* create() { return detail::create_prototype<Type>(record_prototype_); }
|
||||||
|
|
||||||
void bind(const Type &obj)
|
void bind(const Type &obj)
|
||||||
{
|
{
|
||||||
|
|
@ -139,7 +152,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
creator_func creator_ = []{ return new Type; };
|
record record_prototype_;
|
||||||
std::unique_ptr<query_result_impl> impl_;
|
std::unique_ptr<query_result_impl> impl_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef QUERY_SESSION_HPP
|
#ifndef QUERY_SESSION_HPP
|
||||||
#define QUERY_SESSION_HPP
|
#define QUERY_SESSION_HPP
|
||||||
|
|
||||||
#include "matador/sql/column_name_generator.hpp"
|
#include "matador/sql/column_generator.hpp"
|
||||||
#include "matador/sql/connection.hpp"
|
#include "matador/sql/connection.hpp"
|
||||||
#include "matador/sql/connection_pool.hpp"
|
#include "matador/sql/connection_pool.hpp"
|
||||||
#include "matador/sql/query_builder.hpp"
|
#include "matador/sql/query_builder.hpp"
|
||||||
|
|
@ -24,9 +24,9 @@ public:
|
||||||
template < class Type >
|
template < class Type >
|
||||||
query_select_intermediate select()
|
query_select_intermediate select()
|
||||||
{
|
{
|
||||||
return query_select_intermediate{*this, column_name_generator::generate<Type>()};
|
return query_select_intermediate{*this, column_generator::generate<Type>(table_repository_)};
|
||||||
}
|
}
|
||||||
query_select_intermediate select(std::initializer_list<std::string> column_names);
|
query_select_intermediate select(std::initializer_list<column> columns);
|
||||||
query_insert_intermediate insert();
|
query_insert_intermediate insert();
|
||||||
query_update_intermediate update(const std::string &table);
|
query_update_intermediate update(const std::string &table);
|
||||||
query_delete_intermediate remove();
|
query_delete_intermediate remove();
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,16 @@ enum struct database_type_t : uint8_t {
|
||||||
type_unknown /*!< Data type unknown */
|
type_unknown /*!< Data type unknown */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class sql_function_t {
|
||||||
|
NONE,
|
||||||
|
COUNT,
|
||||||
|
AVG,
|
||||||
|
SUM,
|
||||||
|
MIN,
|
||||||
|
MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @tparam T The type of the traits
|
* @tparam T The type of the traits
|
||||||
* @brief Type traits for database types
|
* @brief Type traits for database types
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ set(SQL_SOURCES
|
||||||
sql/key_value_generator.cpp
|
sql/key_value_generator.cpp
|
||||||
sql/fk_value_extractor.cpp
|
sql/fk_value_extractor.cpp
|
||||||
sql/table_repository.cpp
|
sql/table_repository.cpp
|
||||||
sql/any_type_to_visitor.cpp)
|
sql/any_type_to_visitor.cpp
|
||||||
|
sql/query_result.cpp)
|
||||||
|
|
||||||
set(SQL_HEADER
|
set(SQL_HEADER
|
||||||
../include/matador/sql/dialect.hpp
|
../include/matador/sql/dialect.hpp
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ void convert(std::string &dest, bool source)
|
||||||
|
|
||||||
void convert(std::string &dest, const char *source)
|
void convert(std::string &dest, const char *source)
|
||||||
{
|
{
|
||||||
dest = source;
|
dest.assign(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
long long to_long_long(const char *source)
|
long long to_long_long(const char *source)
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,24 @@
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "matador/sql/column.hpp"
|
#include "matador/sql/column.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace matador::sql {
|
namespace matador::sql {
|
||||||
|
|
||||||
const column::data_type_index column::data_type_index_ {
|
column::column(sql_function_t func, std::string name)
|
||||||
data_type_t::type_char,
|
: name_(std::move(name))
|
||||||
data_type_t::type_short,
|
, type_(data_type_t::type_int)
|
||||||
data_type_t::type_int,
|
, attributes_(utils::null_attributes)
|
||||||
data_type_t::type_long,
|
, function_(func) {}
|
||||||
data_type_t::type_long_long,
|
|
||||||
data_type_t::type_unsigned_char,
|
column::column(const char *name, std::string alias)
|
||||||
data_type_t::type_unsigned_short,
|
: name_(name)
|
||||||
data_type_t::type_unsigned_int,
|
, attributes_(utils::null_attributes)
|
||||||
data_type_t::type_unsigned_long,
|
, alias_(std::move(alias)) {}
|
||||||
data_type_t::type_unsigned_long_long,
|
|
||||||
data_type_t::type_float,
|
column::column(std::string name, std::string alias)
|
||||||
data_type_t::type_double,
|
: name_(std::move(name))
|
||||||
data_type_t::type_bool,
|
, attributes_(utils::null_attributes)
|
||||||
data_type_t::type_char_pointer,
|
, alias_(std::move(alias)) {}
|
||||||
data_type_t::type_varchar,
|
|
||||||
data_type_t::type_text,
|
|
||||||
data_type_t::type_null,
|
|
||||||
};
|
|
||||||
|
|
||||||
column::column(std::string name, data_type_t type, utils::field_attributes attr)
|
column::column(std::string name, data_type_t type, utils::field_attributes attr)
|
||||||
: name_(std::move(name))
|
: name_(std::move(name))
|
||||||
|
|
@ -57,6 +53,11 @@ data_type_t column::type() const
|
||||||
return type_;
|
return type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &column::alias() const
|
||||||
|
{
|
||||||
|
return alias_;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string &column::ref_table() const
|
const std::string &column::ref_table() const
|
||||||
{
|
{
|
||||||
return ref_table_;
|
return ref_table_;
|
||||||
|
|
@ -67,6 +68,11 @@ const std::string &column::ref_column() const
|
||||||
return ref_column_;
|
return ref_column_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void column::alias(const std::string &as)
|
||||||
|
{
|
||||||
|
alias_ = as;
|
||||||
|
}
|
||||||
|
|
||||||
std::string column::str() const
|
std::string column::str() const
|
||||||
{
|
{
|
||||||
any_type_to_visitor<std::string> visitor;
|
any_type_to_visitor<std::string> visitor;
|
||||||
|
|
@ -74,9 +80,19 @@ std::string column::str() const
|
||||||
return visitor.result;
|
return visitor.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool column::is_function() const
|
||||||
|
{
|
||||||
|
return function_ != sql_function_t::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql_function_t column::function() const
|
||||||
|
{
|
||||||
|
return function_;
|
||||||
|
}
|
||||||
|
|
||||||
column operator "" _col(const char *name, size_t len)
|
column operator "" _col(const char *name, size_t len)
|
||||||
{
|
{
|
||||||
return column(std::string(name, len));
|
return {std::string(name, len)};
|
||||||
}
|
}
|
||||||
|
|
||||||
column make_column( const std::string& name, data_type_t type, utils::field_attributes attr )
|
column make_column( const std::string& name, data_type_t type, utils::field_attributes attr )
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,6 @@ bool connection::exists(const std::string &table_name) const
|
||||||
return connection_->exists(table_name);
|
return connection_->exists(table_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_result<record> connection::fetch(const std::string &sql) const
|
|
||||||
{
|
|
||||||
auto rec = connection_->describe("person");
|
|
||||||
return {connection_->fetch(sql), [rec](){ return new record(rec); }};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<size_t, std::string> connection::execute(const std::string &sql) const
|
std::pair<size_t, std::string> connection::execute(const std::string &sql) const
|
||||||
{
|
{
|
||||||
return {connection_->execute(sql), sql};
|
return {connection_->execute(sql), sql};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "matador/sql/dialect.hpp"
|
#include "matador/sql/dialect.hpp"
|
||||||
|
#include "matador/sql/column.hpp"
|
||||||
|
|
||||||
#include "matador/utils/string.hpp"
|
#include "matador/utils/string.hpp"
|
||||||
|
|
||||||
|
|
@ -33,11 +34,15 @@ const std::string &dialect::data_type_at(data_type_t type) const
|
||||||
return data_types_.at(type);
|
return data_types_.at(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string dialect::prepare_identifier(const std::string &str) const
|
std::string dialect::prepare_identifier(const column &col) const
|
||||||
{
|
{
|
||||||
std::string result(str);
|
std::string result(col.name());
|
||||||
escape_quotes_in_identifier(result);
|
escape_quotes_in_identifier(result);
|
||||||
quote_identifier(result);
|
if (!col.is_function()) {
|
||||||
|
quote_identifier(result);
|
||||||
|
} else {
|
||||||
|
return sql_func_map_.at(col.function()) + "(" + result + ")";
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,12 +97,12 @@ query_builder& query_builder::drop() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
query_builder& query_builder::select(std::initializer_list<std::string> column_names)
|
query_builder& query_builder::select(std::initializer_list<column> columns)
|
||||||
{
|
{
|
||||||
return select(std::vector<std::string>{column_names});
|
return select(std::vector<column>{columns});
|
||||||
}
|
}
|
||||||
|
|
||||||
query_builder& query_builder::select(const std::vector<std::string> &column_names)
|
query_builder &query_builder::select(const std::vector<column> &columns)
|
||||||
{
|
{
|
||||||
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
initialize(command_t::SELECT, state_t::QUERY_SELECT);
|
||||||
|
|
||||||
|
|
@ -111,15 +111,16 @@ query_builder& query_builder::select(const std::vector<std::string> &column_name
|
||||||
query_.prototype.clear();
|
query_.prototype.clear();
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
if (column_names.size() < 2) {
|
if (columns.size() < 2) {
|
||||||
for (const auto &col : column_names) {
|
for (const auto &col : columns) {
|
||||||
result.append(dialect_.prepare_identifier(col));
|
result.append(dialect_.prepare_identifier(col));
|
||||||
query_.prototype.append(column{col});
|
query_.prototype.append(col);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto it = column_names.begin();
|
auto it = columns.begin();
|
||||||
result.append(dialect_.prepare_identifier(*it++));
|
result.append(dialect_.prepare_identifier(*it++));
|
||||||
for (; it != column_names.end(); ++it) {
|
query_.prototype.append(column{*it});
|
||||||
|
for (; it != columns.end(); ++it) {
|
||||||
result.append(", ");
|
result.append(", ");
|
||||||
result.append(dialect_.prepare_identifier(*it));
|
result.append(dialect_.prepare_identifier(*it));
|
||||||
query_.prototype.append(column{*it});
|
query_.prototype.append(column{*it});
|
||||||
|
|
@ -444,4 +445,19 @@ std::string build_create_column(const column &col, const dialect &d, column_cont
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
column alias(const std::string &column, const std::string &as)
|
||||||
|
{
|
||||||
|
return {column, as};
|
||||||
|
}
|
||||||
|
|
||||||
|
column alias(column &&col, const std::string &as) {
|
||||||
|
col.alias(as);
|
||||||
|
return std::move(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
column count(const std::string &column)
|
||||||
|
{
|
||||||
|
return {sql_function_t::COUNT, column};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -76,10 +76,10 @@ query_where_intermediate query_from_intermediate::where(const basic_condition &c
|
||||||
return query_where_intermediate{session_, builder_.where(cond)};
|
return query_where_intermediate{session_, builder_.where(cond)};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_select_intermediate::query_select_intermediate(session &s, std::vector<std::string> column_names)
|
query_select_intermediate::query_select_intermediate(session &s, const std::vector<column>& columns)
|
||||||
: query_start_intermediate(s)
|
: query_start_intermediate(s)
|
||||||
{
|
{
|
||||||
builder_.select(std::move(column_names));
|
builder_.select(columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
query_from_intermediate query_select_intermediate::from(const std::string &table, const std::string &as)
|
query_from_intermediate query_select_intermediate::from(const std::string &table, const std::string &as)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "matador/sql/query_result.hpp"
|
||||||
|
|
||||||
|
namespace matador::sql::detail {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
record *create_prototype<record>(const record &prototype)
|
||||||
|
{
|
||||||
|
return new record{prototype};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -20,10 +20,9 @@ query_drop_intermediate session::drop()
|
||||||
return query_drop_intermediate{*this};
|
return query_drop_intermediate{*this};
|
||||||
}
|
}
|
||||||
|
|
||||||
query_select_intermediate session::select(std::initializer_list<std::string> column_names)
|
query_select_intermediate session::select(std::initializer_list<column> columns)
|
||||||
{
|
{
|
||||||
|
return {*this, columns};
|
||||||
return query_select_intermediate{*this, column_names};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
query_insert_intermediate session::insert()
|
query_insert_intermediate session::insert()
|
||||||
|
|
@ -52,7 +51,8 @@ query_result<record> session::fetch(const query &q) const
|
||||||
it = prototypes_.emplace(q.table_name, c->describe(q.table_name)).first;
|
it = prototypes_.emplace(q.table_name, c->describe(q.table_name)).first;
|
||||||
}
|
}
|
||||||
auto res = c->call_fetch(q.sql);
|
auto res = c->call_fetch(q.sql);
|
||||||
return query_result<record>{std::move(res), [it]() { return new record(it->second); }};
|
return query_result<record>{std::move(res), q.prototype};
|
||||||
|
// return query_result<record>{std::move(res), [it]() { return new record(it->second); }};
|
||||||
}
|
}
|
||||||
|
|
||||||
//query_result<record> session::fetch(const std::string &sql) const
|
//query_result<record> session::fetch(const std::string &sql) const
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ add_executable(tests builder.cpp
|
||||||
models/flight.hpp
|
models/flight.hpp
|
||||||
models/person.hpp
|
models/person.hpp
|
||||||
AnyTypeToVisitorTest.cpp
|
AnyTypeToVisitorTest.cpp
|
||||||
ColumnTest.cpp)
|
ColumnTest.cpp
|
||||||
|
SessionRecordTest.cpp)
|
||||||
target_link_libraries(tests PRIVATE
|
target_link_libraries(tests PRIVATE
|
||||||
Catch2::Catch2WithMain
|
Catch2::Catch2WithMain
|
||||||
matador
|
matador
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include <matador/sql/condition.hpp>
|
||||||
|
#include <matador/sql/session.hpp>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
using namespace matador::sql;
|
||||||
|
|
||||||
|
TEST_CASE("Create and drop table statement", "[session record]") {
|
||||||
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
|
auto res = s.create()
|
||||||
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255), "age" INTEGER, CONSTRAINT PK_person PRIMARY KEY (id)))");
|
||||||
|
|
||||||
|
res = s.drop()
|
||||||
|
.table("person")
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.second == R"(DROP TABLE "person")");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Execute insert record statement", "[session record]") {
|
||||||
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
|
auto res = s.create()
|
||||||
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 0);
|
||||||
|
|
||||||
|
res = s.insert()
|
||||||
|
.into("person", {"id", "name", "age"})
|
||||||
|
.values({7, "george", 45})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
REQUIRE(res.second == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 45))");
|
||||||
|
|
||||||
|
auto result = s.select({"id", "name", "age"})
|
||||||
|
.from("person")
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
for (const auto& i : result) {
|
||||||
|
REQUIRE(i.size() == 3);
|
||||||
|
REQUIRE(i.at(0).name() == "id");
|
||||||
|
REQUIRE(i.at(0).type() == data_type_t::type_long_long);
|
||||||
|
REQUIRE(i.at(0).as<long long>() == 7);
|
||||||
|
REQUIRE(i.at(1).name() == "name");
|
||||||
|
REQUIRE(i.at(1).type() == data_type_t::type_varchar);
|
||||||
|
REQUIRE(i.at(1).as<std::string>() == "george");
|
||||||
|
REQUIRE(i.at(2).name() == "age");
|
||||||
|
REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int);
|
||||||
|
REQUIRE(i.at(2).as<int>() == 45);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.drop()
|
||||||
|
.table("person")
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Execute update record statement", "[session record]") {
|
||||||
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
|
auto res = s.create()
|
||||||
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 0);
|
||||||
|
|
||||||
|
res = s.insert()
|
||||||
|
.into("person", {"id", "name", "age"})
|
||||||
|
.values({7, "george", 45})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
REQUIRE(res.second == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 45))");
|
||||||
|
|
||||||
|
res = s.update("person")
|
||||||
|
.set({{"id", 7}, {"name", "jane"}, {"age", 35}})
|
||||||
|
.where("id"_col == 7)
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
REQUIRE(res.second == R"(UPDATE "person" SET "id"=7, "name"='jane', "age"=35 WHERE "id" = 7)");
|
||||||
|
|
||||||
|
auto result = s.select({"id", "name", "age"})
|
||||||
|
.from("person")
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
for (const auto& i : result) {
|
||||||
|
REQUIRE(i.size() == 3);
|
||||||
|
REQUIRE(i.at(0).name() == "id");
|
||||||
|
REQUIRE(i.at(0).type() == data_type_t::type_long_long);
|
||||||
|
REQUIRE(i.at(0).as<long long>() == 7);
|
||||||
|
REQUIRE(i.at(1).name() == "name");
|
||||||
|
REQUIRE(i.at(1).type() == data_type_t::type_varchar);
|
||||||
|
REQUIRE(i.at(1).as<std::string>() == "jane");
|
||||||
|
REQUIRE(i.at(2).name() == "age");
|
||||||
|
REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int);
|
||||||
|
REQUIRE(i.at(2).as<int>() == 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.drop().table("person").execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Execute select statement with order by", "[session record]") {
|
||||||
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
|
auto res = s.create()
|
||||||
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
REQUIRE(res.first == 0);
|
||||||
|
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
|
||||||
|
auto result = s.select({"id", "name", "age"})
|
||||||
|
.from("person")
|
||||||
|
.where("id"_col == 8)
|
||||||
|
.order_by("name").desc()
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
std::list<std::string> expected_names {"bob", "george", "jane", "michael"};
|
||||||
|
for (const auto &p : result) {
|
||||||
|
REQUIRE(p.at(1).str() == expected_names.front());
|
||||||
|
expected_names.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
s.drop().table("person").execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Execute select statement with group by and order by", "[session record]") {
|
||||||
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
|
session s(pool);
|
||||||
|
|
||||||
|
auto res = s.create()
|
||||||
|
.table("person", {
|
||||||
|
make_pk_column<unsigned long>("id"),
|
||||||
|
make_column<std::string>("name", 255),
|
||||||
|
make_column<unsigned short>("age")
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
res = s.insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute();
|
||||||
|
REQUIRE(res.first == 1);
|
||||||
|
|
||||||
|
auto result = s.select({alias(count("age"), "age_count"), "age"})
|
||||||
|
.from("person")
|
||||||
|
.group_by("age")
|
||||||
|
.order_by("age_count").asc()
|
||||||
|
.fetch_all();
|
||||||
|
|
||||||
|
std::list<std::pair<int, int>> expected_values {{2, 13}, {2, 45}, {1, 67}};
|
||||||
|
for (const auto &r : result) {
|
||||||
|
REQUIRE(r.at(0).as<int>() == expected_values.front().first);
|
||||||
|
REQUIRE(r.at(1).as<int>() == expected_values.front().second);
|
||||||
|
expected_values.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
s.drop().table("person").execute();
|
||||||
|
}
|
||||||
166
test/session.cpp
166
test/session.cpp
|
|
@ -12,24 +12,6 @@
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
using namespace matador::test;
|
using namespace matador::test;
|
||||||
|
|
||||||
TEST_CASE("Create and drop table statement", "[session]") {
|
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
|
||||||
session s(pool);
|
|
||||||
|
|
||||||
auto res = s.create()
|
|
||||||
.table("person", {
|
|
||||||
make_pk_column<unsigned long>("id"),
|
|
||||||
make_column<std::string>("name", 255),
|
|
||||||
make_column<unsigned short>("age")
|
|
||||||
}).execute();
|
|
||||||
|
|
||||||
REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255), "age" INTEGER, CONSTRAINT PK_person PRIMARY KEY (id)))");
|
|
||||||
|
|
||||||
res = s.drop().table("person").execute();
|
|
||||||
|
|
||||||
REQUIRE(res.second == R"(DROP TABLE "person")");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Create table with foreign key relation", "[session]") {
|
TEST_CASE("Create table with foreign key relation", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
@ -46,104 +28,6 @@ TEST_CASE("Create table with foreign key relation", "[session]") {
|
||||||
s.drop().table("airplane").execute();
|
s.drop().table("airplane").execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute insert record statement", "[session]") {
|
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
|
||||||
session s(pool);
|
|
||||||
|
|
||||||
auto res = s
|
|
||||||
.create()
|
|
||||||
.table("person", {
|
|
||||||
make_pk_column<unsigned long>("id"),
|
|
||||||
make_column<std::string>("name", 255),
|
|
||||||
make_column<unsigned short>("age")
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 0);
|
|
||||||
|
|
||||||
res = s
|
|
||||||
.insert()
|
|
||||||
.into("person", {"id", "name", "age"})
|
|
||||||
.values({7, "george", 45})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 1);
|
|
||||||
REQUIRE(res.second == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 45))");
|
|
||||||
|
|
||||||
auto result = s
|
|
||||||
.select({"id", "name", "age"})
|
|
||||||
.from("person")
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
for (const auto& i : result) {
|
|
||||||
REQUIRE(i.size() == 3);
|
|
||||||
REQUIRE(i.at(0).name() == "id");
|
|
||||||
REQUIRE(i.at(0).type() == data_type_t::type_long_long);
|
|
||||||
REQUIRE(i.at(0).as<long long>() == 7);
|
|
||||||
REQUIRE(i.at(1).name() == "name");
|
|
||||||
REQUIRE(i.at(1).type() == data_type_t::type_varchar);
|
|
||||||
REQUIRE(i.at(1).as<std::string>() == "george");
|
|
||||||
REQUIRE(i.at(2).name() == "age");
|
|
||||||
REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int);
|
|
||||||
REQUIRE(i.at(2).as<int>() == 45);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.drop().table("person").execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Execute update record statement", "[session]") {
|
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
|
||||||
session s(pool);
|
|
||||||
|
|
||||||
auto res = s
|
|
||||||
.create()
|
|
||||||
.table("person", {
|
|
||||||
make_pk_column<unsigned long>("id"),
|
|
||||||
make_column<std::string>("name", 255),
|
|
||||||
make_column<unsigned short>("age")
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 0);
|
|
||||||
|
|
||||||
res = s
|
|
||||||
.insert()
|
|
||||||
.into("person", {"id", "name", "age"})
|
|
||||||
.values({7, "george", 45})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 1);
|
|
||||||
REQUIRE(res.second == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 45))");
|
|
||||||
|
|
||||||
res = s.update("person")
|
|
||||||
.set({{"id", 7}, {"name", "jane"}, {"age", 35}})
|
|
||||||
.where("id"_col == 7)
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 1);
|
|
||||||
REQUIRE(res.second == R"(UPDATE "person" SET "id"=7, "name"='jane', "age"=35 WHERE "id" = 7)");
|
|
||||||
|
|
||||||
auto result = s
|
|
||||||
.select({"id", "name", "age"})
|
|
||||||
.from("person")
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
for (const auto& i : result) {
|
|
||||||
REQUIRE(i.size() == 3);
|
|
||||||
REQUIRE(i.at(0).name() == "id");
|
|
||||||
REQUIRE(i.at(0).type() == data_type_t::type_long_long);
|
|
||||||
REQUIRE(i.at(0).as<long long>() == 7);
|
|
||||||
REQUIRE(i.at(1).name() == "name");
|
|
||||||
REQUIRE(i.at(1).type() == data_type_t::type_varchar);
|
|
||||||
REQUIRE(i.at(1).as<std::string>() == "jane");
|
|
||||||
REQUIRE(i.at(2).name() == "age");
|
|
||||||
REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int);
|
|
||||||
REQUIRE(i.at(2).as<int>() == 35);
|
|
||||||
}
|
|
||||||
|
|
||||||
s.drop().table("person").execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with where clause", "[session]") {
|
TEST_CASE("Execute select statement with where clause", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
@ -213,56 +97,6 @@ TEST_CASE("Execute select statement with where clause", "[session]") {
|
||||||
s.drop().table("person").execute();
|
s.drop().table("person").execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with order by", "[session]") {
|
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
|
||||||
session s(pool);
|
|
||||||
|
|
||||||
auto res = s
|
|
||||||
.create()
|
|
||||||
.table("person", {
|
|
||||||
make_pk_column<unsigned long>("id"),
|
|
||||||
make_column<std::string>("name", 255),
|
|
||||||
make_column<std::string>("color", 63)
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
REQUIRE(res.first == 0);
|
|
||||||
|
|
||||||
auto result = s.select({"id", "name", "color"})
|
|
||||||
.from("person")
|
|
||||||
.where("id"_col == 8)
|
|
||||||
.order_by("name").desc()
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
// Todo: prepare test data
|
|
||||||
|
|
||||||
s.drop().table("person").execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Execute select statement with group by and order by", "[session]") {
|
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
|
||||||
session s(pool);
|
|
||||||
|
|
||||||
auto res = s.create()
|
|
||||||
.table("person", {
|
|
||||||
make_pk_column<unsigned long>("id"),
|
|
||||||
make_column<std::string>("name", 255),
|
|
||||||
make_column<std::string>("color", 63)
|
|
||||||
})
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
auto result = s.select({"id", "name", "color"})
|
|
||||||
.from("person")
|
|
||||||
.where("id"_col == 8)
|
|
||||||
.group_by("color")
|
|
||||||
.order_by("name").asc()
|
|
||||||
.fetch_all();
|
|
||||||
|
|
||||||
// Todo: prepare test data
|
|
||||||
|
|
||||||
s.drop().table("person").execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Execute insert statement", "[session]") {
|
TEST_CASE("Execute insert statement", "[session]") {
|
||||||
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
connection_pool<connection> pool("sqlite://sqlite.db", 4);
|
||||||
session s(pool);
|
session s(pool);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue