added sql function and alias

This commit is contained in:
Sascha Kuehl 2023-11-22 19:57:25 +01:00
parent 145c4dc0a3
commit 72f9d28d0d
22 changed files with 356 additions and 236 deletions

View File

@ -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;
} }
} }

View File

@ -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_;
}; };

View File

@ -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 {

View File

@ -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:

View File

@ -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" },
};
}; };
} }

View File

@ -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();

View File

@ -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 = "");
}; };

View File

@ -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_;
}; };

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 )

View File

@ -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};

View File

@ -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;
} }

View File

@ -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};
}
} }

View File

@ -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)

11
src/sql/query_result.cpp Normal file
View File

@ -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};
}
}

View File

@ -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

View File

@ -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

200
test/SessionRecordTest.cpp Normal file
View File

@ -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();
}

View File

@ -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);