query compiler progress

This commit is contained in:
Sascha Kuehl 2024-02-18 18:12:00 +01:00
parent b966a7a1a7
commit a3f467a5a8
62 changed files with 1934 additions and 641 deletions

View File

@ -58,7 +58,7 @@ std::unique_ptr<sql::query_result_impl> postgres_connection::fetch(const std::st
auto type = PQftype(res, i);
auto size = PQfmod(res, i);
// std::cout << "column " << col_name << ", type " << type << " (size: " << size << ")\n";
prototype.append({col_name});
prototype.append(sql::column_definition{col_name});
}
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), std::move(prototype)));
}

View File

@ -65,7 +65,7 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values
if (context->prototype.empty()) {
for(int i = 0; i < column_count; ++i) {
context->prototype.append(sql::column{columns[i]});
context->prototype.append(sql::column_definition{columns[i]});
}
}

View File

@ -3,6 +3,7 @@
#include "matador/sql/column.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/query_builder.hpp"
#include "connection.hpp"
@ -29,7 +30,7 @@ protected:
private:
void drop_table_if_exists(const std::string &table_name) {
if (db.exists(table_name)) {
db.drop().table(table_name).execute();
db.query().drop().table(table_name).execute();
}
}
};
@ -39,7 +40,7 @@ using namespace matador::sql;
TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[session][record]")
{
REQUIRE(!db.exists("person"));
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -49,7 +50,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi
REQUIRE(db.exists("person"));
db.drop()
db.query().drop()
.table("person")
.execute();
@ -58,7 +59,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi
TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with foreign key", "[session][record]")
{
db.create()
db.query().create()
.table("airplane", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("brand", 255),
@ -68,7 +69,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore
REQUIRE(db.exists("airplane"));
db.create()
db.query().create()
.table("flight", {
make_pk_column<unsigned long>("id"),
make_fk_column<unsigned long>("airplane_id", "airplane", "id"),
@ -78,13 +79,13 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore
REQUIRE(db.exists("flight"));
db.drop()
db.query().drop()
.table("flight")
.execute();
REQUIRE(!db.exists("flight"));
db.drop()
db.query().drop()
.table("airplane")
.execute();
@ -93,7 +94,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore
TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -101,14 +102,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi
})
.execute();
auto res = db.insert()
auto res = db.query().insert()
.into("person", {"id", "name", "age"})
.values({7, "george", 45})
.execute();
REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"})
auto result = db.query().select({"id", "name", "age"})
.from("person")
.fetch_all();
@ -125,14 +126,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi
REQUIRE(i.at(2).template as<int>() == 45);
}
db.drop()
db.query().drop()
.table("person")
.execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with foreign key", "[session][record]")
{
db.create()
db.query().create()
.table("airplane", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("brand", 255),
@ -140,7 +141,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore
})
.execute();
db.create()
db.query().create()
.table("flight", {
make_pk_column<unsigned long>("id"),
make_fk_column<unsigned long>("airplane_id", "airplane", "id"),
@ -148,23 +149,23 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore
})
.execute();
auto res = db.insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute();
auto res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute();
REQUIRE(res == 1);
res = db.insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute();
res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute();
REQUIRE(res == 1);
res = db.insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute();
res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute();
REQUIRE(res == 1);
auto count = db.select({count_all()}).from("airplane").fetch_value<int>();
auto count = db.query().select({count_all()}).from("airplane").fetch_value<int>();
REQUIRE(count == 3);
res = db.insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute();
res = db.query().insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute();
REQUIRE(res == 1);
db.drop().table("flight").execute();
db.drop().table("airplane").execute();
db.query().drop().table("flight").execute();
db.query().drop().table("airplane").execute();
REQUIRE(!db.exists("flight"));
REQUIRE(!db.exists("airplane"));
@ -172,7 +173,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore
TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -180,14 +181,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
})
.execute();
auto res = db.insert()
auto res = db.query().insert()
.into("person", {"id", "name", "age"})
.values({7, "george", 45})
.execute();
REQUIRE(res == 1);
res = db.update("person")
res = db.query().update("person")
.set({{"id", 7},
{"name", "jane"},
{"age", 35}})
@ -196,7 +197,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"})
auto result = db.query().select({"id", "name", "age"})
.from("person")
.fetch_all();
@ -213,12 +214,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
REQUIRE(i.at(2).as<int>() == 35);
}
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -226,16 +227,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec
})
.execute();
auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"})
auto result = db.query().select({"id", "name", "age"})
.from("person")
.fetch_all();
@ -246,22 +247,22 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec
}
REQUIRE(expected_names.empty());
auto rec = db.select({"id", "name", "age"})
auto rec = db.query().select({"id", "name", "age"})
.from("person")
.fetch_one();
REQUIRE(rec.at(1).str() == "george");
auto name = db.select({"name"})
auto name = db.query().select({"name"})
.from("person")
.fetch_value<std::string>();
REQUIRE(name == "george");
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -269,16 +270,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by",
})
.execute();
auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"})
auto result = db.query().select({"id", "name", "age"})
.from("person")
.order_by("name").asc()
.fetch_all();
@ -290,12 +291,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by",
}
REQUIRE(expected_names.empty());
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by and order by", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -303,18 +304,18 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an
})
.execute();
auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute();
REQUIRE(res == 1);
auto result = db.select({alias(count("age"), "age_count"), "age"})
auto result = db.query().select({alias(count("age"), "age_count"), "age"})
.from("person")
.group_by("age")
.order_by("age_count").desc()
@ -329,41 +330,41 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an
expected_values.pop_front();
}
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Execute delete statement", "[session][record]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
make_column<unsigned short>("age")
}).execute();
auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute();
REQUIRE(res == 1);
res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute();
res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute();
REQUIRE(res == 1);
auto count = db.select({count_all()}).from("person").fetch_value<int>();
auto count = db.query().select({count_all()}).from("person").fetch_value<int>();
REQUIRE(count == 2);
res = db.remove()
res = db.query().remove()
.from("person")
.where("id"_col == 1)
.execute();
REQUIRE(res == 1);
count = db.select({count_all()}).from("person").fetch_value<int>();
count = db.query().select({count_all()}).from("person").fetch_value<int>();
REQUIRE(count == 1);
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][record]") {
db.create()
db.query().create()
.table("quotes", {
make_column<std::string>("from", 255),
make_column<std::string>("to", 255)
@ -379,19 +380,19 @@ TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][recor
REQUIRE(field.type() == types[field.index()]);
}
db.insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute();
db.query().insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute();
auto res = db.select({"from", "to"}).from("quotes").fetch_one();
auto res = db.query().select({"from", "to"}).from("quotes").fetch_one();
REQUIRE("Berlin" == res.at("from").str());
REQUIRE("London" == res.at("to").str());
db.update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute();
db.query().update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute();
res = db.select({"from", "to"}).from("quotes").fetch_one();
res = db.query().select({"from", "to"}).from("quotes").fetch_one();
REQUIRE("Hamburg" == res.at("from").str());
REQUIRE("New York" == res.at("to").str());
db.drop().table("quotes").execute();
db.query().drop().table("quotes").execute();
}

View File

@ -1,7 +1,8 @@
#include "catch2/catch_test_macros.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/query_builder.hpp"
#include "matador/sql/session.hpp"
#include "connection.hpp"
@ -36,27 +37,27 @@ private:
void drop_table_if_exists(const std::string &table_name)
{
if (db.exists(table_name)) {
db.drop().table(table_name).execute();
db.query().drop().table(table_name).execute();
}
}
};
TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[session]")
{
db.create()
db.query().create()
.table<airplane>("airplane")
.execute();
REQUIRE(db.exists("airplane"));
db.create()
db.query().create()
.table<flight>("flight")
.execute();
REQUIRE(db.exists("flight"));
db.drop().table("flight").execute();
db.drop().table("airplane").execute();
db.query().drop().table("flight").execute();
db.query().drop().table("airplane").execute();
REQUIRE(!db.exists("flight"));
REQUIRE(!db.exists("airplane"));
@ -64,20 +65,20 @@ TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[sess
TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[session]")
{
db.create()
db.query().create()
.table<person>("person")
.execute();
person george{7, "george", 45};
george.image.push_back(37);
auto res = db.insert()
auto res = db.query().insert()
.into("person", george)
.execute();
REQUIRE(res == 1);
// fetch person as record
auto result_record = db.select<person>()
auto result_record = db.query().select<person>()
.from("person")
.where("id"_col == 7)
.fetch_all();
@ -96,7 +97,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[
}
// fetch person as person
auto result_person = db.select<person>()
auto result_person = db.query().select<person>()
.from("person")
.where("id"_col == 7)
.fetch_all<person>();
@ -107,12 +108,12 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[
REQUIRE(i.age == 45);
}
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
{
db.create()
db.query().create()
.table("person", {
make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255),
@ -120,7 +121,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
})
.execute();
auto res = db.insert()
auto res = db.query().insert()
.into("person", {{"", "id", ""}, {"", "name", ""}, {"", "color", ""}})
.values({7, "george", "green"})
.execute();
@ -128,7 +129,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
REQUIRE(res == 1);
// fetch person as record
auto result_record = db.select({"id", "name", "color"})
auto result_record = db.query().select({"id", "name", "color"})
.from("person")
.where("id"_col == 7)
.fetch_all();
@ -146,16 +147,16 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
REQUIRE(i.at(2).as<std::string>() == "green");
}
db.drop().table("person").execute();
db.query().drop().table("person").execute();
}
TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]")
{
db.create()
db.query().create()
.table<airplane>("airplane")
.execute();
db.create()
db.query().create()
.table<flight>("flight")
.execute();
@ -166,35 +167,35 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]"
};
for (const auto &plane: planes) {
auto res = db.insert().into<airplane>("airplane").values(*plane).execute();
auto res = db.query().insert().into<airplane>("airplane").values(*plane).execute();
REQUIRE(res == 1);
}
auto count = db.select({count_all()}).from("airplane").fetch_value<int>();
auto count = db.query().select({count_all()}).from("airplane").fetch_value<int>();
REQUIRE(count == 3);
flight f4711{4, planes.at(1), "hans"};
auto res = db.insert().into<flight>("flight").values(f4711).execute();
auto res = db.query().insert().into<flight>("flight").values(f4711).execute();
REQUIRE(res == 1);
auto f = *db.select<flight>().from("flight").fetch_all<flight>().begin();
auto f = *db.query().select<flight>().from("flight").fetch_all<flight>().begin();
REQUIRE(f.id == 4);
REQUIRE(f.pilot_name == "hans");
REQUIRE(f.airplane.get() != nullptr);
REQUIRE(f.airplane->id == 2);
db.drop().table("flight").execute();
db.drop().table("airplane").execute();
db.query().drop().table("flight").execute();
db.query().drop().table("airplane").execute();
}
TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[session][join]")
TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left", "[session][join_left]")
{
db.create()
db.query().create()
.table<airplane>("airplane")
.execute();
db.create()
db.query().create()
.table<flight>("flight")
.execute();
@ -205,11 +206,11 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[
};
for (const auto &plane: planes) {
auto res = db.insert().into<airplane>("airplane").values(*plane).execute();
auto res = db.query().insert().into<airplane>("airplane").values(*plane).execute();
REQUIRE(res == 1);
}
auto count = db.select({count_all()}).from("airplane").fetch_value<int>();
auto count = db.query().select({count_all()}).from("airplane").fetch_value<int>();
REQUIRE(count == 3);
std::vector<entity<flight>> flights{
@ -220,20 +221,20 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[
};
for (const auto &f: flights) {
auto res = db.insert().into<flight>("flight").values(*f).execute();
auto res = db.query().insert().into<flight>("flight").values(*f).execute();
REQUIRE(res == 1);
}
auto f = *db.select<flight>().from("flight").fetch_all<flight>().begin();
auto f = *db.query().select<flight>().from("flight").fetch_all<flight>().begin();
REQUIRE(f.id == 4);
REQUIRE(f.pilot_name == "hans");
REQUIRE(f.airplane.get() != nullptr);
REQUIRE(f.airplane->id == 1);
auto result = db.select({"f.id", "ap.brand", "ap.model", "f.pilot_name"})
.from("flight", "f")
.join("airplane", "ap")
.on("f.airplane_id", "ap.id")
auto result = db.query().select({"f.id", "ap.brand", "ap.model", "f.pilot_name"})
.from("flight", "f")
.join_left("airplane", "ap")
.on("f.airplane_id"_col == "ap.id"_col)
.order_by("f.id").asc()
.fetch_all();
@ -250,7 +251,7 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[
REQUIRE(r.at(3).as<std::string>() == expected_result[index++].second);
}
db.drop().table("flight").execute();
db.drop().table("airplane").execute();
db.query().drop().table("flight").execute();
db.query().drop().table("airplane").execute();
}

View File

@ -1,6 +1,6 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/connection.hpp"
@ -18,7 +18,7 @@ public:
: db(matador::test::connection::dns)
{
db.open();
db.create().table<airplane>("airplane").execute();
db.query().create().table<airplane>("airplane").execute();
}
~StatementTestFixture()
@ -38,7 +38,7 @@ protected:
private:
void drop_table_if_exists(const std::string &table_name) {
if (db.exists(table_name)) {
db.drop().table(table_name).execute();
db.query().drop().table(table_name).execute();
}
}
@ -47,7 +47,7 @@ private:
TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement]")
{
SECTION("Insert with prepared statement and placeholder") {
auto stmt = db.insert()
auto stmt = db.query().insert()
.into<airplane>("airplane")
.values<airplane>().prepare();
@ -57,7 +57,7 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement
stmt.reset();
}
auto result = db.select<airplane>().from("airplane").fetch_all<airplane>();
auto result = db.query().select<airplane>().from("airplane").fetch_all<airplane>();
size_t index{0};
for (const auto &i: result) {
@ -69,11 +69,11 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement
SECTION("Select with prepared statement") {
for (const auto &plane: planes) {
auto res = db.insert().into<airplane>("airplane").values(*plane).execute();
auto res = db.query().insert().into<airplane>("airplane").values(*plane).execute();
REQUIRE(res == 1);
}
auto stmt = db.select<airplane>().from("airplane").where("brand"_col == _).prepare();
auto stmt = db.query().select<airplane>().from("airplane").where("brand"_col == _).prepare();
stmt.bind(0, "Airbus");

View File

@ -17,14 +17,14 @@ public:
: db(matador::test::connection::dns)
{
db.open();
db.create()
db.query().create()
.table<location>("location")
.execute();
}
~TypeTraitsTestFixture()
{
db.drop().table("location").execute();
db.query().drop().table("location").execute();
}
protected:
@ -33,7 +33,7 @@ protected:
private:
void drop_table_if_exists(const std::string &table_name) {
if (db.exists(table_name)) {
db.drop().table(table_name).execute();
db.query().drop().table(table_name).execute();
}
}
};
@ -85,10 +85,10 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ
SECTION("Insert and select with direct execution") {
location loc{1, "center", {1, 2, 3}, Color::Black};
auto res = db.insert().into<location>("location").values(loc).execute();
auto res = db.query().insert().into<location>("location").values(loc).execute();
REQUIRE(res == 1);
auto result = db.select<location>().from("location").fetch_all<location>();
auto result = db.query().select<location>().from("location").fetch_all<location>();
for (const auto &l: result) {
REQUIRE(l.name == "center");
@ -98,11 +98,11 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ
SECTION("Insert and select with prepared statement") {
location loc{1, "center", {1, 2, 3}, Color::Black};
auto stmt = db.insert().into<location>("location").values<location>().prepare();
auto stmt = db.query().insert().into<location>("location").values<location>().prepare();
auto res = stmt.bind(loc).execute();
REQUIRE(res == 1);
auto result = db.select<location>().from("location").
auto result = db.query().select<location>().from("location").
template fetch_all<location>();
for (const auto &l: result) {

View File

@ -1,9 +1,74 @@
#include <cstdlib>
#include <iostream>
#include "matador/sql/column.hpp"
#include "matador/sql/condition.hpp"
#include "matador/sql/schema.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/entity.hpp"
#include "matador/utils/access.hpp"
#include <string>
int main() {
const std::string env_var {"MATADOR_BACKENDS_PATH"};
struct author
{
unsigned long id{};
std::string first_name;
std::string last_name;
std::string date_of_birth;
unsigned short year_of_birth{};
bool distinguished{false};
template < typename Operator >
void process(Operator &op) {
namespace field = matador::utils::access;
field::primary_key(op, "id", id);
field::attribute(op, "first_name", first_name, 63);
field::attribute(op, "last_name", last_name, 63);
field::attribute(op, "date_of_birth", date_of_birth, 31);
field::attribute(op, "year_of_birth", year_of_birth);
field::attribute(op, "distinguished", distinguished);
}
};
struct book
{
unsigned long id{};
matador::sql::entity<author> book_author;
std::string title;
unsigned short published_in{};
template < typename Operator >
void process(Operator &op) {
namespace field = matador::utils::access;
field::primary_key(op, "id", id);
field::attribute(op, "title", title, 511);
field::attribute(op, "published_in", published_in);
}
};
int main()
{
using namespace matador::sql;
const std::string env_var{"MATADOR_BACKENDS_PATH"};
std::string dns;
auto s = std::make_shared<schema>();
connection c(dns, s);
auto books = c.query()
.select<book>({"author.name"})
.from("book")
.join_left("author")
.on("book.author_id"_col == "author.id"_col)
.where("book.published_in"_col < 2008 && "author.name"_col == "Michael Crichton")
.order_by("book.title").asc()
.fetch_all<book>();
// SELECT book.title, book.id, book.author_id, book.published_in, author.name
// FROM book
// INNER JOIN author ON book.author_id = author.id
// WHERE book.published_in < 2008 AND author.name = "Michael Crichton"
// ORDER BY "book.title" ASC
// char var[1024];
// size_t len{};

View File

@ -0,0 +1,25 @@
#ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP
#include <string>
namespace matador::query {
class column {
public:
column(const char *name); // NOLINT(*-explicit-constructor)
column(std::string name); // NOLINT(*-explicit-constructor)
column(std::string table_name, std::string name, std::string as);
column& as(std::string a);
std::string table;
std::string name;
std::string alias;
};
column operator "" _col(const char *name, size_t len);
}
#endif //QUERY_COLUMN_HPP

View File

@ -0,0 +1,22 @@
#ifndef QUERY_QUERY_HPP
#define QUERY_QUERY_HPP
#include "matador/query/query_parts.hpp"
namespace matador::query {
class connection;
class query
{
public:
explicit query(connection &c);
query& select(const std::vector<column> &columns);
query& from(const std::string &table, const std::string &as = "");
private:
connection &connection_;
};
}
#endif //QUERY_QUERY_HPP

View File

@ -0,0 +1,24 @@
#ifndef QUERY_QUERY_BUILDER_HPP
#define QUERY_QUERY_BUILDER_HPP
#include "matador/query/column.hpp"
#include "matador/query/query_intermediates.hpp"
#include "matador/sql/schema.hpp"
#include <memory>
namespace matador::query {
class query_builder
{
public:
explicit query_builder(const std::shared_ptr<sql::schema> &scm);
query_select_intermediate select(std::initializer_list<column> columns);
private:
std::shared_ptr<sql::schema> schema_;
};
}
#endif //QUERY_QUERY_BUILDER_HPP

View File

@ -0,0 +1,37 @@
#ifndef QUERY_QUERY_COMPILER_HPP
#define QUERY_QUERY_COMPILER_HPP
#include "matador/query/query_part_visitor.hpp"
#include "matador/query/query_parts.hpp"
#include <typeindex>
#include <string>
namespace matador::sql {
class dialect;
}
namespace matador::query {
struct query_data;
class query_compiler : public query_part_visitor
{
public:
explicit query_compiler(sql::dialect& d);
std::string compile(const query_data *data);
private:
void visit(query_select_part &select_part) override;
void visit(query_from_part &from_part) override;
private:
sql::dialect &dialect_;
std::string sql_;
};
}
#endif //QUERY_QUERY_COMPILER_HPP

View File

@ -0,0 +1,24 @@
#ifndef QUERY_QUERY_DATA_HPP
#define QUERY_QUERY_DATA_HPP
#include "matador/query/query_parts.hpp"
#include "matador/query/sql_commands.hpp"
#include "matador/query/table.hpp"
#include <memory>
#include <vector>
namespace matador::query {
struct query_data
{
SqlCommands command;
std::vector<std::unique_ptr<query_part>> parts;
std::vector<column> columns;
std::unordered_map<std::type_index, table_data> table_map_by_index;
using table_data_ref = std::reference_wrapper<table_data>;
std::unordered_map<std::string, table_data_ref> table_map_by_name;
};
}
#endif //QUERY_QUERY_DATA_HPP

View File

@ -0,0 +1,132 @@
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
#define QUERY_QUERY_INTERMEDIATES_HPP
#include "matador/sql/schema.hpp"
#include <string>
#include <memory>
namespace matador::sql {
class basic_condition;
}
namespace matador::query {
class query_from_intermediate;
class query_join_intermediate;
class query_on_intermediate;
class query_where_intermediate;
class query_group_by_intermediate;
class query_order_by_intermediate;
class query_order_direction_intermediate;
class query_offset_intermediate;
class query_limit_intermediate;
class query_intermediate
{
public:
explicit query_intermediate(const std::shared_ptr<sql::schema> &scm);
protected:
sql::schema& schema() const;
private:
std::shared_ptr<sql::schema> schema_;
};
class query_select_finish_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
void compile();
};
class query_select_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_from_intermediate from(const std::string &table, const std::string &as = "");
};
class query_from_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
query_join_intermediate join(const std::string &join_table_name, const std::string &as);
query_where_intermediate where(const sql::basic_condition &cond);
query_group_by_intermediate group_by(const std::string &name);
query_order_by_intermediate order_by(const std::string &name);
};
class query_join_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_on_intermediate on(const std::string &column, const std::string &join_column);
};
class query_on_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
query_join_intermediate join(const std::string &join_table_name, const std::string &as);
query_where_intermediate where(const sql::basic_condition &cond);
query_group_by_intermediate group_by(const std::string &name);
query_order_by_intermediate order_by(const std::string &name);
};
class query_where_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
query_group_by_intermediate group_by(const std::string &name);
query_order_by_intermediate order_by(const std::string &name);
};
class query_group_by_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
query_order_by_intermediate order_by(const std::string &name);
};
class query_order_by_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_order_direction_intermediate asc();
query_order_direction_intermediate desc();
};
class query_order_direction_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
query_offset_intermediate offset(size_t offset);
query_limit_intermediate limit(size_t limit);
};
class query_offset_intermediate : public query_intermediate
{
public:
using query_intermediate::query_intermediate;
query_limit_intermediate limit(size_t limit);
};
class query_limit_intermediate : public query_select_finish_intermediate
{
public:
using query_select_finish_intermediate::query_intermediate;
};
}
#endif //QUERY_QUERY_INTERMEDIATES_HPP

View File

@ -0,0 +1,19 @@
#ifndef QUERY_QUERY_PART_VISITOR_HPP
#define QUERY_QUERY_PART_VISITOR_HPP
namespace matador::query {
class query_select_part;
class query_from_part;
class query_part_visitor
{
public:
virtual ~query_part_visitor() = default;
virtual void visit(query_select_part &select_part) = 0;
virtual void visit(query_from_part &from_part) = 0;
};
}
#endif //QUERY_QUERY_PART_VISITOR_HPP

View File

@ -0,0 +1,55 @@
#ifndef QUERY_QUERY_PARTS_HPP
#define QUERY_QUERY_PARTS_HPP
#include "matador/query/query_part_visitor.hpp"
#include "matador/query/column.hpp"
#include "matador/sql/dialect.hpp"
namespace matador::query {
class query_part
{
protected:
explicit query_part(sql::dialect::token_t token);
public:
virtual ~query_part() = default;
virtual void accept(query_part_visitor &visitor) = 0;
protected:
sql::dialect::token_t token_;
};
/**
* Represents the SQL SELECT part
*/
class query_select_part : public query_part
{
public:
explicit query_select_part(std::vector<column> columns);
void accept(query_part_visitor &visitor) override;
private:
std::vector<column> columns_;
};
/**
* Represents the SQL FROM part
*/
class query_from_part : public query_part
{
public:
explicit query_from_part(std::string table_name);
query_from_part(std::string table_name, std::string as);
private:
void accept(query_part_visitor &visitor) override;
private:
std::string table_;
std::string alias_;
};
}
#endif //QUERY_QUERY_PARTS_HPP

View File

@ -0,0 +1,31 @@
#ifndef QUERY_SQL_COMMANDS_HPP
#define QUERY_SQL_COMMANDS_HPP
#include "matador/utils/enum_mapper.hpp"
namespace matador::query {
enum class SqlCommands
{
UNKNOWN, /**< Unknown query command */
CREATE, /**< Create query command */
DROP, /**< Drop query command */
SELECT, /**< Select query command */
INSERT, /**< Insert query command */
UPDATE, /**< Update query command */
REMOVE /**< Remove query command */
};
static const utils::enum_mapper<SqlCommands> sql_command_enum({
{SqlCommands::UNKNOWN, "unknown"},
{SqlCommands::CREATE, "create"},
{SqlCommands::DROP, "drop"},
{SqlCommands::SELECT, "select"},
{SqlCommands::INSERT, "insert"},
{SqlCommands::UPDATE, "update"},
{SqlCommands::REMOVE, "delete"}
});
}
#endif //QUERY_SQL_COMMANDS_HPP

View File

@ -0,0 +1,16 @@
#ifndef QUERY_TABLE_HPP
#define QUERY_TABLE_HPP
#include <typeindex>
#include <string>
namespace matador::query {
struct table_data
{
std::type_index index;
std::string name;
};
}
#endif //QUERY_TABLE_HPP

View File

@ -1,174 +1,45 @@
#ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/any_type_to_visitor.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/field_attributes.hpp"
#include <optional>
#include <vector>
#include <string>
namespace matador::sql {
enum class null_option : uint8_t {
NULLABLE, NOT_NULL
enum class sql_function_t {
NONE,
COUNT,
AVG,
SUM,
MIN,
MAX
};
class column {
public:
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)
struct column
{
column(const char *name) : name(name) {} // NOLINT(*-explicit-constructor)
column(std::string name) : name(std::move(name)) {} // NOLINT(*-explicit-constructor)
column(sql_function_t func, std::string name) : name(std::move(name)), function_(func) {} // NOLINT(*-explicit-constructor)
column(std::string table_name, std::string name, std::string as)
: table(std::move(table_name))
, name(std::move(name))
, alias(std::move(as)) {} // NOLINT(*-explicit-constructor)
column(const column&) = default;
column& operator=(const column&) = default;
column(column&&) noexcept = default;
column& operator=(column&&) noexcept = default;
template<typename Type>
explicit column(std::string name, utils::field_attributes attr)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
{}
template<typename Type>
column(std::string name, const Type &, utils::field_attributes attr, null_option null_opt)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr, null_opt)
{}
column(std::string name, data_type_t type, utils::field_attributes attr, null_option null_opt, size_t index = 0);
template<typename Type>
column(std::string name, std::string ref_table, std::string ref_column, utils::field_attributes attr, null_option null_opt)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), ref_table, ref_column, attr, null_opt)
{}
column(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column, utils::field_attributes attr, null_option null_opt);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] size_t index() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] bool is_nullable() 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 type(data_type_t type);
void alias(const std::string &as);
template< typename Type >
[[nodiscard]] bool is_type_of() const {
return std::holds_alternative<Type>(value_);
column& as(std::string a) {
alias = std::move(a);
return *this;
}
[[nodiscard]] std::string str() const;
template<typename Type>
void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes)
{
type_ = data_type_traits<Type>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
[[nodiscard]] bool is_function() const {
return function_ != sql_function_t::NONE;
}
void set(const std::string &value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const char *value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
template<class Type>
Type as() const
{
const Type* ptr= std::get_if<Type>(&value_);
if (ptr) {
return *ptr;
}
any_type_to_visitor<Type> visitor;
std::visit(visitor, const_cast<any_type&>(value_));
return visitor.result;
}
[[nodiscard]] bool is_function() const;
[[nodiscard]] sql_function_t function() const;
private:
template<class Operator>
void process(Operator &op)
{
op.on_attribute(name_.c_str(), value_, type_, attributes_);
}
using data_type_index = std::vector<data_type_t>;
private:
friend class record;
static const data_type_index data_type_index_;
std::string name_;
size_t index_{};
utils::field_attributes attributes_;
null_option null_option_{null_option::NOT_NULL};
data_type_t type_{data_type_t::type_unknown};
any_type value_;
std::string table;
std::string name;
std::string alias;
sql_function_t function_{sql_function_t::NONE};
std::string alias_;
std::string ref_table_;
std::string ref_column_;
};
/**
* User defined literal to have a shortcut creating a column object
* @param name Name of the column
* @param len Length of the column name
* @return A column object with given name
*/
column operator "" _col(const char *name, size_t len);
column make_column(const std::string &name, data_type_t type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL);
template < typename Type >
column make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL)
{
return make_column(name, data_type_traits<Type>::builtin_type(0), attr, null_opt);
}
template <>
column make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt);
template < typename Type >
column make_pk_column(const std::string &name, size_t size = 0)
{
return make_column<Type>(name, { size, utils::constraints::PRIMARY_KEY });
}
template <>
column make_pk_column<std::string>(const std::string &name, size_t size);
template < typename Type >
column make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column)
{
return {name, data_type_traits<Type>::builtin_type(size), ref_table, ref_column, { size, utils::constraints::FOREIGN_KEY }};
}
template < typename Type >
[[maybe_unused]] column make_fk_column(const std::string &name, const std::string &ref_table, const std::string &ref_column)
{
return {name, data_type_traits<Type>::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template <>
column make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column);
}
#endif //QUERY_COLUMN_HPP

View File

@ -0,0 +1,164 @@
#ifndef QUERY_COLUMN_DEFINITION_HPP
#define QUERY_COLUMN_DEFINITION_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/any_type_to_visitor.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/field_attributes.hpp"
#include <optional>
#include <vector>
namespace matador::sql {
enum class null_option : uint8_t {
NULLABLE, NOT_NULL
};
class column_definition {
public:
explicit column_definition(const char *name); // NOLINT(*-explicit-constructor)
explicit column_definition(std::string name); // NOLINT(*-explicit-constructor)
column_definition(const column_definition&) = default;
column_definition& operator=(const column_definition&) = default;
column_definition(column_definition&&) noexcept = default;
column_definition& operator=(column_definition&&) noexcept = default;
template<typename Type>
explicit column_definition(std::string name, utils::field_attributes attr)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
{}
template<typename Type>
column_definition(std::string name, const Type &, utils::field_attributes attr, null_option null_opt)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr, null_opt)
{}
column_definition(std::string name, data_type_t type, utils::field_attributes attr, null_option null_opt, size_t index = 0);
template<typename Type>
column_definition(std::string name, std::string ref_table, std::string ref_column, utils::field_attributes attr, null_option null_opt)
: column_definition(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), ref_table, ref_column, attr, null_opt)
{}
column_definition(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column, utils::field_attributes attr, null_option null_opt);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] size_t index() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] bool is_nullable() const;
[[nodiscard]] data_type_t type() const;
[[nodiscard]] const std::string& ref_table() const;
[[nodiscard]] const std::string& ref_column() const;
void type(data_type_t type);
template< typename Type >
[[nodiscard]] bool is_type_of() const {
return std::holds_alternative<Type>(value_);
}
[[nodiscard]] std::string str() const;
template<typename Type>
void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes)
{
type_ = data_type_traits<Type>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const std::string &value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const char *value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
template<class Type>
Type as() const
{
const Type* ptr= std::get_if<Type>(&value_);
if (ptr) {
return *ptr;
}
any_type_to_visitor<Type> visitor;
std::visit(visitor, const_cast<any_type&>(value_));
return visitor.result;
}
private:
template<class Operator>
void process(Operator &op)
{
op.on_attribute(name_.c_str(), value_, type_, attributes_);
}
using data_type_index = std::vector<data_type_t>;
private:
friend class record;
static const data_type_index data_type_index_;
std::string name_;
size_t index_{};
utils::field_attributes attributes_;
null_option null_option_{null_option::NOT_NULL};
data_type_t type_{data_type_t::type_unknown};
any_type value_;
std::string ref_table_;
std::string ref_column_;
};
/**
* User defined literal to have a shortcut creating a column object
* @param name Name of the column
* @param len Length of the column name
* @return A column object with given name
*/
column_definition make_column(const std::string &name, data_type_t type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL);
template < typename Type >
column_definition make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL)
{
return make_column(name, data_type_traits<Type>::builtin_type(0), attr, null_opt);
}
template <>
column_definition make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt);
template < typename Type >
column_definition make_pk_column(const std::string &name, size_t size = 0)
{
return make_column<Type>(name, { size, utils::constraints::PRIMARY_KEY });
}
template <>
column_definition make_pk_column<std::string>(const std::string &name, size_t size);
template < typename Type >
column_definition make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column)
{
return {name, data_type_traits<Type>::builtin_type(size), ref_table, ref_column, { size, utils::constraints::FOREIGN_KEY }};
}
template < typename Type >
[[maybe_unused]] column_definition make_fk_column(const std::string &name, const std::string &ref_table, const std::string &ref_column)
{
return {name, data_type_traits<Type>::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template <>
column_definition make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column);
}
#endif //QUERY_COLUMN_DEFINITION_HPP

View File

@ -1,7 +1,7 @@
#ifndef QUERY_COLUMN_GENERATOR_HPP
#define QUERY_COLUMN_GENERATOR_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/access.hpp"
@ -21,10 +21,10 @@ public:
fk_column_generator() = default;
template<class Type>
column generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
column_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
utils::access::process(*this, x);
return column{id, type_, 0, ref_table, ref_column, { utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
return column_definition{id, type_, 0, ref_table, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template<typename ValueType>
@ -53,15 +53,15 @@ private:
class column_generator
{
private:
column_generator(std::vector<column> &columns, const schema &repo);
column_generator(std::vector<column_definition> &columns, const schema &repo);
public:
~column_generator() = default;
template < class Type >
static std::vector<column> generate(const schema &repo)
static std::vector<column_definition> generate(const schema &repo)
{
std::vector<column> columns;
std::vector<column_definition> columns;
column_generator gen(columns, repo);
Type obj;
matador::utils::access::process(gen, obj);
@ -101,7 +101,7 @@ private:
private:
size_t index_ = 0;
std::vector<column> &columns_;
std::vector<column_definition> &columns_;
const schema &repo_;
fk_column_generator fk_column_generator_;

View File

@ -5,6 +5,7 @@
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/schema.hpp"
#include <string>
@ -13,29 +14,22 @@
namespace matador::sql {
struct column_info
{
std::string table;
std::string name;
std::string alias;
};
class column_name_generator
{
private:
column_name_generator(std::vector<column_info> &column_infos, const sql::schema &ts, const std::string &table_name);
column_name_generator(std::vector<column> &column_infos, const sql::schema &ts, const std::string &table_name);
public:
~column_name_generator() = default;
template < class Type >
static std::vector<column_info> generate(const sql::schema &ts)
static std::vector<column> generate(const sql::schema &ts)
{
const auto info = ts.info<Type>();
if (!info) {
return {};
}
std::vector<column_info> columns;
std::vector<column> columns;
column_name_generator gen(columns, ts, info.value().name);
Type obj;
matador::utils::access::process(gen, obj);
@ -93,7 +87,7 @@ private:
private:
std::stack<std::string> table_name_stack_;
std::vector<column_info> &column_infos_;
std::vector<column> &column_infos_;
const sql::schema &table_schema_;
int column_index{0};
};

View File

@ -7,6 +7,7 @@
#include "matador/sql/query_context.hpp"
#include <memory>
#include <utility>
namespace matador::sql {
@ -55,8 +56,8 @@ public:
std::string evaluate(dialect &d, query_context &query) const override
{
query.bind_vars.emplace_back(field_.name());
return d.prepare_identifier(field_.name()) + " " + operand + " " + std::to_string(value);
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_.name) + " " + operand + " " + std::to_string(value);
}
};
@ -75,8 +76,8 @@ public:
std::string evaluate(dialect &d, query_context &query) const override
{
query.bind_vars.emplace_back(field_.name());
return d.prepare_identifier(field_.name()) + " " + operand + " '" + value + "'";
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_.name) + " " + operand + " '" + value + "'";
}
};
@ -96,7 +97,7 @@ public:
std::string evaluate(dialect &d, query_context &query) const override
{
return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_.name());
return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_.name);
}
};
@ -115,7 +116,7 @@ public:
std::string evaluate(dialect &d, query_context &query) const override
{
return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_.name());
return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_.name);
}
};
@ -158,10 +159,10 @@ public:
std::string evaluate(dialect &d, query_context &query) const override {
auto count = size();
for (size_t i = 0; i < count; ++i) {
query.bind_vars.emplace_back(field_.name());
query.bind_vars.emplace_back(field_.name);
}
std::string result = d.prepare_identifier(field_.name()) + " IN (";
std::string result = d.prepare_identifier(field_.name) + " IN (";
if (args_.size() < 2) {
for (const auto &val : args_) {
result.append(std::to_string(val));
@ -261,9 +262,9 @@ public:
* @return A condition BETWEEN part of the query
*/
std::string evaluate(dialect &d, query_context &query) const override {
query.bind_vars.emplace_back(field_.name());
query.bind_vars.emplace_back(field_.name());
return d.prepare_identifier(field_.name()) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second);
query.bind_vars.emplace_back(field_.name);
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_.name) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second);
}
private:
@ -355,6 +356,28 @@ private:
std::string operand;
};
template<>
class condition<column, column> : public basic_column_condition
{
public:
condition(const column &a, basic_condition::operand_t op, column b)
: basic_column_condition(a, op)
, other_column_(std::move(b)) {}
/**
* @brief Evaluates the condition
*
* @param d The d used to evaluate
* @return The evaluated string based on the compile type
*/
std::string evaluate(dialect &d, query_context &query) const override
{
return d.prepare_identifier(field_.name) + " " + operand + " " + d.prepare_identifier(other_column_.name);
}
private:
column other_column_;
};
/**
* @file condition.hpp
* @brief Contains functions to create query conditions
@ -441,6 +464,8 @@ condition<column, T> operator==(const column &col, T val)
return condition<column, T>(col, basic_condition::operand_t::EQUAL, val);
}
condition<column, column> operator==(const column &a, const column &b);
/**
* @brief Condition equality method for a column and a query
*

View File

@ -4,11 +4,12 @@
#include "matador/sql/connection_info.hpp"
#include "matador/sql/connection_impl.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/query_intermediates.hpp"
#include "matador/sql/query.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
#include "matador/utils/logger.hpp"
@ -19,8 +20,8 @@ namespace matador::sql {
class connection
{
public:
explicit connection(connection_info info, const std::shared_ptr<schema> &repo = std::make_shared<schema>());
explicit connection(const std::string& dns, const std::shared_ptr<schema> &repo = std::make_shared<schema>());
explicit connection(connection_info info, const std::shared_ptr<schema> &repo = std::make_shared<sql::schema>());
explicit connection(const std::string& dns, const std::shared_ptr<schema> &repo = std::make_shared<sql::schema>());
connection(const connection &x);
connection& operator=(const connection &x);
connection(connection &&x) noexcept = default;
@ -31,19 +32,12 @@ public:
[[nodiscard]] bool is_open() const;
[[nodiscard]] const connection_info& info() const;
query_create_intermediate create();
query_drop_intermediate drop();
template < class Type >
query_select_intermediate select();
query_select_intermediate select(std::initializer_list<column> columns);
query_insert_intermediate insert();
query_update_intermediate update(const std::string &table);
query_delete_intermediate remove();
[[nodiscard]] record describe(const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &table_name) const;
sql::query query() const;
query_result<record> fetch(const query_context &q) const;
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
[[nodiscard]] size_t execute(const std::string &sql) const;
@ -51,21 +45,15 @@ public:
statement prepare(query_context &&query) const;
const class dialect& dialect() const;
std::shared_ptr<schema> tables() const;
std::shared_ptr<sql::schema> schema() const;
private:
connection_info connection_info_;
std::unique_ptr<connection_impl> connection_;
utils::logger logger_;
const class dialect &dialect_;
std::shared_ptr<schema> schema_;
std::shared_ptr<sql::schema> schema_;
};
template<class Type>
query_select_intermediate connection::select()
{
return query_select_intermediate{*this, column_generator::generate<Type>(*schema_)};
}
}
#endif //QUERY_CONNECTION_HPP

View File

@ -41,16 +41,6 @@ enum class data_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

View File

@ -1,6 +1,7 @@
#ifndef QUERY_DIALECT_HPP
#define QUERY_DIALECT_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/data_type_traits.hpp"
#include <cstdint>
@ -11,8 +12,6 @@
namespace matador::sql {
class column;
class dialect final
{
public:

View File

@ -0,0 +1,48 @@
#ifndef QUERY_QUERY_HPP
#define QUERY_QUERY_HPP
#include "matador/sql/query_intermediates.hpp"
namespace matador::sql {
class connection;
class query
{
public:
explicit query(connection &c);
query(const query &) = delete;
query& operator=(const query &) = delete;
query_create_intermediate create();
query_drop_intermediate drop();
template < class Type >
query_select_intermediate select();
template < class Type >
query_select_intermediate select(std::initializer_list<column> columns);
query_select_intermediate select(std::initializer_list<column> columns);
query_insert_intermediate insert();
query_update_intermediate update(const std::string &table);
query_delete_intermediate remove();
private:
[[nodiscard]] const sql::schema& schema() const;
private:
connection &connection_;
};
template<class Type>
query_select_intermediate query::select()
{
return query_select_intermediate{connection_, column_name_generator::generate<Type>(this->schema())};
}
template<class Type>
query_select_intermediate query::select(std::initializer_list<column> columns)
{
return query_select_intermediate{connection_, column_name_generator::generate<Type>(this->schema())};
}
}
#endif //QUERY_QUERY_HPP

View File

@ -2,6 +2,7 @@
#define QUERY_QUERY_BUILDER_HPP
#include "matador/sql/basic_condition.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/sql/key_value_pair.hpp"
@ -123,11 +124,11 @@ public:
query_builder& update(const std::string &table);
query_builder& remove();
query_builder& table(const std::string &table, std::initializer_list<column> columns);
query_builder& table(const std::string &table, const std::vector<column> &columns);
query_builder& table(const std::string &table, std::initializer_list<column_definition> columns);
query_builder& table(const std::string &table, const std::vector<column_definition> &columns);
query_builder& table(const std::string &table);
query_builder& into(const std::string &table, std::initializer_list<column_info> column_names);
query_builder& into(const std::string &table, const std::vector<column_info> &column_names);
query_builder& into(const std::string &table, std::initializer_list<column> column_names);
query_builder& into(const std::string &table, const std::vector<column> &column_names);
query_builder& values(std::initializer_list<any_type> values);
query_builder& values(const std::vector<any_type> &values);
query_builder& from(const std::string &table, const std::string &as = "");

View File

@ -0,0 +1,51 @@
#ifndef QUERY_QUERY_COMPILER_HPP
#define QUERY_QUERY_COMPILER_HPP
#include "matador/sql/query_part_visitor.hpp"
#include "matador/sql/query_parts.hpp"
#include "matador/sql/query_context.hpp"
#include <typeindex>
#include <string>
namespace matador::sql {
class dialect;
struct query_data;
class query_compiler : public query_part_visitor
{
public:
explicit query_compiler(const sql::dialect& d);
query_context compile(const query_data *data);
private:
void visit(query_select_part &select_part) override;
void visit(query_from_part &from_part) override;
void visit(query_where_part &where_part) override;
void visit(query_group_by_part &group_by_part) override;
void visit(query_order_by_part &order_by_part) override;
void visit(query_order_by_asc_part &order_by_asc_part) override;
void visit(query_order_by_desc_part &order_by_desc_part) override;
void visit(query_insert_part &insert_part) override;
void visit(query_values_part &values_part) override;
void visit(query_update_part &update_part) override;
void visit(query_delete_part &delete_part) override;
void visit(query_create_part &create_part) override;
void visit(query_drop_part &drop_part) override;
private:
const sql::dialect &dialect_;
query_context query_;
};
}
#endif //QUERY_QUERY_COMPILER_HPP

View File

@ -0,0 +1,24 @@
#ifndef QUERY_QUERY_DATA_HPP
#define QUERY_QUERY_DATA_HPP
#include "matador/sql/query_parts.hpp"
#include "matador/sql/table.hpp"
#include <memory>
#include <vector>
namespace matador::sql {
struct query_data
{
// SqlCommands command;
std::vector<std::unique_ptr<query_part>> parts;
std::vector<column_definition> columns;
std::unordered_map<std::type_index, table> table_map_by_index;
using table_ref = std::reference_wrapper<table>;
std::unordered_map<std::string, table_ref> table_map_by_name;
};
}
#endif //QUERY_QUERY_DATA_HPP

View File

@ -1,14 +1,14 @@
#ifndef QUERY_QUERY_INTERMEDIATES_HPP
#define QUERY_QUERY_INTERMEDIATES_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/key_value_generator.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/placeholder_generator.hpp"
#include "matador/sql/query_builder.hpp"
#include "matador/sql/query_result.hpp"
#include "matador/sql/query_data.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
@ -36,10 +36,10 @@ protected:
class query_intermediate : public basic_query_intermediate
{
public:
query_intermediate(connection &db, query_builder &query);
query_intermediate(connection &db, query_data &data);
protected:
query_builder &builder_;
query_data &data_;
};
class query_execute_finish : public query_intermediate
@ -146,7 +146,7 @@ class query_join_intermediate : public query_intermediate
public:
using query_intermediate::query_intermediate;
query_on_intermediate on(const std::string &column, const std::string &join_column);
query_on_intermediate on(const basic_condition &cond);
};
class query_from_intermediate : public query_select_finish
@ -154,7 +154,7 @@ class query_from_intermediate : public query_select_finish
public:
using query_select_finish::query_select_finish;
query_join_intermediate join(const std::string &join_table_name, const std::string &as);
query_join_intermediate join_left(const std::string &join_table_name, const std::string &as = "");
query_where_intermediate where(const basic_condition &cond);
query_group_by_intermediate group_by(const std::string &name);
query_order_by_intermediate order_by(const std::string &name);
@ -163,10 +163,10 @@ public:
class query_start_intermediate : public basic_query_intermediate
{
public:
explicit query_start_intermediate(connection &s);
explicit query_start_intermediate(connection &db);
protected:
query_builder builder_;
query_data data_;
};
class query_select_intermediate : public query_start_intermediate
@ -192,16 +192,19 @@ public:
using query_intermediate::query_intermediate;
query_execute_finish values(std::initializer_list<any_type> values);
query_execute_finish values(const std::vector<any_type>& values);
template<class Type>
query_execute_finish values()
{
Type obj;
return {connection_, builder_.values(as_placeholder(obj))};
return {connection_, data_};
// return {connection_, builder_.values(as_placeholder(obj))};
}
template<class Type>
query_execute_finish values(const Type &obj)
{
return {connection_, builder_.values(value_extractor::extract(obj))};
return {connection_, data_};
// return {connection_, builder_.values(value_extractor::extract(obj))};
}
};
@ -210,15 +213,16 @@ class query_create_intermediate : public query_start_intermediate
public:
explicit query_create_intermediate(connection &db);
query_execute_finish table(const std::string &table_name, std::initializer_list<column> columns);
query_execute_finish table(const std::string &table_name, const std::vector<column> &columns);
query_execute_finish table(const std::string &table_name, std::initializer_list<column_definition> columns);
query_execute_finish table(const std::string &table_name, const std::vector<column_definition> &columns);
template<class Type>
query_execute_finish table(const std::string &table_name)
{
if (!tables()->exists<Type>()) {
tables()->attach<Type>(table_name);
}
return {connection_, builder_.table(table_name, column_generator::generate<Type>(*tables()))};
return {connection_, data_};
// return {connection_, builder_.table(table_name, column_generator::generate<Type>(*tables()))};
}
};
@ -235,17 +239,19 @@ class query_insert_intermediate : public query_start_intermediate
public:
explicit query_insert_intermediate(connection &s);
query_into_intermediate into(const std::string &table, std::initializer_list<column_info> column_names);
query_into_intermediate into(const std::string &table, std::initializer_list<column> column_names);
template<class Type>
query_into_intermediate into(const std::string &table)
{
return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables()))};
return {connection_, data_};
// return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables()))};
}
template<class Type>
query_execute_finish into(const std::string &table, const Type &obj)
{
return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables()))
.values(value_extractor::extract(obj))};
return {connection_, data_};
// return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables()))
// .values(value_extractor::extract(obj))};
}
};
@ -274,7 +280,8 @@ public:
template<class Type>
query_set_intermediate set(const Type &obj)
{
return {connection_, builder_.set(key_value_generator::generate(obj))};
return {connection_, data_};
// return {connection_, builder_.set(key_value_generator::generate(obj))};
}
};

View File

@ -0,0 +1,46 @@
#ifndef QUERY_QUERY_PART_VISITOR_HPP
#define QUERY_QUERY_PART_VISITOR_HPP
namespace matador::sql {
class query_select_part;
class query_from_part;
class query_where_part;
class query_group_by_part;
class query_order_by_part;
class query_order_by_asc_part;
class query_order_by_desc_part;
class query_insert_part;
class query_values_part;
class query_update_part;
class query_delete_part;
class query_create_part;
class query_drop_part;
class query_part_visitor
{
public:
virtual ~query_part_visitor() = default;
virtual void visit(query_select_part &select_part) = 0;
virtual void visit(query_from_part &from_part) = 0;
virtual void visit(query_where_part &where_part) = 0;
virtual void visit(query_group_by_part &group_by_part) = 0;
virtual void visit(query_order_by_part &order_by_part) = 0;
virtual void visit(query_order_by_asc_part &order_by_asc_part) = 0;
virtual void visit(query_order_by_desc_part &order_by_desc_part) = 0;
virtual void visit(query_insert_part &insert_part) = 0;
virtual void visit(query_values_part &values_part) = 0;
virtual void visit(query_update_part &update_part) = 0;
virtual void visit(query_delete_part &delete_part) = 0;
virtual void visit(query_create_part &create_part) = 0;
virtual void visit(query_drop_part &drop_part) = 0;
};
}
#endif //QUERY_QUERY_PART_VISITOR_HPP

View File

@ -0,0 +1,181 @@
#ifndef QUERY_QUERY_PARTS_HPP
#define QUERY_QUERY_PARTS_HPP
#include "matador/sql/query_part_visitor.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/dialect.hpp"
#include <memory>
namespace matador::sql {
class basic_condition;
class query_part
{
protected:
explicit query_part(sql::dialect::token_t token);
public:
virtual ~query_part() = default;
virtual void accept(query_part_visitor &visitor) = 0;
protected:
sql::dialect::token_t token_;
};
/**
* Represents the SQL SELECT part
*/
class query_select_part : public query_part
{
public:
explicit query_select_part(std::vector<column> columns);
void accept(query_part_visitor &visitor) override;
[[nodiscard]] const std::vector<column>& columns() const;
private:
std::vector<column> columns_;
};
/**
* Represents the SQL FROM part
*/
class query_from_part : public query_part
{
public:
explicit query_from_part(std::string table_name);
query_from_part(std::string table_name, std::string as);
private:
void accept(query_part_visitor &visitor) override;
private:
std::string table_;
std::string alias_;
};
class query_where_part : public query_part
{
public:
template < class Condition >
explicit query_where_part(const Condition &cond)
: query_part(dialect::token_t::WHERE)
, condition_(new Condition(cond)) {}
private:
void accept(query_part_visitor &visitor) override;
private:
std::unique_ptr<basic_condition> condition_;
};
class query_table_name_part : public query_part
{
protected:
explicit query_table_name_part(sql::dialect::token_t token, std::string table_name);
protected:
std::string table_name_;
};
class query_group_by_part : public query_table_name_part
{
public:
explicit query_group_by_part(const std::string &table_name);
private:
void accept(query_part_visitor &visitor) override;
};
class query_order_by_part : public query_table_name_part
{
public:
explicit query_order_by_part(const std::string &table_name);
private:
void accept(query_part_visitor &visitor) override;
};
class query_order_by_asc_part : public query_part
{
public:
query_order_by_asc_part();
private:
void accept(query_part_visitor &visitor) override;
};
class query_order_by_desc_part : public query_part
{
public:
query_order_by_desc_part();
private:
void accept(query_part_visitor &visitor) override;
};
class query_insert_part : public query_part
{
public:
query_insert_part();
private:
void accept(query_part_visitor &visitor) override;
};
/**
* Represents the SQL VALUES part
*/
class query_values_part : public query_part
{
public:
query_values_part(std::initializer_list<any_type> values);
private:
void accept(query_part_visitor &visitor) override;
private:
std::vector<any_type> values_;
};
class query_update_part : public query_table_name_part
{
public:
explicit query_update_part(const std::string &table_name);
private:
void accept(query_part_visitor &visitor) override;
};
class query_delete_part : public query_part
{
public:
query_delete_part();
private:
void accept(query_part_visitor &visitor) override;
};
class query_create_part : public query_part
{
public:
query_create_part();
private:
void accept(query_part_visitor &visitor) override;
};
class query_drop_part : public query_part
{
public:
query_drop_part();
private:
void accept(query_part_visitor &visitor) override;
};
}
#endif //QUERY_QUERY_PARTS_HPP

View File

@ -3,7 +3,7 @@
#include "matador/utils/access.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include <vector>
#include <unordered_map>
@ -13,8 +13,8 @@ namespace matador::sql {
class record
{
private:
using column_by_index = std::vector<column>;
using column_index_pair = std::pair<std::reference_wrapper<column>, size_t>;
using column_by_index = std::vector<column_definition>;
using column_index_pair = std::pair<std::reference_wrapper<column_definition>, size_t>;
using column_by_name_map = std::unordered_map<std::string, column_index_pair>;
public:
@ -22,8 +22,8 @@ public:
using const_iterator = column_by_index::const_iterator;
record() = default;
record(std::initializer_list<column> columns);
explicit record(const std::vector<column> &columns);
record(std::initializer_list<column_definition> columns);
explicit record(const std::vector<column_definition> &columns);
record(const record &x);
record& operator=(const record &x);
record(record&&) noexcept = default;
@ -43,15 +43,15 @@ public:
append(make_column<Type>(name, size));
}
void append(column col);
void append(column_definition col);
[[nodiscard]] bool has_primary_key() const;
[[nodiscard]] const column& primary_key() const;
[[nodiscard]] const column_definition& primary_key() const;
[[nodiscard]] const std::vector<column>& columns() const;
[[nodiscard]] const std::vector<column_definition>& columns() const;
[[nodiscard]] const column& at(const std::string &name) const;
[[nodiscard]] const column& at(size_t index) const;
[[nodiscard]] const column_definition& at(const std::string &name) const;
[[nodiscard]] const column_definition& at(size_t index) const;
iterator find(const std::string &column_name);
[[nodiscard]] const_iterator find(const std::string &column_name) const;
@ -72,7 +72,7 @@ public:
private:
void init();
void add_to_map(column &col, size_t index);
void add_to_map(column_definition &col, size_t index);
private:
column_by_index columns_;

View File

@ -28,6 +28,8 @@ public:
using iterator = repository::iterator;
using const_iterator = repository::const_iterator;
std::string name() const;
template<typename Type>
const table_info& attach(const std::string &table_name)
{
@ -68,6 +70,7 @@ public:
[[nodiscard]] bool empty() const;
private:
std::string name_;
repository repository_;
};

View File

@ -74,7 +74,7 @@ entity<Type> session::insert(Type *obj)
if (!info) {
return {};
}
c->insert().into<Type>(info->name).values(*obj).execute();
c->query().insert().into<Type>(info->name).values(*obj).execute();
return entity{obj};
}

View File

@ -0,0 +1,17 @@
#ifndef QUERY_TABLE_HPP
#define QUERY_TABLE_HPP
#include <typeindex>
#include <string>
namespace matador::sql {
struct table
{
std::type_index index;
std::string name;
};
}
#endif //QUERY_TABLE_HPP

View File

@ -38,7 +38,7 @@ std::string to_string(const blob &data);
* given stream
*
* @tparam R Type og the range (e.g. map, list, vector, etc)
* @param range The range with the elements to join
* @param range The range with the elements to join_left
* @param delim The delimiter for the elements
* @return The ostream reference
*/

View File

@ -1,7 +1,7 @@
set(SQL_SOURCES
sql/dialect.cpp
sql/query_builder.cpp
sql/column.cpp
sql/column_definition.cpp
sql/key_value_pair.cpp
sql/basic_condition.cpp
sql/connection.cpp
@ -28,12 +28,16 @@ set(SQL_SOURCES
sql/result_parameter_binder.cpp
sql/statement.cpp
sql/convert.cpp
sql/column.cpp
sql/query.cpp
sql/query_parts.cpp
sql/query_compiler.cpp
)
set(SQL_HEADER
../include/matador/sql/dialect.hpp
../include/matador/sql/query_builder.hpp
../include/matador/sql/column.hpp
../include/matador/sql/column_definition.hpp
../include/matador/sql/data_type_traits.hpp
../include/matador/sql/key_value_pair.hpp
../include/matador/sql/basic_condition.hpp
@ -69,6 +73,34 @@ set(SQL_HEADER
../include/matador/sql/placeholder_generator.hpp
../include/matador/sql/result_parameter_binder.hpp
../include/matador/sql/convert.hpp
../include/matador/sql/query.hpp
../include/matador/sql/query_parts.hpp
../include/matador/sql/query_part_visitor.hpp
../include/matador/sql/query_compiler.hpp
../include/matador/sql/query_data.hpp
../include/matador/sql/table.hpp
)
set(QUERY_SOURCES
query/query.cpp
query/query_compiler.cpp
query/query_parts.cpp
query/column.cpp
query/query_builder.cpp
query/query_intermediates.cpp
)
set(QUERY_HEADER
../include/matador/query/query.hpp
../include/matador/query/query_part_visitor.hpp
../include/matador/query/query_compiler.hpp
../include/matador/query/query_parts.hpp
../include/matador/query/column.hpp
../include/matador/query/query_builder.hpp
../include/matador/query/query_intermediates.hpp
../include/matador/query/sql_commands.hpp
../include/matador/query/query_data.hpp
../include/matador/query/table.hpp
)
set(UTILS_HEADER
@ -84,7 +116,8 @@ set(UTILS_HEADER
../include/matador/utils/enum_mapper.hpp
../include/matador/utils/types.hpp
../include/matador/utils/foreign_attributes.hpp
../include/matador/utils/fetch_type.hpp)
../include/matador/utils/fetch_type.hpp
)
set(UTILS_SOURCES
utils/field_attributes.cpp
@ -95,8 +128,14 @@ set(UTILS_SOURCES
utils/identifier.cpp
sql/value_extractor.cpp
utils/logger.cpp
utils/foreign_attributes.cpp)
utils/foreign_attributes.cpp
)
add_library(matador STATIC
${SQL_SOURCES} ${SQL_HEADER}
# ${QUERY_SOURCES} ${QUERY_HEADER}
${UTILS_SOURCES} ${UTILS_HEADER}
)
add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER})
target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include)
#set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX)

21
src/query/column.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "matador/query/column.hpp"
namespace matador::query {
column::column(const char *name)
: name(name) {}
column::column(std::string name)
: name(std::move(name)) {}
column::column(std::string table_name, std::string name, std::string as)
: table(std::move(table_name))
, name(std::move(name))
, alias(std::move(as)) {}
column& column::as(std::string a) {
alias = std::move(a);
return *this;
}
}

6
src/query/query.cpp Normal file
View File

@ -0,0 +1,6 @@
#include "matador/query/query.hpp"
namespace matador::sql {
}

View File

@ -0,0 +1,13 @@
#include "matador/query/query_builder.hpp"
namespace matador::query {
query_builder::query_builder(const std::shared_ptr<sql::schema> &scm)
: schema_(scm) {}
query_select_intermediate query_builder::select(std::initializer_list<column> columns)
{
return query_select_intermediate{schema_};
}
}

View File

@ -0,0 +1,33 @@
#include "matador/query/query_compiler.hpp"
#include "matador/query/query_data.hpp"
#include "matador/query/column.hpp"
#include "matador/sql/dialect.hpp"
namespace matador::query {
query_compiler::query_compiler(sql::dialect &d)
: dialect_(d)
{}
std::string query_compiler::compile(const query_data *data)
{
sql_.clear();
for (const auto &part : data->parts) {
part->accept(*this);
}
return sql_;
}
void query_compiler::visit(query_select_part &select_part)
{
auto ci = "name"_col.as("c01");
}
void query_compiler::visit(query_from_part &from_part)
{
}
}

View File

@ -0,0 +1,8 @@
#include "matador/query/query_intermediates.hpp"
namespace matador::query {
query_intermediate::query_intermediate(const std::shared_ptr<sql::schema> &scm)
: schema_(scm) {}
}

30
src/query/query_parts.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "matador/query/query_parts.hpp"
namespace matador::query {
query_part::query_part(sql::dialect::token_t token)
: token_(token) {}
query_select_part::query_select_part(std::vector<column> columns)
: query_part(sql::dialect::token_t::SELECT)
, columns_(std::move(columns)) {}
void query_select_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_from_part::query_from_part(std::string table_name)
: query_part(sql::dialect::token_t::FROM)
, table_(std::move(table_name)) {}
query_from_part::query_from_part(std::string table_name, std::string as)
: query_part(sql::dialect::token_t::FROM)
, table_(std::move(table_name))
, alias_(std::move(as)) {}
void query_from_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
}

View File

@ -1,129 +1,10 @@
#include "matador/sql/column.hpp"
#include <utility>
namespace matador::sql {
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, null_option null_opt, size_t index)
: name_(std::move(name)), index_(index), type_(type), attributes_(attr), null_option_(null_opt)
{}
column::column(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column,
utils::field_attributes attr, null_option null_opt)
: name_(std::move(name))
, index_(index)
, type_(type)
, attributes_(attr)
, null_option_(null_opt)
, ref_table_(std::move(ref_table))
, ref_column_(std::move(ref_column))
{}
const std::string &column::name() const
column operator ""_col(const char *name, size_t len)
{
return name_;
return {{name, len}};
}
size_t column::index() const
{
return index_;
}
const utils::field_attributes &column::attributes() const
{
return attributes_;
}
bool column::is_nullable() const
{
return null_option_ == null_option::NULLABLE;
}
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_;
}
const std::string &column::ref_column() const
{
return ref_column_;
}
void column::type(data_type_t type)
{
type_ = type;
}
void column::alias(const std::string &as)
{
alias_ = as;
}
std::string column::str() const
{
any_type_to_visitor<std::string> visitor;
std::visit(visitor, const_cast<any_type &>(value_));
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 {std::string(name, len)};
}
column make_column(const std::string &name, data_type_t type, utils::field_attributes attr, null_option null_opt)
{
return {name, type, attr, null_opt};
}
template<>
column make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt)
{
return make_column(name, data_type_traits<std::string>::builtin_type(attr.size()), attr, null_opt);
}
template<>
column make_pk_column<std::string>(const std::string &name, size_t size)
{
return make_column<std::string>(name, {size, utils::constraints::FOREIGN_KEY});
}
template<>
[[maybe_unused]] column make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table,
const std::string &ref_column)
{
return {name, data_type_traits<std::string>::builtin_type(size), 0, ref_table, ref_column, {size, utils::constraints::FOREIGN_KEY}, null_option::NOT_NULL};
}
}

View File

@ -0,0 +1,100 @@
#include "matador/sql/column_definition.hpp"
#include <utility>
namespace matador::sql {
column_definition::column_definition(const char *name)
: name_(name), attributes_(utils::null_attributes)
{}
column_definition::column_definition(std::string name)
: name_(std::move(name)), attributes_(utils::null_attributes)
{}
column_definition::column_definition(std::string name, data_type_t type, utils::field_attributes attr, null_option null_opt, size_t index)
: name_(std::move(name)), index_(index), type_(type), attributes_(attr), null_option_(null_opt)
{}
column_definition::column_definition(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column,
utils::field_attributes attr, null_option null_opt)
: name_(std::move(name))
, index_(index)
, type_(type)
, attributes_(attr)
, null_option_(null_opt)
, ref_table_(std::move(ref_table))
, ref_column_(std::move(ref_column))
{}
const std::string &column_definition::name() const
{
return name_;
}
size_t column_definition::index() const
{
return index_;
}
const utils::field_attributes &column_definition::attributes() const
{
return attributes_;
}
bool column_definition::is_nullable() const
{
return null_option_ == null_option::NULLABLE;
}
data_type_t column_definition::type() const
{
return type_;
}
const std::string &column_definition::ref_table() const
{
return ref_table_;
}
const std::string &column_definition::ref_column() const
{
return ref_column_;
}
void column_definition::type(data_type_t type)
{
type_ = type;
}
std::string column_definition::str() const
{
any_type_to_visitor<std::string> visitor;
std::visit(visitor, const_cast<any_type &>(value_));
return visitor.result;
}
column_definition make_column(const std::string &name, data_type_t type, utils::field_attributes attr, null_option null_opt)
{
return {name, type, attr, null_opt};
}
template<>
column_definition make_column<std::string>(const std::string &name, utils::field_attributes attr, null_option null_opt)
{
return make_column(name, data_type_traits<std::string>::builtin_type(attr.size()), attr, null_opt);
}
template<>
column_definition make_pk_column<std::string>(const std::string &name, size_t size)
{
return make_column<std::string>(name, {size, utils::constraints::FOREIGN_KEY});
}
template<>
[[maybe_unused]] column_definition make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table,
const std::string &ref_column)
{
return {name, data_type_traits<std::string>::builtin_type(size), 0, ref_table, ref_column, {size, utils::constraints::FOREIGN_KEY}, null_option::NOT_NULL};
}
}

View File

@ -3,7 +3,7 @@
namespace matador::sql {
column_generator::column_generator(std::vector<column> &columns, const schema &repo)
column_generator::column_generator(std::vector<column_definition> &columns, const schema &repo)
: columns_(columns)
, repo_(repo)
{}

View File

@ -2,7 +2,7 @@
namespace matador::sql {
column_name_generator::column_name_generator(std::vector<column_info> &column_infos,
column_name_generator::column_name_generator(std::vector<column> &column_infos,
const sql::schema &ts,
const std::string &table_name)
: column_infos_(column_infos)
@ -25,7 +25,7 @@ void column_name_generator::push(const std::string &column_name)
{
char str[4];
snprintf(str, 4, "c%02d", ++column_index);
column_infos_.emplace_back(column_info{table_name_stack_.top(), column_name, str});
column_infos_.emplace_back(table_name_stack_.top(), column_name, str);
}
}

View File

@ -8,8 +8,8 @@ condition<column, placeholder, std::enable_if<true>::type>::condition(const colu
std::string condition<column, placeholder, std::enable_if<true>::type>::evaluate(dialect &d, query_context &query) const
{
query.bind_vars.emplace_back(field_.name());
return d.prepare_identifier(field_.name()) + " " + operand + " " + d.next_placeholder(query.bind_vars);
query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_.name) + " " + operand + " " + d.next_placeholder(query.bind_vars);
}
condition<column, query_context>::condition(column col, basic_condition::operand_t op, query_context &q)
@ -18,9 +18,13 @@ condition<column, query_context>::condition(column col, basic_condition::operand
std::string condition<column, query_context>::evaluate(dialect &d, query_context &query) const
{
std::string result(d.prepare_identifier(field_.name()) + " " + operand + " (");
std::string result(d.prepare_identifier(field_.name) + " " + operand + " (");
result += (")");
return result;
}
condition<column, column> operator==(const column &a, const column &b)
{
return {a, basic_condition::operand_t::EQUAL, b};
}
}

View File

@ -8,7 +8,7 @@
namespace matador::sql {
connection::connection(connection_info info, const std::shared_ptr<schema> &repo)
connection::connection(connection_info info, const std::shared_ptr<sql::schema> &repo)
: connection_info_(std::move(info))
, logger_(stdout, "SQL")
, dialect_(backend_provider::instance().connection_dialect(connection_info_.type))
@ -17,7 +17,7 @@ connection::connection(connection_info info, const std::shared_ptr<schema> &repo
connection_.reset(backend_provider::instance().create_connection(connection_info_.type, connection_info_));
}
connection::connection(const std::string& dns, const std::shared_ptr<schema> &repo)
connection::connection(const std::string& dns, const std::shared_ptr<sql::schema> &repo)
: connection(connection_info::parse(dns), repo)
{}
@ -69,36 +69,6 @@ const connection_info &connection::info() const
return connection_info_;
}
query_create_intermediate connection::create()
{
return query_create_intermediate(*this);
}
query_drop_intermediate connection::drop()
{
return query_drop_intermediate{*this};
}
query_select_intermediate connection::select(std::initializer_list<column> columns)
{
return {*this, columns};
}
query_insert_intermediate connection::insert()
{
return query_insert_intermediate{*this};
}
query_update_intermediate connection::update(const std::string &table)
{
return query_update_intermediate{*this, table};
}
query_delete_intermediate connection::remove()
{
return query_delete_intermediate{*this};
}
record connection::describe(const std::string &table_name) const
{
return std::move(connection_->describe(table_name));
@ -120,15 +90,20 @@ size_t connection::execute(const std::string &sql) const
return connection_->execute(sql);
}
sql::query connection::query() const
{
return sql::query(*const_cast<connection*>(this));
}
query_result<record> connection::fetch(const query_context &q) const
{
if (q.prototype.empty() || q.prototype.unknown()) {
const auto table_prototype = describe(q.table_name);
for (auto &col : q.prototype) {
if (const auto rit = table_prototype.find(col.name()); col.type() == data_type_t::type_unknown && rit != table_prototype.end()) {
const_cast<column&>(col).type(rit->type());
const_cast<column_definition&>(col).type(rit->type());
}
}
}
}
// auto it = prototypes_.find(q.table_name);
// if (it == prototypes_.end()) {
@ -160,7 +135,7 @@ const class dialect &connection::dialect() const
return dialect_;
}
std::shared_ptr<schema> connection::tables() const
std::shared_ptr<schema> connection::schema() const
{
return schema_;
}

View File

@ -1,5 +1,5 @@
#include "matador/sql/dialect.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/utils/string.hpp"
@ -19,12 +19,12 @@ std::string dialect::prepare_identifier(const column &col) const
{
std::string result;
if (!col.is_function()) {
result = prepare_identifier_string(col.name());
result = prepare_identifier_string(col.name);
} else {
result = sql_func_map_.at(col.function()) + "(" + col.name() + ")";
result = sql_func_map_.at(col.function_) + "(" + col.name + ")";
}
if (!col.alias().empty()) {
result += " AS " + col.alias();
if (!col.alias.empty()) {
result += " AS " + col.alias;
}
return result;
}

45
src/sql/query.cpp Normal file
View File

@ -0,0 +1,45 @@
#include "matador/sql/query.hpp"
#include "matador/sql/connection.hpp"
namespace matador::sql {
query::query(connection &c)
: connection_(c)
{}
query_create_intermediate query::create()
{
return query_create_intermediate(connection_);
}
query_drop_intermediate query::drop()
{
return query_drop_intermediate{connection_};
}
query_select_intermediate query::select(std::initializer_list<column> columns)
{
return {connection_, columns};
}
query_insert_intermediate query::insert()
{
return query_insert_intermediate{connection_};
}
query_update_intermediate query::update(const std::string &table)
{
return query_update_intermediate{connection_, table};
}
query_delete_intermediate query::remove()
{
return query_delete_intermediate{connection_};
}
const sql::schema& query::schema() const
{
return *connection_.schema();
}
}

View File

@ -1,5 +1,6 @@
#include "matador/sql/query_builder.hpp"
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp"
#include "matador/utils/string.hpp"
@ -139,19 +140,19 @@ query_builder &query_builder::select(const std::vector<column> &columns)
if (columns.size() < 2) {
for (const auto &col: columns) {
result.append(dialect_.prepare_identifier(col));
query_.result_vars.emplace_back(col.name());
query_.prototype.append(col);
query_.result_vars.emplace_back(col.name);
query_.prototype.append(column_definition{col.name});
}
} else {
auto it = columns.begin();
result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name());
query_.prototype.append(column{*it++});
query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it++).name});
for (; it != columns.end(); ++it) {
result.append(", ");
result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name());
query_.prototype.append(column{*it});
query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it).name});
}
}
@ -187,9 +188,9 @@ query_builder &query_builder::remove()
return *this;
}
query_builder &query_builder::table(const std::string &table, std::initializer_list<column> columns)
query_builder &query_builder::table(const std::string &table, std::initializer_list<column_definition> columns)
{
return this->table(table, std::vector<column>{columns});
return this->table(table, std::vector<column_definition>{columns});
}
struct fk_context
@ -205,9 +206,9 @@ struct column_context
std::vector<fk_context> foreign_contexts;
};
std::string build_create_column(const column &col, const dialect &d, column_context &context);
std::string build_create_column(const column_definition &col, const dialect &d, column_context &context);
query_builder &query_builder::table(const std::string &table, const std::vector<column> &columns)
query_builder &query_builder::table(const std::string &table, const std::vector<column_definition> &columns)
{
transition_to(state_t::QUERY_TABLE_CREATE);
@ -256,12 +257,12 @@ query_builder &query_builder::table(const std::string &table)
return *this;
}
query_builder &query_builder::into(const std::string &table, std::initializer_list<column_info> column_names)
query_builder &query_builder::into(const std::string &table, std::initializer_list<column> column_names)
{
return into(table, std::vector<column_info>{column_names});
return into(table, std::vector<column>{column_names});
}
query_builder &query_builder::into(const std::string &table, const std::vector<column_info> &column_names)
query_builder &query_builder::into(const std::string &table, const std::vector<column> &column_names)
{
transition_to(state_t::QUERY_INTO);
@ -490,7 +491,7 @@ void query_builder::initialize(query_builder::command_t cmd, query_builder::stat
query_parts_.clear();
}
std::string build_create_column(const column &col, const dialect &d, column_context &context)
std::string build_create_column(const column_definition &col, const dialect &d, column_context &context)
{
std::string result = d.prepare_identifier(col.name()) + " " + d.data_type_at(col.type());
if (col.attributes().size() > 0) {
@ -514,12 +515,12 @@ std::string build_create_column(const column &col, const dialect &d, column_cont
column alias(const std::string &column, const std::string &as)
{
return {column, as};
return {"", column, as};
}
column alias(column &&col, const std::string &as)
{
col.alias(as);
col.as(as);
return std::move(col);
}

105
src/sql/query_compiler.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "matador/sql/query_compiler.hpp"
#include "matador/sql/query_data.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/dialect.hpp"
namespace matador::sql {
query_compiler::query_compiler(const sql::dialect &d)
: dialect_(d)
{}
query_context query_compiler::compile(const query_data *data)
{
for (const auto &part : data->parts) {
part->accept(*this);
}
return query_;
}
void query_compiler::visit(query_select_part &select_part)
{
std::string result;
const auto &columns = select_part.columns();
if (columns.size() < 2) {
for (const auto &col: columns) {
result.append(dialect_.prepare_identifier(col));
query_.result_vars.emplace_back(col.name);
query_.prototype.append(column_definition{col.name});
}
} else {
auto it = columns.begin();
result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it++).name});
for (; it != columns.end(); ++it) {
result.append(", ");
result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it).name});
}
}
}
void query_compiler::visit(query_from_part &from_part)
{
}
void query_compiler::visit(query_where_part &where_part)
{
}
void query_compiler::visit(query_group_by_part &group_by_part)
{
}
void query_compiler::visit(query_order_by_part &order_by_part)
{
}
void query_compiler::visit(query_order_by_asc_part &order_by_asc_part)
{
}
void query_compiler::visit(query_order_by_desc_part &order_by_desc_part)
{
}
void query_compiler::visit(query_insert_part &insert_part)
{
}
void query_compiler::visit(query_values_part &values_part)
{
}
void query_compiler::visit(query_update_part &update_part)
{
}
void query_compiler::visit(query_delete_part &delete_part)
{
}
void query_compiler::visit(query_create_part &create_part)
{
}
void query_compiler::visit(query_drop_part &drop_part)
{
}
}

View File

@ -1,5 +1,6 @@
#include "matador/sql/query_intermediates.hpp"
#include "matador/sql/session.hpp"
#include "matador/sql/query_compiler.hpp"
namespace matador::sql {
basic_query_intermediate::basic_query_intermediate(connection &db)
@ -7,219 +8,252 @@ basic_query_intermediate::basic_query_intermediate(connection &db)
std::shared_ptr<schema> basic_query_intermediate::tables() const
{
return connection_.tables();
return connection_.schema();
}
query_result<record> query_select_finish::fetch_all()
{
return connection_.fetch(builder_.compile());
query_compiler compiler(connection_.dialect());
return connection_.fetch(compiler.compile(&data_));
}
record query_select_finish::fetch_one()
{
return *connection_.fetch(builder_.compile()).begin().get();
query_compiler compiler(connection_.dialect());
return *connection_.fetch(compiler.compile(&data_)).begin().get();
}
std::unique_ptr<query_result_impl> query_select_finish::fetch()
{
return connection_.fetch(builder_.compile().sql);
query_compiler compiler(connection_.dialect());
return connection_.fetch(compiler.compile(&data_).sql);
}
statement query_select_finish::prepare()
{
return connection_.prepare(builder_.compile());
query_compiler compiler(connection_.dialect());
return connection_.prepare(compiler.compile(&data_));
}
query_intermediate::query_intermediate(connection &db, query_builder &query)
: basic_query_intermediate(db), builder_(query) {}
query_intermediate::query_intermediate(connection &db, query_data &data)
: basic_query_intermediate(db), data_(data) {}
query_offset_intermediate query_order_direction_intermediate::offset(size_t offset)
{
return {connection_, builder_};
return {connection_, data_};
}
query_limit_intermediate query_offset_intermediate::limit(size_t limit)
{
return {connection_, builder_};
return {connection_, data_};
}
query_limit_intermediate query_order_direction_intermediate::limit(size_t limit)
{
return {connection_, builder_};
return {connection_, data_};
}
query_order_by_intermediate query_group_by_intermediate::order_by(const std::string &name)
{
return {connection_, builder_.order_by(name)};
return {connection_, data_};
// return {connection_, builder_.order_by(name)};
}
query_order_direction_intermediate query_order_by_intermediate::asc()
{
return {connection_, builder_.asc()};
return {connection_, data_};
// return {connection_, builder_.asc()};
}
query_order_direction_intermediate query_order_by_intermediate::desc()
{
return {connection_, builder_.desc()};
return {connection_, data_};
// return {connection_, builder_.desc()};
}
query_group_by_intermediate query_from_intermediate::group_by(const std::string &name)
{
return {connection_, builder_.group_by(name)};
return {connection_, data_};
// return {connection_, builder_.group_by(name)};
}
query_order_by_intermediate query_from_intermediate::order_by(const std::string &name)
{
return {connection_, builder_.order_by(name)};
return {connection_, data_};
// return {connection_, builder_.order_by(name)};
}
query_group_by_intermediate query_where_intermediate::group_by(const std::string &name)
{
return {connection_, builder_.group_by(name)};
return {connection_, data_};
// return {connection_, builder_.group_by(name)};
}
query_order_by_intermediate query_where_intermediate::order_by(const std::string &name)
{
return {connection_, builder_.order_by(name)};
return {connection_, data_};
// return {connection_, builder_.order_by(name)};
}
query_join_intermediate query_on_intermediate::join(const std::string &join_table_name, const std::string &as)
{
return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)};
return {connection_, data_};
// return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)};
}
query_where_intermediate query_on_intermediate::where(const basic_condition &cond)
{
return {connection_, builder_.where(cond)};
return {connection_, data_};
// return {connection_, builder_.where(cond)};
}
query_group_by_intermediate query_on_intermediate::group_by(const std::string &name)
{
return {connection_, builder_.group_by(name)};
return {connection_, data_};
// return {connection_, builder_.group_by(name)};
}
query_order_by_intermediate query_on_intermediate::order_by(const std::string &name)
{
return {connection_, builder_.order_by(name)};
return {connection_, data_};
// return {connection_, builder_.order_by(name)};
}
query_on_intermediate query_join_intermediate::on(const std::string &column, const std::string &join_column)
query_on_intermediate query_join_intermediate::on(const basic_condition &cond)
{
return {connection_, builder_.on(column, join_column)};
return {connection_, data_};
// return {connection_, builder_.on(column, join_column)};
}
query_join_intermediate query_from_intermediate::join(const std::string &join_table_name, const std::string &as)
query_join_intermediate query_from_intermediate::join_left(const std::string &join_table_name, const std::string &as)
{
return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)};
return {connection_, data_};
// return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)};
}
query_where_intermediate query_from_intermediate::where(const basic_condition &cond)
{
return query_where_intermediate{connection_, builder_.where(cond)};
return query_where_intermediate{connection_, data_};
// return query_where_intermediate{connection_, builder_.where(cond)};
}
query_select_intermediate::query_select_intermediate(connection &s, const std::vector<column>& columns)
: query_start_intermediate(s)
query_select_intermediate::query_select_intermediate(connection &db, const std::vector<column>& columns)
: query_start_intermediate(db)
{
builder_.select(columns);
data_.parts.push_back(std::make_unique<query_select_part>(columns));
}
query_from_intermediate query_select_intermediate::from(const std::string &table, const std::string &as)
{
return {connection_, builder_.from(table, as)};
return {connection_, data_};
// return {connection_, builder_.from(table, as)};
}
query_insert_intermediate::query_insert_intermediate(connection &s)
: query_start_intermediate(s)
{
builder_.insert();
data_.parts.push_back(std::make_unique<query_insert_part>());
}
query_into_intermediate query_insert_intermediate::into(const std::string &table, std::initializer_list<column_info> column_names)
query_into_intermediate query_insert_intermediate::into(const std::string &table, std::initializer_list<column> column_names)
{
return {connection_, builder_.into(table, column_names)};
return {connection_, data_};
// return {connection_, builder_.into(table, column_names)};
}
size_t query_execute_finish::execute()
{
return connection_.execute(builder_.compile().sql);
query_compiler compiler(connection_.dialect());
return connection_.execute(compiler.compile(&data_).sql);
}
statement query_execute_finish::prepare()
{
return connection_.prepare(builder_.compile());
query_compiler compiler(connection_.dialect());
return connection_.prepare(compiler.compile(&data_));
}
query_execute_finish query_into_intermediate::values(std::initializer_list<any_type> values)
{
return {connection_, builder_.values(values)};
return this->values(std::vector<any_type>(values));
}
query_execute_finish query_into_intermediate::values(const std::vector<any_type> &values)
{
return {connection_, data_};
}
query_create_intermediate::query_create_intermediate(connection &db)
: query_start_intermediate(db) {
builder_.create();
data_.parts.push_back(std::make_unique<query_create_part>());
}
query_execute_finish query_create_intermediate::table(const std::string &table_name, std::initializer_list<column> columns)
query_execute_finish query_create_intermediate::table(const std::string &table_name, std::initializer_list<column_definition> columns)
{
return table(table_name, std::vector<column>{columns});
return table(table_name, std::vector<column_definition>{columns});
}
query_execute_finish query_create_intermediate::table(const std::string &table_name, const std::vector<column> &columns)
query_execute_finish query_create_intermediate::table(const std::string &table_name, const std::vector<column_definition> &columns)
{
return {connection_, builder_.table(table_name, columns)};
return {connection_, data_};
// return {connection_, builder_.table(table_name, columns)};
}
query_drop_intermediate::query_drop_intermediate(connection &s)
: query_start_intermediate(s)
{
builder_.drop();
data_.parts.push_back(std::make_unique<query_drop_part>());
}
query_execute_finish query_drop_intermediate::table(const std::string &table)
{
return {connection_, builder_.table(table)};
return {connection_, data_};
// return {connection_, builder_.table(table)};
}
query_execute_finish query_execute_where_intermediate::limit(int limit)
{
return {connection_, builder_.limit(limit)};
return {connection_, data_};
// return {connection_, builder_.limit(limit)};
}
query_execute_where_intermediate query_set_intermediate::where(const basic_condition &cond)
{
return {connection_, builder_.where(cond)};
return {connection_, data_};
// return {connection_, builder_.where(cond)};
}
query_update_intermediate::query_update_intermediate(connection &s, const std::string& table_name)
: query_start_intermediate(s)
{
builder_.update(table_name);
data_.parts.push_back(std::make_unique<query_update_part>(table_name));
}
query_set_intermediate query_update_intermediate::set(std::initializer_list<key_value_pair> columns)
{
return {connection_, builder_.set(columns)};
return {connection_, data_};
// return {connection_, builder_.set(columns)};
}
query_execute_where_intermediate query_delete_from_intermediate::where(const basic_condition &cond)
{
return {connection_, builder_.where(cond)};
return {connection_, data_};
// return {connection_, builder_.where(cond)};
}
query_delete_intermediate::query_delete_intermediate(connection &s)
: query_start_intermediate(s)
{
builder_.remove();
data_.parts.push_back(std::make_unique<query_delete_part>());
}
query_delete_from_intermediate query_delete_intermediate::from(const std::string &table)
{
return {connection_, builder_.from(table)};
return {connection_, data_};
// return {connection_, builder_.from(table)};
}
query_start_intermediate::query_start_intermediate(connection &s)
: basic_query_intermediate(s)
, builder_(s.dialect())
query_start_intermediate::query_start_intermediate(connection &db)
: basic_query_intermediate(db)
{}
}

131
src/sql/query_parts.cpp Normal file
View File

@ -0,0 +1,131 @@
#include "matador/sql/query_parts.hpp"
#include "matador/sql/basic_condition.hpp"
namespace matador::sql {
query_part::query_part(sql::dialect::token_t token)
: token_(token) {}
query_select_part::query_select_part(std::vector<column> columns)
: query_part(sql::dialect::token_t::SELECT)
, columns_(std::move(columns)) {}
void query_select_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
const std::vector<column>& query_select_part::columns() const
{
return columns_;
}
query_from_part::query_from_part(std::string table_name)
: query_part(sql::dialect::token_t::FROM)
, table_(std::move(table_name)) {}
query_from_part::query_from_part(std::string table_name, std::string as)
: query_part(sql::dialect::token_t::FROM)
, table_(std::move(table_name))
, alias_(std::move(as)) {}
void query_from_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
void query_where_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_table_name_part::query_table_name_part(sql::dialect::token_t token, std::string table_name)
: query_part(token)
, table_name_(std::move(table_name)) {}
query_group_by_part::query_group_by_part(const std::string &table_name)
: query_table_name_part(dialect::token_t::GROUP_BY, table_name)
{}
void query_group_by_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_order_by_part::query_order_by_part(const std::string &table_name)
: query_table_name_part(dialect::token_t::ORDER_BY, table_name)
{}
void query_order_by_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_order_by_asc_part::query_order_by_asc_part()
: query_part(dialect::token_t::ASC)
{}
void query_order_by_asc_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_order_by_desc_part::query_order_by_desc_part()
: query_part(dialect::token_t::DESC)
{}
void query_order_by_desc_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_insert_part::query_insert_part()
: query_part(dialect::token_t::INSERT) {}
void query_insert_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_values_part::query_values_part(std::initializer_list<any_type> values)
: query_part(sql::dialect::token_t::VALUES)
, values_(values) {}
void query_values_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_update_part::query_update_part(const std::string &table_name)
: query_table_name_part(dialect::token_t::UPDATE, table_name) {}
void query_update_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_delete_part::query_delete_part()
: query_part(sql::dialect::token_t::REMOVE) {}
void query_delete_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_create_part::query_create_part()
: query_part(sql::dialect::token_t::CREATE) {}
void query_create_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
query_drop_part::query_drop_part()
: query_part(sql::dialect::token_t::DROP) {}
void query_drop_part::accept(query_part_visitor &visitor)
{
visitor.visit(*this);
}
}

View File

@ -5,13 +5,13 @@
namespace matador::sql {
record::record(std::initializer_list<column> columns)
record::record(std::initializer_list<column_definition> columns)
: columns_(columns)
{
init();
}
record::record(const std::vector<column> &columns)
record::record(const std::vector<column_definition> &columns)
: columns_(columns)
{
init();
@ -41,7 +41,7 @@ record &record::operator=(const record &x)
return *this;
}
const std::vector<column> &record::columns() const
const std::vector<column_definition> &record::columns() const
{
return columns_;
}
@ -51,7 +51,7 @@ bool record::has_primary_key() const
return pk_index_ > -1;
}
const column &record::primary_key() const
const column_definition &record::primary_key() const
{
if (!has_primary_key()) {
throw std::logic_error("record has no primary key");
@ -60,13 +60,13 @@ const column &record::primary_key() const
return columns_[pk_index_];
}
const column &record::at(const std::string &name) const
const column_definition &record::at(const std::string &name) const
{
auto ref = columns_by_name_.at(name).first;
return columns_by_name_.at(name).first;
}
const column &record::at(size_t index) const
const column_definition &record::at(size_t index) const
{
return columns_.at(index);
}
@ -82,7 +82,7 @@ record::const_iterator record::find(const std::string &column_name) const {
return it != columns_by_name_.end() ? columns_.begin() + it->second.second : columns_.end();
}
void record::append(column col)
void record::append(column_definition col)
{
auto &ref = columns_.emplace_back(std::move(col));
add_to_map(ref, columns_.size()-1);
@ -149,7 +149,7 @@ void record::init()
}
}
void record::add_to_map(column &col, size_t index)
void record::add_to_map(column_definition &col, size_t index)
{
columns_by_name_.emplace(col.name(), column_index_pair {std::ref(col), index});
if (utils::is_constraint_set(col.attributes().options(), utils::constraints::PRIMARY_KEY)) {

View File

@ -7,12 +7,17 @@ namespace matador::sql {
void table_info::create(connection &conn) const
{
conn.create().table(name, prototype.columns()).execute();
conn.query().create().table(name, prototype.columns()).execute();
}
void table_info::drop(connection &conn) const
{
conn.drop().table(name).execute();
conn.query().drop().table(name).execute();
}
std::string schema::name() const
{
return name_;
}
const table_info& schema::attach(const std::type_index ti, const table_info& table)
@ -71,4 +76,5 @@ bool schema::empty() const
{
return repository_.empty();
}
}

View File

@ -25,7 +25,7 @@ void session::drop_table(const std::string &table_name)
throw std::logic_error("no database connection available");
}
c->drop().table(table_name).execute();
c->query().drop().table(table_name).execute();
}
query_result<record> session::fetch(const query_context &q) const
@ -41,7 +41,7 @@ query_result<record> session::fetch(const query_context &q) const
// adjust columns from given query
for (auto &col : q.prototype) {
if (const auto rit = it->second.find(col.name()); col.type() == data_type_t::type_unknown && rit != it->second.end()) {
const_cast<column&>(col).type(rit->type());
const_cast<column_definition&>(col).type(rit->type());
}
}
auto res = c->fetch(q.sql);

View File

@ -14,16 +14,16 @@ TEST_CASE("Generate columns from object", "[column generator]") {
auto columns = column_generator::generate<matador::test::product>(repo);
const std::vector<column> expected_columns = {
column{ "product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column{ "supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column{ "category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column{ "quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column{ "unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column{ "units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column{ "units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column{ "reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column{ "discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL }
const std::vector<column_definition> expected_columns = {
column_definition{"product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL }
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
@ -40,10 +40,10 @@ TEST_CASE("Generate columns from object with nullable columns", "[column generat
auto columns = column_generator::generate<matador::test::optional>(repo);
const std::vector<column> expected_columns = {
column{ "id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column{ "name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column{ "age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }
const std::vector<column_definition> expected_columns = {
column_definition{"id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());

View File

@ -1,11 +1,11 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/sql/column.hpp"
#include "matador/sql/column_definition.hpp"
using namespace matador::sql;
TEST_CASE("Create empty column", "[column]") {
column c("name");
column_definition c("name");
REQUIRE(c.name() == "name");
REQUIRE(c.index() == 0);
@ -25,7 +25,7 @@ TEST_CASE("Create empty column", "[column]") {
}
TEST_CASE("Copy and move column", "[column]") {
column c("name");
column_definition c("name");
c.set(std::string{"george"}, 255);
REQUIRE(c.name() == "name");
REQUIRE(c.index() == 0);

View File

@ -1,6 +1,6 @@
#include <catch2/catch_test_macros.hpp>
#include <matador/sql/column.hpp>
#include <matador/sql/column_definition.hpp>
#include <matador/sql/condition.hpp>
#include <matador/sql/dialect_builder.hpp>
#include <matador/sql/query_builder.hpp>
@ -164,7 +164,7 @@ TEST_CASE("Create, insert and select a blob column", "[query][blob]") {
REQUIRE(q.table_name == "person");
q = query.insert().into("person", {
{"", "id", ""}, {"", "name", ""}, {"", "data", ""}
{ "id", "name", "data" }
}).values({7UL, "george", blob{1, 'A', 3, 4}}).compile();
REQUIRE(q.sql == R"(INSERT INTO "person" ("id", "name", "data") VALUES (7, 'george', X'01410304'))");
@ -176,7 +176,7 @@ TEST_CASE("Create, insert and select a blob column", "[query][blob]") {
REQUIRE(q.table_name == "person");
}
TEST_CASE("Select statement with join", "[query][join]") {
TEST_CASE("Select statement with join_left", "[query][join_left]") {
dialect d = dialect_builder::builder().create().build();
query_builder query(d);