initial matador ng commit

This commit is contained in:
2025-02-02 20:37:12 +01:00
parent 19de5714f4
commit ded3daceb3
378 changed files with 14913 additions and 13431 deletions
+112
View File
@@ -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%'");
}
+235
View File
@@ -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);
// }
+15
View File
@@ -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");
}
}
+21
View File
@@ -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
+36
View File
@@ -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);
}