initial matador ng commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
CPMAddPackage("gh:catchorg/Catch2@3.7.1")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||
|
||||
add_executable(OrmTests
|
||||
backend/test_backend_service.cpp
|
||||
backend/test_backend_service.hpp
|
||||
backend/test_connection.cpp
|
||||
backend/test_connection.hpp
|
||||
query/ConditionTests.cpp
|
||||
query/QueryBuilderTest.cpp
|
||||
query/QueryFixture.cpp
|
||||
query/QueryFixture.hpp
|
||||
sql/ColumnTest.cpp
|
||||
sql/FieldTest.cpp
|
||||
backend/test_result_reader.cpp
|
||||
backend/test_result_reader.hpp
|
||||
backend/test_statement.cpp
|
||||
backend/test_statement.hpp
|
||||
backend/test_parameter_binder.cpp
|
||||
backend/test_parameter_binder.hpp
|
||||
query/QueryTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(OrmTests matador-orm matador-core Catch2::Catch2WithMain)
|
||||
|
||||
target_compile_options(OrmTests PRIVATE -coverage)
|
||||
target_link_options(OrmTests PRIVATE -coverage)
|
||||
|
||||
add_test(NAME OrmTests COMMAND OrmTests)
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "test_backend_service.hpp"
|
||||
#include "test_connection.hpp"
|
||||
|
||||
#include "matador/sql/dialect_builder.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
sql::connection_impl *test_backend_service::create(const sql::connection_info &info)
|
||||
{
|
||||
return noop_connections_.insert(std::make_unique<test_connection>(info)).first->get();
|
||||
}
|
||||
|
||||
void test_backend_service::destroy(sql::connection_impl *impl)
|
||||
{
|
||||
auto it = std::find_if(noop_connections_.begin(), noop_connections_.end(), [impl](const auto &item) {
|
||||
return impl == item.get();
|
||||
});
|
||||
if (it != noop_connections_.end()) {
|
||||
noop_connections_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
const sql::dialect *test_backend_service::dialect() const
|
||||
{
|
||||
static sql::dialect dialect_ = sql::dialect_builder::builder().create().build();
|
||||
return &dialect_;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef NOOP_BACKEND_SERVICE_HPP
|
||||
#define NOOP_BACKEND_SERVICE_HPP
|
||||
|
||||
#include "matador/sql/backend_provider.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
class test_backend_service final : public sql::backend_provider::basic_backend_service {
|
||||
public:
|
||||
sql::connection_impl *create(const sql::connection_info &info) override;
|
||||
void destroy(sql::connection_impl *impl) override;
|
||||
[[nodiscard]] const sql::dialect *dialect() const override;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::unique_ptr<sql::connection_impl>> noop_connections_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //NOOP_BACKEND_SERVICE_HPP
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "test_connection.hpp"
|
||||
#include "test_result_reader.hpp"
|
||||
|
||||
#include "matador/sql/query_context.hpp"
|
||||
#include "matador/sql/record.hpp"
|
||||
|
||||
#include "matador/sql/internal/query_result_impl.hpp"
|
||||
|
||||
#include "matador/sql/interface/statement_impl.hpp"
|
||||
|
||||
#include "matador/utils/string.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace matador::test::orm {
|
||||
test_connection::test_connection(const sql::connection_info &info)
|
||||
: connection_impl(info) {}
|
||||
|
||||
utils::result<void, utils::error> test_connection::open()
|
||||
{
|
||||
is_open_ = true;
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> test_connection::close()
|
||||
{
|
||||
is_open_ = false;
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> test_connection::is_open() const
|
||||
{
|
||||
return utils::ok(is_open_);
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> test_connection::is_valid() const
|
||||
{
|
||||
return is_open();
|
||||
}
|
||||
|
||||
utils::result<utils::version, utils::error> test_connection::client_version() const {
|
||||
return utils::ok(utils::version{1, 2, 3});
|
||||
}
|
||||
|
||||
utils::result<utils::version, utils::error> test_connection::server_version() const {
|
||||
return utils::ok(utils::version{3, 2, 1});
|
||||
}
|
||||
|
||||
utils::result<size_t, utils::error> test_connection::execute(const std::string &/*stmt*/)
|
||||
{
|
||||
return utils::ok(static_cast<size_t>(4));
|
||||
}
|
||||
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_connection::fetch(const sql::query_context &context)
|
||||
{
|
||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<test_result_reader>(), context.prototype, context.prototype.size()));
|
||||
}
|
||||
|
||||
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> test_connection::prepare(const sql::query_context &/*context*/)
|
||||
{
|
||||
return utils::ok(std::unique_ptr<sql::statement_impl>{});
|
||||
}
|
||||
|
||||
utils::result<std::vector<sql::column_definition>, utils::error> test_connection::describe(const std::string &/*table*/)
|
||||
{
|
||||
return utils::ok(std::vector<sql::column_definition>{});
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> test_connection::exists(const std::string &/*schema_name*/, const std::string &/*table_name*/)
|
||||
{
|
||||
return utils::ok(false);
|
||||
}
|
||||
|
||||
std::string test_connection::to_escaped_string(const utils::blob& value) const
|
||||
{
|
||||
return utils::to_string(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef QUERY_NOOP_CONNECTION_HPP
|
||||
#define QUERY_NOOP_CONNECTION_HPP
|
||||
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
class test_connection final : public sql::connection_impl
|
||||
{
|
||||
public:
|
||||
explicit test_connection(const sql::connection_info &info);
|
||||
|
||||
utils::result<void, utils::error> open() override;
|
||||
utils::result<void, utils::error> close() override;
|
||||
[[nodiscard]] utils::result<bool, utils::error> is_open() const override;
|
||||
[[nodiscard]] utils::result<bool, utils::error> is_valid() const override;
|
||||
[[nodiscard]] utils::result<utils::version, utils::error> client_version() const override;
|
||||
[[nodiscard]] utils::result<utils::version, utils::error> server_version() const override;
|
||||
utils::result<size_t, utils::error> execute(const std::string &stmt) override;
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &context) override;
|
||||
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> prepare(const sql::query_context &context) override;
|
||||
utils::result<std::vector<sql::column_definition>, utils::error> describe(const std::string &table) override;
|
||||
utils::result<bool, utils::error> exists(const std::string &schema_name, const std::string &table_name) override;
|
||||
|
||||
[[nodiscard]] std::string to_escaped_string( const utils::blob& value ) const override;
|
||||
|
||||
private:
|
||||
bool is_open_{false};
|
||||
};
|
||||
|
||||
}
|
||||
#endif //QUERY_NOOP_CONNECTION_HPP
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "test_parameter_binder.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
void test_parameter_binder::write_value(size_t pos, const int8_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const int16_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const int32_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const int64_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const uint8_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const uint16_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const uint32_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const uint64_t &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const bool &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const float &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const double &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const time &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const date &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const char *x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const char *x, size_t size) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const std::string &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const std::string &x, size_t size) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const utils::blob &x) {}
|
||||
void test_parameter_binder::write_value(size_t pos, const utils::value &x, size_t size) {}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef TEST_PARAMETER_BINDER_HPP
|
||||
#define TEST_PARAMETER_BINDER_HPP
|
||||
|
||||
#include "matador/utils/attribute_writer.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
class test_parameter_binder final : public utils::attribute_writer {
|
||||
public:
|
||||
void write_value(size_t pos, const int8_t &x) override;
|
||||
void write_value(size_t pos, const int16_t &x) override;
|
||||
void write_value(size_t pos, const int32_t &x) override;
|
||||
void write_value(size_t pos, const int64_t &x) override;
|
||||
void write_value(size_t pos, const uint8_t &x) override;
|
||||
void write_value(size_t pos, const uint16_t &x) override;
|
||||
void write_value(size_t pos, const uint32_t &x) override;
|
||||
void write_value(size_t pos, const uint64_t &x) override;
|
||||
void write_value(size_t pos, const bool &x) override;
|
||||
void write_value(size_t pos, const float &x) override;
|
||||
void write_value(size_t pos, const double &x) override;
|
||||
void write_value(size_t pos, const time &x) override;
|
||||
void write_value(size_t pos, const date &x) override;
|
||||
void write_value(size_t pos, const char *x) override;
|
||||
void write_value(size_t pos, const char *x, size_t size) override;
|
||||
void write_value(size_t pos, const std::string &x) override;
|
||||
void write_value(size_t pos, const std::string &x, size_t size) override;
|
||||
void write_value(size_t pos, const utils::blob &x) override;
|
||||
void write_value(size_t pos, const utils::value &x, size_t size) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //TEST_PARAMETER_BINDER_HPP
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "test_result_reader.hpp"
|
||||
|
||||
#include "matador/utils/value.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
size_t test_result_reader::column_count() const {
|
||||
return 10;
|
||||
}
|
||||
|
||||
const char *test_result_reader::column(size_t index) const {
|
||||
return "";
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> test_result_reader::fetch() { return utils::ok(rows_-- > 0); }
|
||||
|
||||
size_t test_result_reader::start_column_index() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, int8_t &value) {
|
||||
value = -8;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, int16_t &value) {
|
||||
value = -16;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, int32_t &value) {
|
||||
value = -32;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, int64_t &value) {
|
||||
value = -64;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, uint8_t &value) {
|
||||
value = 8;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, uint16_t &value) {
|
||||
value = 16;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, uint32_t &value) {
|
||||
value = 32;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, uint64_t &value) {
|
||||
value = 64;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, bool &value) {
|
||||
value = true;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, float &value) {
|
||||
value = 3.141572f;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, double &value) {
|
||||
value = 2.14159265358979323846;
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, matador::time &value) {
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, matador::date &value) {
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, char *value, const size_t size) {
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, std::string &value) {
|
||||
value = "Lorem ipsum";
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, std::string &value, const size_t size) {
|
||||
value = "Hello world";
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, utils::blob &value) {
|
||||
value = {'b', 'l', 'o', 'b'};
|
||||
}
|
||||
|
||||
void test_result_reader::read_value(const char *id, const size_t index, utils::value &val, const size_t size) {
|
||||
val = "value";
|
||||
}
|
||||
utils::attribute_reader &test_result_reader::result_binder() {
|
||||
return query_result_reader::result_binder();
|
||||
}
|
||||
} // namespace matador::test::orm
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef TEST_RESULT_READER_HPP
|
||||
#define TEST_RESULT_READER_HPP
|
||||
|
||||
#include "matador/sql/interface/query_result_reader.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
class test_result_reader final : public sql::query_result_reader {
|
||||
public:
|
||||
[[nodiscard]] size_t column_count() const override;
|
||||
[[nodiscard]] const char *column(size_t index) const override;
|
||||
[[nodiscard]] utils::result<bool, utils::error> fetch() override;
|
||||
[[nodiscard]] size_t start_column_index() const override;
|
||||
|
||||
void read_value(const char *id, size_t index, int8_t &value) override;
|
||||
void read_value(const char *id, size_t index, int16_t &value) override;
|
||||
void read_value(const char *id, size_t index, int32_t &value) override;
|
||||
void read_value(const char *id, size_t index, int64_t &value) override;
|
||||
void read_value(const char *id, size_t index, uint8_t &value) override;
|
||||
void read_value(const char *id, size_t index, uint16_t &value) override;
|
||||
void read_value(const char *id, size_t index, uint32_t &value) override;
|
||||
void read_value(const char *id, size_t index, uint64_t &value) override;
|
||||
void read_value(const char *id, size_t index, bool &value) override;
|
||||
void read_value(const char *id, size_t index, float &value) override;
|
||||
void read_value(const char *id, size_t index, double &value) override;
|
||||
void read_value(const char *id, size_t index, matador::time &value) override;
|
||||
void read_value(const char *id, size_t index, matador::date &value) override;
|
||||
void read_value(const char *id, size_t index, char *value, size_t size) override;
|
||||
void read_value(const char *id, size_t index, std::string &value) override;
|
||||
void read_value(const char *id, size_t index, std::string &value, size_t size) override;
|
||||
void read_value(const char *id, size_t index, utils::blob &value) override;
|
||||
void read_value(const char *id, size_t index, utils::value &val, size_t size) override;
|
||||
|
||||
protected:
|
||||
attribute_reader &result_binder() override;
|
||||
|
||||
private:
|
||||
uint8_t rows_{5};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //TEST_RESULT_READER_HPP
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "test_statement.hpp"
|
||||
#include "test_result_reader.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
test_statement::test_statement(const sql::query_context &query)
|
||||
: statement_impl(query) {}
|
||||
|
||||
utils::result<size_t, utils::error> test_statement::execute() {
|
||||
return utils::ok(static_cast<size_t>(8));
|
||||
}
|
||||
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_statement::fetch() {
|
||||
return utils::ok(std::make_unique<sql::query_result_impl>(std::make_unique<test_result_reader>(), query_.prototype, query_.prototype.size()));
|
||||
}
|
||||
|
||||
void test_statement::reset() {}
|
||||
|
||||
utils::attribute_writer &test_statement::binder() {
|
||||
return binder_;
|
||||
}
|
||||
|
||||
} // namespace matador::test::orm
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef TEST_STATEMENT_HPP
|
||||
#define TEST_STATEMENT_HPP
|
||||
|
||||
#include "test_parameter_binder.hpp"
|
||||
|
||||
#include "matador/sql/interface/statement_impl.hpp"
|
||||
|
||||
namespace matador::test::orm {
|
||||
|
||||
class test_statement final : public sql::statement_impl {
|
||||
public:
|
||||
explicit test_statement(const sql::query_context &query);
|
||||
utils::result<size_t, utils::error> execute() override;
|
||||
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch() override;
|
||||
void reset() override;
|
||||
|
||||
protected:
|
||||
utils::attribute_writer &binder() override;
|
||||
|
||||
private:
|
||||
test_parameter_binder binder_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //TEST_STATEMENT_HPP
|
||||
@@ -0,0 +1,112 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "matador/query/condition.hpp"
|
||||
|
||||
#include "matador/sql/dialect_builder.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
using namespace matador::query;
|
||||
|
||||
class ConditionFixture {
|
||||
protected:
|
||||
dialect dlc = dialect_builder::builder()
|
||||
.create()
|
||||
.build();
|
||||
query_context ctx;
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test column user defined literal", "[column][literal]") {
|
||||
const auto col = "name"_col;
|
||||
|
||||
REQUIRE(col.name == "name");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test logical condition", "[condition][logical]") {
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
REQUIRE(name_col.name == "name");
|
||||
|
||||
auto cond1 = name_col != "george";
|
||||
|
||||
auto clause = cond1.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "\"name\" <> 'george'");
|
||||
|
||||
auto cond2 = "age"_col != 9;
|
||||
clause = cond2.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "\"age\" <> 9");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test and condition", "[condition][bin][and]") {
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
REQUIRE(name_col.name == "name");
|
||||
|
||||
const auto cond = name_col == "Hans" && name_col == "Dieter";
|
||||
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "(\"name\" = 'Hans' AND \"name\" = 'Dieter')");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test or condition", "[condition][bin][or]") {
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
REQUIRE(name_col.name == "name");
|
||||
|
||||
const auto cond = name_col == "Hans" || name_col == "Dieter";
|
||||
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "\"name\" = 'Hans' OR \"name\" = 'Dieter'");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test not condition", "[condition][not]") {
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
REQUIRE(name_col.name == "name");
|
||||
|
||||
const auto cond = !(name_col != "Hans");
|
||||
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "NOT (\"name\" <> 'Hans')");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test in condition", "[condition][in]") {
|
||||
const auto age_col = "age"_col;
|
||||
|
||||
REQUIRE(age_col.name == "age");
|
||||
auto cond = age_col != 7 && in(age_col, {7,5,5,8});
|
||||
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "(\"age\" <> 7 AND \"age\" IN (7, 5, 5, 8))");
|
||||
|
||||
cond = age_col != 7 && in(age_col, {7});
|
||||
clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "(\"age\" <> 7 AND \"age\" IN (7))");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test in query condition", "[condition][in query]") {
|
||||
const auto age_col = "age"_col;
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
query_context sub_ctx;
|
||||
sub_ctx.sql = R"(SELECT "name" FROM "test")";
|
||||
|
||||
auto cond = age_col != 7 && in(name_col, std::move(sub_ctx));
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "(\"age\" <> 7 AND \"name\" IN (SELECT \"name\" FROM \"test\"))");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test between condition", "[condition][between]") {
|
||||
const auto age_col = "age"_col;
|
||||
|
||||
auto cond = age_col != 7 && between(age_col, 21, 30);
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "(\"age\" <> 7 AND \"age\" BETWEEN 21 AND 30)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ConditionFixture, "Test like condition", "[condition][like]") {
|
||||
const auto name_col = "name"_col;
|
||||
|
||||
auto cond = like(name_col, "%er%");
|
||||
auto clause = cond.evaluate(dlc, ctx);
|
||||
REQUIRE(clause == "\"name\" LIKE '%er%'");
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "QueryFixture.hpp"
|
||||
|
||||
#include <matador/query/condition.hpp>
|
||||
#include <matador/query/query.hpp>
|
||||
|
||||
#include <matador/sql/column_definition.hpp>
|
||||
#include <matador/sql/connection.hpp>
|
||||
#include <matador/sql/table.hpp>
|
||||
|
||||
#include <matador/utils/placeholder.hpp>
|
||||
|
||||
// #include "models/author.hpp"
|
||||
// #include "models/book.hpp"
|
||||
|
||||
using namespace matador::test;
|
||||
using namespace matador::sql;
|
||||
using namespace matador::query;
|
||||
using namespace matador::utils;
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query]") {
|
||||
auto result = query::create()
|
||||
.table({"person"}, {
|
||||
make_pk_column<unsigned long>("id"),
|
||||
make_column<std::string>("name", 255),
|
||||
make_column<unsigned short>("age")
|
||||
}).str(*db);
|
||||
|
||||
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
|
||||
|
||||
result = query::create()
|
||||
.table("person", {
|
||||
make_pk_column<unsigned long>("id"),
|
||||
make_column<std::string>("name", {255, constraints::UNIQUE}, null_option::NOT_NULL),
|
||||
make_column<unsigned short>("age"),
|
||||
make_fk_column<unsigned long>("address", "address", "id")
|
||||
}).str(*db);
|
||||
|
||||
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL UNIQUE, "age" INTEGER NOT NULL, "address" BIGINT NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id), CONSTRAINT FK_person_address FOREIGN KEY (address) REFERENCES address(id)))##");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test drop table sql statement string", "[query]") {
|
||||
const auto result = query::drop()
|
||||
.table("person")
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(DROP TABLE "person")");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string", "[query]") {
|
||||
const auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person")");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test insert sql statement string", "[query]") {
|
||||
const auto result = query::insert()
|
||||
.into("person", {
|
||||
"id", "name", "age"
|
||||
})
|
||||
.values({7UL, "george", 65U})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "age") VALUES (7, 'george', 65))");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test update sql statement string", "[query]") {
|
||||
auto result = query::update("person")
|
||||
.set({
|
||||
{"id", 7UL},
|
||||
{"name", "george"},
|
||||
{"age", 65U}
|
||||
})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65)");
|
||||
|
||||
result = query::update("person")
|
||||
.set({
|
||||
{"id", 7UL},
|
||||
{"name", "george"},
|
||||
{"age", 65U}
|
||||
})
|
||||
.where("id"_col > 9)
|
||||
.order_by("id").asc()
|
||||
.limit(3)
|
||||
.offset(2)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65 WHERE "id" > 9 ORDER BY "id" ASC LIMIT 3 OFFSET 2)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test update limit sql statement", "[query][update][limit]") {
|
||||
const auto result = query::update("person")
|
||||
.set({{"id", 7UL}, {"name", "george"}, {"age", 65U}})
|
||||
.where("name"_col == "george")
|
||||
.order_by("id"_col).asc()
|
||||
.limit(2)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65 WHERE "name" = 'george' ORDER BY "id" ASC LIMIT 2)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test delete sql statement string", "[query]") {
|
||||
const auto result = query::remove().from("person").str(*db);
|
||||
|
||||
REQUIRE(result == R"(DELETE FROM "person")");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test delete limit sql statement", "[query][delete][limit]") {
|
||||
const auto result = query::remove()
|
||||
.from("person")
|
||||
.where("name"_col == "george")
|
||||
.order_by("id"_col).asc()
|
||||
.limit(2)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(DELETE FROM "person" WHERE "name" = 'george' ORDER BY "id" ASC LIMIT 2)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with where clause", "[query]") {
|
||||
auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.where("id"_col == 8 && "age"_col > 50)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person" WHERE ("id" = 8 AND "age" > 50))");
|
||||
|
||||
result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.where("id"_col == _ && "age"_col > 50)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person" WHERE ("id" = ? AND "age" > 50))");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test insert sql statement with placeholder", "[query]") {
|
||||
auto result = query::insert()
|
||||
.into("person", {"id", "name", "age"})
|
||||
.values({_, _, _})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "age") VALUES (?, ?, ?))");
|
||||
|
||||
result = query::insert()
|
||||
.into("person", {"id", "name", "age"})
|
||||
.values({9, "george", _})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "age") VALUES (9, 'george', ?))");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with order by", "[query]") {
|
||||
const auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.order_by("name"_col).asc()
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person" ORDER BY "name" ASC)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with group by", "[query]") {
|
||||
const auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.group_by("age"_col)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person" GROUP BY "age")");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with offset and limit", "[query]") {
|
||||
const auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.order_by("id"_col).asc()
|
||||
.limit(20)
|
||||
.offset(10)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "age" FROM "person" ORDER BY "id" ASC LIMIT 20 OFFSET 10)");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test create, insert and select a blob column", "[query][blob]") {
|
||||
auto result = query::create()
|
||||
.table("person", {
|
||||
make_pk_column<unsigned long>("id"),
|
||||
make_column<std::string>("name", 255),
|
||||
make_column<blob>("data")
|
||||
})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "data" BLOB NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
|
||||
|
||||
result = query::insert()
|
||||
.into("person", {"id", "name", "data"})
|
||||
.values({7UL, "george", blob{1, 'A', 3, 4}})
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "data") VALUES (7, 'george', X'01410304'))");
|
||||
|
||||
result = query::select({"id", "name", "data"})
|
||||
.from("person")
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "id", "name", "data" FROM "person")");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test select statement with join_left", "[query][statement][join_left]") {
|
||||
const auto result = query::select({"f.id", "ap.brand", "f.pilot_name"})
|
||||
.from({"flight", "f"})
|
||||
.join_left({"airplane", "ap"})
|
||||
.on("f.airplane_id"_col == "ap.id"_col)
|
||||
.str(*db);
|
||||
|
||||
REQUIRE(result == R"(SELECT "f"."id", "ap"."brand", "f"."pilot_name" FROM "flight" "f" LEFT JOIN "airplane" "ap" ON "f"."airplane_id" = "ap"."id")");
|
||||
}
|
||||
|
||||
// TEST_CASE_METHOD(QueryFixture, "Select statement with aliased columns", "[query][select][alias]") {
|
||||
// using namespace matador::test;
|
||||
// connection noop("noop://noop.db");
|
||||
// schema scm("noop");
|
||||
// scm.attach<author>("authors");
|
||||
// scm.attach<book>("books");
|
||||
//
|
||||
//
|
||||
// const auto result = query::select<author>(scm)
|
||||
// .from("authors"_tab.as("T01"))
|
||||
// .str(*db);
|
||||
//
|
||||
// const auto expected_sql = R"(SELECT "T01"."id", "T01"."first_name", "T01"."last_name", "T01"."date_of_birth", "T01"."year_of_birth", "T01"."distinguished" FROM "authors" "T01")";
|
||||
//
|
||||
// REQUIRE(result == expected_sql);
|
||||
// }
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "QueryFixture.hpp"
|
||||
|
||||
#include "../backend/test_backend_service.hpp"
|
||||
|
||||
#include "matador/sql/interface/connection_impl.hpp"
|
||||
|
||||
namespace matador::test {
|
||||
|
||||
QueryFixture::QueryFixture() {
|
||||
sql::backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
|
||||
|
||||
db = std::make_unique<sql::connection>("noop://noop.db");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef QUERY_FIXTURE_HPP
|
||||
#define QUERY_FIXTURE_HPP
|
||||
|
||||
#include "matador/sql/connection.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace matador::test {
|
||||
|
||||
class QueryFixture {
|
||||
public:
|
||||
QueryFixture();
|
||||
~QueryFixture() = default;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<sql::connection> db;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_FIXTURE_HPP
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <matador/query/query.hpp>
|
||||
|
||||
#include "QueryFixture.hpp"
|
||||
|
||||
using namespace matador::test;
|
||||
using namespace matador::query;
|
||||
|
||||
TEST_CASE_METHOD(QueryFixture, "Test simple query", "[query][fetch]") {
|
||||
auto result = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.fetch_all(*db);
|
||||
|
||||
REQUIRE(result.is_ok());
|
||||
|
||||
for (const auto& row : *result) {
|
||||
REQUIRE(row.size() == 3);
|
||||
}
|
||||
|
||||
auto single = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.fetch_one(*db);
|
||||
|
||||
REQUIRE(single.is_ok());
|
||||
REQUIRE(single.value().has_value());
|
||||
REQUIRE(single.value().value().size() == 3);
|
||||
|
||||
auto val = query::select({"id", "name", "age"})
|
||||
.from("person")
|
||||
.fetch_value<int>(*db);
|
||||
|
||||
REQUIRE(val.is_ok());
|
||||
REQUIRE(val.value().has_value());
|
||||
// REQUIRE(val.value().value() == -1);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "matador/sql/column_definition.hpp"
|
||||
|
||||
using namespace matador::sql;
|
||||
using namespace matador::utils;
|
||||
|
||||
TEST_CASE("Test create empty column", "[column]") {
|
||||
column_definition c("name");
|
||||
|
||||
REQUIRE(c.name() == "name");
|
||||
REQUIRE(c.index() == -1);
|
||||
REQUIRE(c.type() == basic_type::type_null);
|
||||
REQUIRE(c.ref_table().empty());
|
||||
REQUIRE(c.ref_column().empty());
|
||||
|
||||
c.set(std::string{"george"}, 255);
|
||||
REQUIRE(c.type() == basic_type::type_varchar);
|
||||
REQUIRE(c.as<std::string>() == "george");
|
||||
|
||||
c.set(7);
|
||||
REQUIRE(c.type() == basic_type::type_int32);
|
||||
REQUIRE(c.as<std::string>() == "7");
|
||||
REQUIRE(c.as<long>() == 7);
|
||||
REQUIRE(c.str() == "7");
|
||||
}
|
||||
|
||||
TEST_CASE("Test copy and move column", "[column]") {
|
||||
column_definition c("name");
|
||||
c.set(std::string{"george"}, 255);
|
||||
REQUIRE(c.name() == "name");
|
||||
REQUIRE(c.index() == -1);
|
||||
REQUIRE(c.ref_table().empty());
|
||||
REQUIRE(c.ref_column().empty());
|
||||
REQUIRE(c.type() == basic_type::type_varchar);
|
||||
REQUIRE(c.as<std::string>() == "george");
|
||||
REQUIRE(c.attributes().size() == 255);
|
||||
|
||||
auto c2 = c;
|
||||
REQUIRE(c2.name() == "name");
|
||||
REQUIRE(c2.index() == -1);
|
||||
REQUIRE(c2.ref_table().empty());
|
||||
REQUIRE(c2.ref_column().empty());
|
||||
REQUIRE(c2.type() == basic_type::type_varchar);
|
||||
REQUIRE(c2.as<std::string>() == "george");
|
||||
REQUIRE(c2.attributes().size() == 255);
|
||||
|
||||
auto c3 = std::move(c2);
|
||||
REQUIRE(c3.name() == "name");
|
||||
REQUIRE(c3.index() == -1);
|
||||
REQUIRE(c3.ref_table().empty());
|
||||
REQUIRE(c3.ref_column().empty());
|
||||
REQUIRE(c3.type() == basic_type::type_varchar);
|
||||
REQUIRE(c3.as<std::string>() == "george");
|
||||
REQUIRE(c3.attributes().size() == 255);
|
||||
|
||||
REQUIRE(c2.name().empty());
|
||||
REQUIRE(c2.index() == -1);
|
||||
REQUIRE(c2.ref_table().empty());
|
||||
REQUIRE(c2.ref_column().empty());
|
||||
REQUIRE(c2.type() == basic_type::type_null);
|
||||
// REQUIRE(!c2.as<std::string>().has_value());
|
||||
REQUIRE(c2.attributes().size() == 255);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "matador/sql/field.hpp"
|
||||
|
||||
using namespace matador;
|
||||
|
||||
TEST_CASE("Test field", "[field]") {
|
||||
sql::field f("name");
|
||||
|
||||
REQUIRE(f.name() == "name");
|
||||
REQUIRE(f.index() == -1);
|
||||
REQUIRE(f.is_null());
|
||||
REQUIRE(!f.is_integer());
|
||||
REQUIRE(!f.is_floating_point());
|
||||
REQUIRE(!f.is_blob());
|
||||
REQUIRE(!f.is_bool());
|
||||
REQUIRE(!f.is_string());
|
||||
|
||||
f = 7UL;
|
||||
REQUIRE(!f.is_null());
|
||||
REQUIRE(f.is_integer());
|
||||
REQUIRE(!f.is_floating_point());
|
||||
REQUIRE(!f.is_blob());
|
||||
REQUIRE(!f.is_bool());
|
||||
REQUIRE(!f.is_string());
|
||||
|
||||
auto int_val = f.as<int>();
|
||||
REQUIRE(int_val.has_value());
|
||||
REQUIRE(int_val.value() == 7);
|
||||
auto float_val = f.as<float>();
|
||||
REQUIRE(float_val.has_value());
|
||||
REQUIRE(float_val.value() == 7.0);
|
||||
auto str_val = f.as<std::string>();
|
||||
REQUIRE(str_val.has_value());
|
||||
REQUIRE(str_val.value() == "7");
|
||||
auto bool_val = f.as<bool>();
|
||||
REQUIRE(bool_val.has_value());
|
||||
REQUIRE(bool_val.value());
|
||||
|
||||
f = sql::field("name", utils::blob{ 7,8,6,5,4,3 }, 0, 1);
|
||||
REQUIRE(f.index() == 1);
|
||||
REQUIRE(!f.is_null());
|
||||
REQUIRE(!f.is_integer());
|
||||
REQUIRE(!f.is_floating_point());
|
||||
REQUIRE(f.is_blob());
|
||||
REQUIRE(!f.is_bool());
|
||||
REQUIRE(!f.is_string());
|
||||
|
||||
auto blob_val = f.as<utils::blob>();
|
||||
REQUIRE(blob_val.has_value());
|
||||
REQUIRE(blob_val.value() == utils::blob{ 7,8,6,5,4,3 });
|
||||
|
||||
REQUIRE(!f.as<std::string>().has_value());
|
||||
}
|
||||
Reference in New Issue
Block a user