diff --git a/backends/sqlite/src/sqlite_query_result.cpp b/backends/sqlite/src/sqlite_query_result.cpp index 331336d..8ff7e68 100644 --- a/backends/sqlite/src/sqlite_query_result.cpp +++ b/backends/sqlite/src/sqlite_query_result.cpp @@ -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"); } case sql::data_type_t::type_unknown: { - value = result_[row_index_][index]; + value = std::string(result_[row_index_][index]); break; } } diff --git a/include/matador/sql/column.hpp b/include/matador/sql/column.hpp index 2405fb1..375a28e 100644 --- a/include/matador/sql/column.hpp +++ b/include/matador/sql/column.hpp @@ -12,15 +12,11 @@ namespace matador::sql { -namespace detail { - - -} class column { public: - explicit column(std::string name) - : name_(std::move(name)) - , attributes_(utils::null_attributes) {} + column(sql_function_t func, std::string name); + column(const char *name, std::string alias = ""); // NOLINT(*-explicit-constructor) + column(std::string name, std::string alias = ""); // NOLINT(*-explicit-constructor) column(const column&) = default; column& operator=(const column&) = default; @@ -50,9 +46,12 @@ public: [[nodiscard]] size_t index() const; [[nodiscard]] const utils::field_attributes& attributes() 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_column() const; + void alias(const std::string &as); + template< typename Type > [[nodiscard]] bool is_type_of() const { return std::holds_alternative(value_); @@ -94,6 +93,9 @@ public: return visitor.result; } + [[nodiscard]] bool is_function() const; + [[nodiscard]] sql_function_t function() const; + private: template void process(Operator &op) @@ -113,6 +115,8 @@ private: utils::field_attributes attributes_; data_type_t type_{data_type_t::type_unknown}; any_type value_; + sql_function_t function_{sql_function_t::NONE}; + std::string alias_; std::string ref_table_; std::string ref_column_; }; diff --git a/include/matador/sql/column_generator.hpp b/include/matador/sql/column_generator.hpp index 21f092c..0a071c8 100644 --- a/include/matador/sql/column_generator.hpp +++ b/include/matador/sql/column_generator.hpp @@ -6,8 +6,8 @@ #include "matador/utils/access.hpp" #include "matador/utils/field_attributes.hpp" -#include "matador/utils/identifier.hpp" +#include #include namespace matador::sql { diff --git a/include/matador/sql/connection.hpp b/include/matador/sql/connection.hpp index 51a7246..ccc9faa 100644 --- a/include/matador/sql/connection.hpp +++ b/include/matador/sql/connection.hpp @@ -30,14 +30,13 @@ public: [[nodiscard]] const connection_info& info() 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 query_result fetch(const std::string &sql) { return query_result(connection_->fetch(sql)); } - [[nodiscard]] query_result fetch(const std::string &sql) const; [[nodiscard]] std::pair execute(const std::string &sql) const; private: diff --git a/include/matador/sql/dialect.hpp b/include/matador/sql/dialect.hpp index c5ec78d..8ee22fc 100644 --- a/include/matador/sql/dialect.hpp +++ b/include/matador/sql/dialect.hpp @@ -10,6 +10,8 @@ namespace matador::sql { +class column; + class dialect { public: @@ -61,6 +63,7 @@ public: using token_to_string_map = std::unordered_map; using data_type_to_string_map = std::unordered_map; + using sql_func_to_string_map = std::unordered_map; public: dialect() = default; @@ -79,7 +82,7 @@ public: * @param str The identifier string to be prepared * @return The prepared string */ - std::string prepare_identifier(const std::string &str) const; + std::string prepare_identifier(const column &col) const; /** * Prepare string literal @@ -196,6 +199,15 @@ private: {data_type_t::type_null, "NULL"}, {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" }, + }; }; } diff --git a/include/matador/sql/query_builder.hpp b/include/matador/sql/query_builder.hpp index 145e0f4..e224604 100644 --- a/include/matador/sql/query_builder.hpp +++ b/include/matador/sql/query_builder.hpp @@ -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 { INNER, OUTER, LEFT, RIGHT }; @@ -103,8 +107,8 @@ public: query_builder& create(); query_builder& drop(); - query_builder& select(std::initializer_list column_names); - query_builder& select(const std::vector &column_names); + query_builder& select(std::initializer_list columns); + query_builder& select(const std::vector &columns); query_builder& insert(); query_builder& update(const std::string &table); query_builder& remove(); diff --git a/include/matador/sql/query_intermediates.hpp b/include/matador/sql/query_intermediates.hpp index f1a511d..007b56b 100644 --- a/include/matador/sql/query_intermediates.hpp +++ b/include/matador/sql/query_intermediates.hpp @@ -136,7 +136,7 @@ protected: class query_select_intermediate : public query_start_intermediate { public: - query_select_intermediate(session &s, std::vector column_names); + query_select_intermediate(session &s, const std::vector& columns); query_from_intermediate from(const std::string &table, const std::string &as = ""); }; diff --git a/include/matador/sql/query_result.hpp b/include/matador/sql/query_result.hpp index 831774b..d2ba69f 100644 --- a/include/matador/sql/query_result.hpp +++ b/include/matador/sql/query_result.hpp @@ -105,6 +105,19 @@ private: query_result *result_{nullptr}; }; +namespace detail { + +template < typename Type > +Type* create_prototype(const record &/*prototype*/) +{ + return new Type{}; +} + +template <> +record* create_prototype(const record &prototype); + +} + template < typename Type > class query_result { @@ -116,8 +129,8 @@ public: explicit query_result(std::unique_ptr impl) : impl_(std::move(impl)) {} - query_result(std::unique_ptr impl, creator_func creator) - : creator_(creator) + query_result(std::unique_ptr impl, record record_prototype) + : record_prototype_(std::move(record_prototype)) , impl_(std::move(impl)) {} iterator begin() { return std::move(++iterator(this)); } @@ -126,7 +139,7 @@ public: private: friend class query_result_iterator; - Type* create() { return creator_(); } + Type* create() { return detail::create_prototype(record_prototype_); } void bind(const Type &obj) { @@ -139,7 +152,7 @@ private: } private: - creator_func creator_ = []{ return new Type; }; + record record_prototype_; std::unique_ptr impl_; }; diff --git a/include/matador/sql/session.hpp b/include/matador/sql/session.hpp index d4534a3..64c2128 100644 --- a/include/matador/sql/session.hpp +++ b/include/matador/sql/session.hpp @@ -1,7 +1,7 @@ #ifndef 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_pool.hpp" #include "matador/sql/query_builder.hpp" @@ -24,9 +24,9 @@ public: template < class Type > query_select_intermediate select() { - return query_select_intermediate{*this, column_name_generator::generate()}; + return query_select_intermediate{*this, column_generator::generate(table_repository_)}; } - query_select_intermediate select(std::initializer_list column_names); + query_select_intermediate select(std::initializer_list columns); query_insert_intermediate insert(); query_update_intermediate update(const std::string &table); query_delete_intermediate remove(); diff --git a/include/matador/sql/types.hpp b/include/matador/sql/types.hpp index cc0d9c8..ad3d6c1 100644 --- a/include/matador/sql/types.hpp +++ b/include/matador/sql/types.hpp @@ -53,6 +53,16 @@ enum struct database_type_t : uint8_t { type_unknown /*!< Data type unknown */ }; +enum class sql_function_t { + NONE, + COUNT, + AVG, + SUM, + MIN, + MAX +}; + + /** * @tparam T The type of the traits * @brief Type traits for database types diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f37d7c..bbcfe39 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,7 +17,8 @@ set(SQL_SOURCES sql/key_value_generator.cpp sql/fk_value_extractor.cpp sql/table_repository.cpp - sql/any_type_to_visitor.cpp) + sql/any_type_to_visitor.cpp + sql/query_result.cpp) set(SQL_HEADER ../include/matador/sql/dialect.hpp diff --git a/src/sql/any_type_to_visitor.cpp b/src/sql/any_type_to_visitor.cpp index b5fe425..9a79a23 100644 --- a/src/sql/any_type_to_visitor.cpp +++ b/src/sql/any_type_to_visitor.cpp @@ -9,7 +9,7 @@ void convert(std::string &dest, bool source) void convert(std::string &dest, const char *source) { - dest = source; + dest.assign(source); } long long to_long_long(const char *source) diff --git a/src/sql/column.cpp b/src/sql/column.cpp index d5e8766..a5be917 100644 --- a/src/sql/column.cpp +++ b/src/sql/column.cpp @@ -1,28 +1,24 @@ -#include - #include "matador/sql/column.hpp" +#include + namespace matador::sql { -const column::data_type_index column::data_type_index_ { - data_type_t::type_char, - data_type_t::type_short, - data_type_t::type_int, - data_type_t::type_long, - data_type_t::type_long_long, - data_type_t::type_unsigned_char, - data_type_t::type_unsigned_short, - data_type_t::type_unsigned_int, - data_type_t::type_unsigned_long, - data_type_t::type_unsigned_long_long, - data_type_t::type_float, - data_type_t::type_double, - data_type_t::type_bool, - data_type_t::type_char_pointer, - data_type_t::type_varchar, - data_type_t::type_text, - data_type_t::type_null, -}; +column::column(sql_function_t func, std::string name) +: name_(std::move(name)) +, type_(data_type_t::type_int) +, attributes_(utils::null_attributes) +, function_(func) {} + +column::column(const char *name, std::string alias) +: name_(name) +, attributes_(utils::null_attributes) +, alias_(std::move(alias)) {} + +column::column(std::string name, std::string alias) +: name_(std::move(name)) +, attributes_(utils::null_attributes) +, alias_(std::move(alias)) {} column::column(std::string name, data_type_t type, utils::field_attributes attr) : name_(std::move(name)) @@ -57,6 +53,11 @@ data_type_t column::type() const return type_; } +const std::string &column::alias() const +{ + return alias_; +} + const std::string &column::ref_table() const { return ref_table_; @@ -67,6 +68,11 @@ const std::string &column::ref_column() const return ref_column_; } +void column::alias(const std::string &as) +{ + alias_ = as; +} + std::string column::str() const { any_type_to_visitor visitor; @@ -74,9 +80,19 @@ std::string column::str() const 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) { - 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 ) diff --git a/src/sql/connection.cpp b/src/sql/connection.cpp index 867fb15..a7d5018 100644 --- a/src/sql/connection.cpp +++ b/src/sql/connection.cpp @@ -73,12 +73,6 @@ bool connection::exists(const std::string &table_name) const return connection_->exists(table_name); } -query_result connection::fetch(const std::string &sql) const -{ - auto rec = connection_->describe("person"); - return {connection_->fetch(sql), [rec](){ return new record(rec); }}; -} - std::pair connection::execute(const std::string &sql) const { return {connection_->execute(sql), sql}; diff --git a/src/sql/dialect.cpp b/src/sql/dialect.cpp index 666d4e5..d7e81d1 100644 --- a/src/sql/dialect.cpp +++ b/src/sql/dialect.cpp @@ -1,4 +1,5 @@ #include "matador/sql/dialect.hpp" +#include "matador/sql/column.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); } -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); - quote_identifier(result); + if (!col.is_function()) { + quote_identifier(result); + } else { + return sql_func_map_.at(col.function()) + "(" + result + ")"; + } return result; } diff --git a/src/sql/query_builder.cpp b/src/sql/query_builder.cpp index 2075a6e..bca823f 100644 --- a/src/sql/query_builder.cpp +++ b/src/sql/query_builder.cpp @@ -97,12 +97,12 @@ query_builder& query_builder::drop() { return *this; } -query_builder& query_builder::select(std::initializer_list column_names) +query_builder& query_builder::select(std::initializer_list columns) { - return select(std::vector{column_names}); + return select(std::vector{columns}); } -query_builder& query_builder::select(const std::vector &column_names) +query_builder &query_builder::select(const std::vector &columns) { initialize(command_t::SELECT, state_t::QUERY_SELECT); @@ -111,15 +111,16 @@ query_builder& query_builder::select(const std::vector &column_name query_.prototype.clear(); std::string result; - if (column_names.size() < 2) { - for (const auto &col : column_names) { + if (columns.size() < 2) { + for (const auto &col : columns) { result.append(dialect_.prepare_identifier(col)); - query_.prototype.append(column{col}); + query_.prototype.append(col); } } else { - auto it = column_names.begin(); + auto it = columns.begin(); 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(dialect_.prepare_identifier(*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; } +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}; +} + } \ No newline at end of file diff --git a/src/sql/query_intermediates.cpp b/src/sql/query_intermediates.cpp index 4d1b9ee..d32b0c5 100644 --- a/src/sql/query_intermediates.cpp +++ b/src/sql/query_intermediates.cpp @@ -76,10 +76,10 @@ query_where_intermediate query_from_intermediate::where(const basic_condition &c return query_where_intermediate{session_, builder_.where(cond)}; } -query_select_intermediate::query_select_intermediate(session &s, std::vector column_names) +query_select_intermediate::query_select_intermediate(session &s, const std::vector& columns) : 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) diff --git a/src/sql/query_result.cpp b/src/sql/query_result.cpp new file mode 100644 index 0000000..722e471 --- /dev/null +++ b/src/sql/query_result.cpp @@ -0,0 +1,11 @@ +#include "matador/sql/query_result.hpp" + +namespace matador::sql::detail { + +template<> +record *create_prototype(const record &prototype) +{ + return new record{prototype}; +} + +} \ No newline at end of file diff --git a/src/sql/session.cpp b/src/sql/session.cpp index 6a0c824..aae935d 100644 --- a/src/sql/session.cpp +++ b/src/sql/session.cpp @@ -20,10 +20,9 @@ query_drop_intermediate session::drop() return query_drop_intermediate{*this}; } -query_select_intermediate session::select(std::initializer_list column_names) +query_select_intermediate session::select(std::initializer_list columns) { - - return query_select_intermediate{*this, column_names}; + return {*this, columns}; } query_insert_intermediate session::insert() @@ -52,7 +51,8 @@ query_result session::fetch(const query &q) const it = prototypes_.emplace(q.table_name, c->describe(q.table_name)).first; } auto res = c->call_fetch(q.sql); - return query_result{std::move(res), [it]() { return new record(it->second); }}; + return query_result{std::move(res), q.prototype}; +// return query_result{std::move(res), [it]() { return new record(it->second); }}; } //query_result session::fetch(const std::string &sql) const diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 06da1dc..e789382 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -25,7 +25,8 @@ add_executable(tests builder.cpp models/flight.hpp models/person.hpp AnyTypeToVisitorTest.cpp - ColumnTest.cpp) + ColumnTest.cpp + SessionRecordTest.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain matador diff --git a/test/SessionRecordTest.cpp b/test/SessionRecordTest.cpp new file mode 100644 index 0000000..5e2a473 --- /dev/null +++ b/test/SessionRecordTest.cpp @@ -0,0 +1,200 @@ +#include + +#include +#include + +#include + +using namespace matador::sql; + +TEST_CASE("Create and drop table statement", "[session record]") { + connection_pool pool("sqlite://sqlite.db", 4); + session s(pool); + + auto res = s.create() + .table("person", { + make_pk_column("id"), + make_column("name", 255), + make_column("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 pool("sqlite://sqlite.db", 4); + session s(pool); + + auto res = s.create() + .table("person", { + make_pk_column("id"), + make_column("name", 255), + make_column("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() == 7); + REQUIRE(i.at(1).name() == "name"); + REQUIRE(i.at(1).type() == data_type_t::type_varchar); + REQUIRE(i.at(1).as() == "george"); + REQUIRE(i.at(2).name() == "age"); + REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int); + REQUIRE(i.at(2).as() == 45); + } + + s.drop() + .table("person") + .execute(); +} + +TEST_CASE("Execute update record statement", "[session record]") { + connection_pool pool("sqlite://sqlite.db", 4); + session s(pool); + + auto res = s.create() + .table("person", { + make_pk_column("id"), + make_column("name", 255), + make_column("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() == 7); + REQUIRE(i.at(1).name() == "name"); + REQUIRE(i.at(1).type() == data_type_t::type_varchar); + REQUIRE(i.at(1).as() == "jane"); + REQUIRE(i.at(2).name() == "age"); + REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int); + REQUIRE(i.at(2).as() == 35); + } + + s.drop().table("person").execute(); +} + +TEST_CASE("Execute select statement with order by", "[session record]") { + connection_pool pool("sqlite://sqlite.db", 4); + session s(pool); + + auto res = s.create() + .table("person", { + make_pk_column("id"), + make_column("name", 255), + make_column("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 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 pool("sqlite://sqlite.db", 4); + session s(pool); + + auto res = s.create() + .table("person", { + make_pk_column("id"), + make_column("name", 255), + make_column("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> expected_values {{2, 13}, {2, 45}, {1, 67}}; + for (const auto &r : result) { + REQUIRE(r.at(0).as() == expected_values.front().first); + REQUIRE(r.at(1).as() == expected_values.front().second); + expected_values.pop_front(); + } + + s.drop().table("person").execute(); +} diff --git a/test/session.cpp b/test/session.cpp index c631a27..05dfe4b 100644 --- a/test/session.cpp +++ b/test/session.cpp @@ -12,24 +12,6 @@ using namespace matador::sql; using namespace matador::test; -TEST_CASE("Create and drop table statement", "[session]") { - connection_pool pool("sqlite://sqlite.db", 4); - session s(pool); - - auto res = s.create() - .table("person", { - make_pk_column("id"), - make_column("name", 255), - make_column("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]") { connection_pool pool("sqlite://sqlite.db", 4); session s(pool); @@ -46,104 +28,6 @@ TEST_CASE("Create table with foreign key relation", "[session]") { s.drop().table("airplane").execute(); } -TEST_CASE("Execute insert record statement", "[session]") { - connection_pool pool("sqlite://sqlite.db", 4); - session s(pool); - - auto res = s - .create() - .table("person", { - make_pk_column("id"), - make_column("name", 255), - make_column("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() == 7); - REQUIRE(i.at(1).name() == "name"); - REQUIRE(i.at(1).type() == data_type_t::type_varchar); - REQUIRE(i.at(1).as() == "george"); - REQUIRE(i.at(2).name() == "age"); - REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int); - REQUIRE(i.at(2).as() == 45); - } - - s.drop().table("person").execute(); -} - -TEST_CASE("Execute update record statement", "[session]") { - connection_pool pool("sqlite://sqlite.db", 4); - session s(pool); - - auto res = s - .create() - .table("person", { - make_pk_column("id"), - make_column("name", 255), - make_column("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() == 7); - REQUIRE(i.at(1).name() == "name"); - REQUIRE(i.at(1).type() == data_type_t::type_varchar); - REQUIRE(i.at(1).as() == "jane"); - REQUIRE(i.at(2).name() == "age"); - REQUIRE(i.at(2).type() == matador::sql::data_type_t::type_int); - REQUIRE(i.at(2).as() == 35); - } - - s.drop().table("person").execute(); -} - TEST_CASE("Execute select statement with where clause", "[session]") { connection_pool pool("sqlite://sqlite.db", 4); session s(pool); @@ -213,56 +97,6 @@ TEST_CASE("Execute select statement with where clause", "[session]") { s.drop().table("person").execute(); } -TEST_CASE("Execute select statement with order by", "[session]") { - connection_pool pool("sqlite://sqlite.db", 4); - session s(pool); - - auto res = s - .create() - .table("person", { - make_pk_column("id"), - make_column("name", 255), - make_column("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 pool("sqlite://sqlite.db", 4); - session s(pool); - - auto res = s.create() - .table("person", { - make_pk_column("id"), - make_column("name", 255), - make_column("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]") { connection_pool pool("sqlite://sqlite.db", 4); session s(pool);