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 type = PQftype(res, i);
auto size = PQfmod(res, i); auto size = PQfmod(res, i);
// std::cout << "column " << col_name << ", type " << type << " (size: " << size << ")\n"; // 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))); 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()) { if (context->prototype.empty()) {
for(int i = 0; i < column_count; ++i) { 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/column.hpp"
#include "matador/sql/condition.hpp" #include "matador/sql/condition.hpp"
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "matador/sql/query_builder.hpp"
#include "connection.hpp" #include "connection.hpp"
@ -29,7 +30,7 @@ protected:
private: private:
void drop_table_if_exists(const std::string &table_name) { void drop_table_if_exists(const std::string &table_name) {
if (db.exists(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]") TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[session][record]")
{ {
REQUIRE(!db.exists("person")); REQUIRE(!db.exists("person"));
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -49,7 +50,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi
REQUIRE(db.exists("person")); REQUIRE(db.exists("person"));
db.drop() db.query().drop()
.table("person") .table("person")
.execute(); .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]") TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with foreign key", "[session][record]")
{ {
db.create() db.query().create()
.table("airplane", { .table("airplane", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("brand", 255), 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")); REQUIRE(db.exists("airplane"));
db.create() db.query().create()
.table("flight", { .table("flight", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_fk_column<unsigned long>("airplane_id", "airplane", "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")); REQUIRE(db.exists("flight"));
db.drop() db.query().drop()
.table("flight") .table("flight")
.execute(); .execute();
REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("flight"));
db.drop() db.query().drop()
.table("airplane") .table("airplane")
.execute(); .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]") TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -101,14 +102,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi
}) })
.execute(); .execute();
auto res = db.insert() auto res = db.query().insert()
.into("person", {"id", "name", "age"}) .into("person", {"id", "name", "age"})
.values({7, "george", 45}) .values({7, "george", 45})
.execute(); .execute();
REQUIRE(res == 1); REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"}) auto result = db.query().select({"id", "name", "age"})
.from("person") .from("person")
.fetch_all(); .fetch_all();
@ -125,14 +126,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi
REQUIRE(i.at(2).template as<int>() == 45); REQUIRE(i.at(2).template as<int>() == 45);
} }
db.drop() db.query().drop()
.table("person") .table("person")
.execute(); .execute();
} }
TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with foreign key", "[session][record]") TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with foreign key", "[session][record]")
{ {
db.create() db.query().create()
.table("airplane", { .table("airplane", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("brand", 255), make_column<std::string>("brand", 255),
@ -140,7 +141,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore
}) })
.execute(); .execute();
db.create() db.query().create()
.table("flight", { .table("flight", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_fk_column<unsigned long>("airplane_id", "airplane", "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(); .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); 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); 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); 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); 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); REQUIRE(res == 1);
db.drop().table("flight").execute(); db.query().drop().table("flight").execute();
db.drop().table("airplane").execute(); db.query().drop().table("airplane").execute();
REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("flight"));
REQUIRE(!db.exists("airplane")); 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]") TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -180,14 +181,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
}) })
.execute(); .execute();
auto res = db.insert() auto res = db.query().insert()
.into("person", {"id", "name", "age"}) .into("person", {"id", "name", "age"})
.values({7, "george", 45}) .values({7, "george", 45})
.execute(); .execute();
REQUIRE(res == 1); REQUIRE(res == 1);
res = db.update("person") res = db.query().update("person")
.set({{"id", 7}, .set({{"id", 7},
{"name", "jane"}, {"name", "jane"},
{"age", 35}}) {"age", 35}})
@ -196,7 +197,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
REQUIRE(res == 1); REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"}) auto result = db.query().select({"id", "name", "age"})
.from("person") .from("person")
.fetch_all(); .fetch_all();
@ -213,12 +214,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi
REQUIRE(i.at(2).as<int>() == 35); 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]") TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -226,16 +227,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec
}) })
.execute(); .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); 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); 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); 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); REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"}) auto result = db.query().select({"id", "name", "age"})
.from("person") .from("person")
.fetch_all(); .fetch_all();
@ -246,22 +247,22 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec
} }
REQUIRE(expected_names.empty()); REQUIRE(expected_names.empty());
auto rec = db.select({"id", "name", "age"}) auto rec = db.query().select({"id", "name", "age"})
.from("person") .from("person")
.fetch_one(); .fetch_one();
REQUIRE(rec.at(1).str() == "george"); REQUIRE(rec.at(1).str() == "george");
auto name = db.select({"name"}) auto name = db.query().select({"name"})
.from("person") .from("person")
.fetch_value<std::string>(); .fetch_value<std::string>();
REQUIRE(name == "george"); 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]") TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -269,16 +270,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by",
}) })
.execute(); .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); 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); 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); 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); REQUIRE(res == 1);
auto result = db.select({"id", "name", "age"}) auto result = db.query().select({"id", "name", "age"})
.from("person") .from("person")
.order_by("name").asc() .order_by("name").asc()
.fetch_all(); .fetch_all();
@ -290,12 +291,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by",
} }
REQUIRE(expected_names.empty()); 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]") TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by and order by", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -303,18 +304,18 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an
}) })
.execute(); .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); 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); 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); 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); 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); 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") .from("person")
.group_by("age") .group_by("age")
.order_by("age_count").desc() .order_by("age_count").desc()
@ -329,41 +330,41 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an
expected_values.pop_front(); expected_values.pop_front();
} }
db.drop().table("person").execute(); db.query().drop().table("person").execute();
} }
TEST_CASE_METHOD(QueryRecordFixture, " Execute delete statement", "[session][record]") TEST_CASE_METHOD(QueryRecordFixture, " Execute delete statement", "[session][record]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
make_column<unsigned short>("age") make_column<unsigned short>("age")
}).execute(); }).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); 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); 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); REQUIRE(count == 2);
res = db.remove() res = db.query().remove()
.from("person") .from("person")
.where("id"_col == 1) .where("id"_col == 1)
.execute(); .execute();
REQUIRE(res == 1); 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); REQUIRE(count == 1);
db.drop().table("person").execute(); db.query().drop().table("person").execute();
} }
TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][record]") { TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][record]") {
db.create() db.query().create()
.table("quotes", { .table("quotes", {
make_column<std::string>("from", 255), make_column<std::string>("from", 255),
make_column<std::string>("to", 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()]); 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("Berlin" == res.at("from").str());
REQUIRE("London" == res.at("to").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("Hamburg" == res.at("from").str());
REQUIRE("New York" == res.at("to").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 "catch2/catch_test_macros.hpp"
#include "matador/sql/column.hpp" #include "matador/sql/column_definition.hpp"
#include "matador/sql/condition.hpp" #include "matador/sql/condition.hpp"
#include "matador/sql/query_builder.hpp"
#include "matador/sql/session.hpp" #include "matador/sql/session.hpp"
#include "connection.hpp" #include "connection.hpp"
@ -36,27 +37,27 @@ private:
void drop_table_if_exists(const std::string &table_name) void drop_table_if_exists(const std::string &table_name)
{ {
if (db.exists(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]") TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[session]")
{ {
db.create() db.query().create()
.table<airplane>("airplane") .table<airplane>("airplane")
.execute(); .execute();
REQUIRE(db.exists("airplane")); REQUIRE(db.exists("airplane"));
db.create() db.query().create()
.table<flight>("flight") .table<flight>("flight")
.execute(); .execute();
REQUIRE(db.exists("flight")); REQUIRE(db.exists("flight"));
db.drop().table("flight").execute(); db.query().drop().table("flight").execute();
db.drop().table("airplane").execute(); db.query().drop().table("airplane").execute();
REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("flight"));
REQUIRE(!db.exists("airplane")); 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]") TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[session]")
{ {
db.create() db.query().create()
.table<person>("person") .table<person>("person")
.execute(); .execute();
person george{7, "george", 45}; person george{7, "george", 45};
george.image.push_back(37); george.image.push_back(37);
auto res = db.insert() auto res = db.query().insert()
.into("person", george) .into("person", george)
.execute(); .execute();
REQUIRE(res == 1); REQUIRE(res == 1);
// fetch person as record // fetch person as record
auto result_record = db.select<person>() auto result_record = db.query().select<person>()
.from("person") .from("person")
.where("id"_col == 7) .where("id"_col == 7)
.fetch_all(); .fetch_all();
@ -96,7 +97,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[
} }
// fetch person as person // fetch person as person
auto result_person = db.select<person>() auto result_person = db.query().select<person>()
.from("person") .from("person")
.where("id"_col == 7) .where("id"_col == 7)
.fetch_all<person>(); .fetch_all<person>();
@ -107,12 +108,12 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[
REQUIRE(i.age == 45); REQUIRE(i.age == 45);
} }
db.drop().table("person").execute(); db.query().drop().table("person").execute();
} }
TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
{ {
db.create() db.query().create()
.table("person", { .table("person", {
make_pk_column<unsigned long>("id"), make_pk_column<unsigned long>("id"),
make_column<std::string>("name", 255), make_column<std::string>("name", 255),
@ -120,7 +121,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
}) })
.execute(); .execute();
auto res = db.insert() auto res = db.query().insert()
.into("person", {{"", "id", ""}, {"", "name", ""}, {"", "color", ""}}) .into("person", {{"", "id", ""}, {"", "name", ""}, {"", "color", ""}})
.values({7, "george", "green"}) .values({7, "george", "green"})
.execute(); .execute();
@ -128,7 +129,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
REQUIRE(res == 1); REQUIRE(res == 1);
// fetch person as record // fetch person as record
auto result_record = db.select({"id", "name", "color"}) auto result_record = db.query().select({"id", "name", "color"})
.from("person") .from("person")
.where("id"_col == 7) .where("id"_col == 7)
.fetch_all(); .fetch_all();
@ -146,16 +147,16 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]")
REQUIRE(i.at(2).as<std::string>() == "green"); 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]") TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]")
{ {
db.create() db.query().create()
.table<airplane>("airplane") .table<airplane>("airplane")
.execute(); .execute();
db.create() db.query().create()
.table<flight>("flight") .table<flight>("flight")
.execute(); .execute();
@ -166,35 +167,35 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]"
}; };
for (const auto &plane: planes) { 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); 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); REQUIRE(count == 3);
flight f4711{4, planes.at(1), "hans"}; 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); 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.id == 4);
REQUIRE(f.pilot_name == "hans"); REQUIRE(f.pilot_name == "hans");
REQUIRE(f.airplane.get() != nullptr); REQUIRE(f.airplane.get() != nullptr);
REQUIRE(f.airplane->id == 2); REQUIRE(f.airplane->id == 2);
db.drop().table("flight").execute(); db.query().drop().table("flight").execute();
db.drop().table("airplane").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") .table<airplane>("airplane")
.execute(); .execute();
db.create() db.query().create()
.table<flight>("flight") .table<flight>("flight")
.execute(); .execute();
@ -205,11 +206,11 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[
}; };
for (const auto &plane: planes) { 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); 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); REQUIRE(count == 3);
std::vector<entity<flight>> flights{ 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) { 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); 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.id == 4);
REQUIRE(f.pilot_name == "hans"); REQUIRE(f.pilot_name == "hans");
REQUIRE(f.airplane.get() != nullptr); REQUIRE(f.airplane.get() != nullptr);
REQUIRE(f.airplane->id == 1); REQUIRE(f.airplane->id == 1);
auto result = db.select({"f.id", "ap.brand", "ap.model", "f.pilot_name"}) auto result = db.query().select({"f.id", "ap.brand", "ap.model", "f.pilot_name"})
.from("flight", "f") .from("flight", "f")
.join("airplane", "ap") .join_left("airplane", "ap")
.on("f.airplane_id", "ap.id") .on("f.airplane_id"_col == "ap.id"_col)
.order_by("f.id").asc() .order_by("f.id").asc()
.fetch_all(); .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); REQUIRE(r.at(3).as<std::string>() == expected_result[index++].second);
} }
db.drop().table("flight").execute(); db.query().drop().table("flight").execute();
db.drop().table("airplane").execute(); db.query().drop().table("airplane").execute();
} }

View File

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

View File

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

View File

@ -1,10 +1,75 @@
#include <cstdlib> #include "matador/sql/column.hpp"
#include <iostream> #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> #include <string>
int main() { 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"}; 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]; // char var[1024];
// size_t len{}; // size_t len{};
// const auto error = getenv_s(&len, var, 1024, env_var.c_str()); // const auto error = getenv_s(&len, var, 1024, env_var.c_str());

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 #ifndef QUERY_COLUMN_HPP
#define QUERY_COLUMN_HPP #define QUERY_COLUMN_HPP
#include "matador/sql/any_type.hpp" #include <string>
#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 { namespace matador::sql {
enum class null_option : uint8_t { enum class sql_function_t {
NULLABLE, NOT_NULL NONE,
COUNT,
AVG,
SUM,
MIN,
MAX
}; };
class column { struct 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)
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_);
}
[[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()); column(const char *name) : name(name) {} // NOLINT(*-explicit-constructor)
attributes_ = attr; column(std::string name) : name(std::move(name)) {} // NOLINT(*-explicit-constructor)
value_ = value; 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& as(std::string a) {
alias = std::move(a);
return *this;
} }
void set(const std::string &value, const utils::field_attributes &attr) [[nodiscard]] bool is_function() const {
{ return function_ != sql_function_t::NONE;
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
} }
void set(const char *value, const utils::field_attributes &attr) std::string table;
{ std::string name;
type_ = data_type_traits<std::string>::builtin_type(attr.size()); std::string alias;
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_;
sql_function_t function_{sql_function_t::NONE}; 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 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 #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 #ifndef QUERY_COLUMN_GENERATOR_HPP
#define 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/sql/data_type_traits.hpp"
#include "matador/utils/access.hpp" #include "matador/utils/access.hpp"
@ -21,10 +21,10 @@ public:
fk_column_generator() = default; fk_column_generator() = default;
template<class Type> 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); 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> template<typename ValueType>
@ -53,15 +53,15 @@ private:
class column_generator class column_generator
{ {
private: private:
column_generator(std::vector<column> &columns, const schema &repo); column_generator(std::vector<column_definition> &columns, const schema &repo);
public: public:
~column_generator() = default; ~column_generator() = default;
template < class Type > 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); column_generator gen(columns, repo);
Type obj; Type obj;
matador::utils::access::process(gen, obj); matador::utils::access::process(gen, obj);
@ -101,7 +101,7 @@ private:
private: private:
size_t index_ = 0; size_t index_ = 0;
std::vector<column> &columns_; std::vector<column_definition> &columns_;
const schema &repo_; const schema &repo_;
fk_column_generator fk_column_generator_; fk_column_generator fk_column_generator_;

View File

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

View File

@ -7,6 +7,7 @@
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
#include <memory> #include <memory>
#include <utility>
namespace matador::sql { namespace matador::sql {
@ -55,8 +56,8 @@ public:
std::string evaluate(dialect &d, query_context &query) const override 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()) + " " + operand + " " + std::to_string(value); 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 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()) + " " + operand + " '" + value + "'"; return d.prepare_identifier(field_.name) + " " + operand + " '" + value + "'";
} }
}; };
@ -96,7 +97,7 @@ public:
std::string evaluate(dialect &d, query_context &query) const override 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 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 { std::string evaluate(dialect &d, query_context &query) const override {
auto count = size(); auto count = size();
for (size_t i = 0; i < count; ++i) { 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) { if (args_.size() < 2) {
for (const auto &val : args_) { for (const auto &val : args_) {
result.append(std::to_string(val)); result.append(std::to_string(val));
@ -261,9 +262,9 @@ public:
* @return A condition BETWEEN part of the query * @return A condition BETWEEN part of the query
*/ */
std::string evaluate(dialect &d, query_context &query) const override { std::string evaluate(dialect &d, query_context &query) const override {
query.bind_vars.emplace_back(field_.name()); query.bind_vars.emplace_back(field_.name);
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); return d.prepare_identifier(field_.name) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second);
} }
private: private:
@ -355,6 +356,28 @@ private:
std::string operand; 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 * @file condition.hpp
* @brief Contains functions to create query conditions * @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); 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 * @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_info.hpp"
#include "matador/sql/connection_impl.hpp" #include "matador/sql/connection_impl.hpp"
#include "matador/sql/dialect.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_context.hpp"
#include "matador/sql/query_result.hpp" #include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp" #include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
#include "matador/utils/logger.hpp" #include "matador/utils/logger.hpp"
@ -19,8 +20,8 @@ namespace matador::sql {
class connection class connection
{ {
public: public:
explicit connection(connection_info info, 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<schema>()); explicit connection(const std::string& dns, const std::shared_ptr<schema> &repo = std::make_shared<sql::schema>());
connection(const connection &x); connection(const connection &x);
connection& operator=(const connection &x); connection& operator=(const connection &x);
connection(connection &&x) noexcept = default; connection(connection &&x) noexcept = default;
@ -31,19 +32,12 @@ public:
[[nodiscard]] bool is_open() const; [[nodiscard]] bool is_open() const;
[[nodiscard]] const connection_info& info() 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]] 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 &schema_name, const std::string &table_name) const;
[[nodiscard]] bool exists(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; query_result<record> fetch(const query_context &q) const;
[[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const; [[nodiscard]] std::unique_ptr<query_result_impl> fetch(const std::string &sql) const;
[[nodiscard]] size_t execute(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; statement prepare(query_context &&query) const;
const class dialect& dialect() const; const class dialect& dialect() const;
std::shared_ptr<schema> tables() const; std::shared_ptr<sql::schema> schema() const;
private: private:
connection_info connection_info_; connection_info connection_info_;
std::unique_ptr<connection_impl> connection_; std::unique_ptr<connection_impl> connection_;
utils::logger logger_; utils::logger logger_;
const class dialect &dialect_; 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 #endif //QUERY_CONNECTION_HPP

View File

@ -41,16 +41,6 @@ enum class data_type_t : uint8_t {
type_unknown /*!< Data type unknown */ type_unknown /*!< Data type unknown */
}; };
enum class sql_function_t {
NONE,
COUNT,
AVG,
SUM,
MIN,
MAX
};
/** /**
* @tparam T The type of the traits * @tparam T The type of the traits
* @brief Type traits for database types * @brief Type traits for database types

View File

@ -1,6 +1,7 @@
#ifndef QUERY_DIALECT_HPP #ifndef QUERY_DIALECT_HPP
#define QUERY_DIALECT_HPP #define QUERY_DIALECT_HPP
#include "matador/sql/column.hpp"
#include "matador/sql/data_type_traits.hpp" #include "matador/sql/data_type_traits.hpp"
#include <cstdint> #include <cstdint>
@ -11,8 +12,6 @@
namespace matador::sql { namespace matador::sql {
class column;
class dialect final class dialect final
{ {
public: 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 #define QUERY_QUERY_BUILDER_HPP
#include "matador/sql/basic_condition.hpp" #include "matador/sql/basic_condition.hpp"
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column.hpp" #include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/sql/key_value_pair.hpp" #include "matador/sql/key_value_pair.hpp"
@ -123,11 +124,11 @@ public:
query_builder& update(const std::string &table); query_builder& update(const std::string &table);
query_builder& remove(); query_builder& remove();
query_builder& table(const std::string &table, std::initializer_list<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> &columns); query_builder& table(const std::string &table, const std::vector<column_definition> &columns);
query_builder& table(const std::string &table); 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, std::initializer_list<column> column_names);
query_builder& into(const std::string &table, const std::vector<column_info> &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(std::initializer_list<any_type> values);
query_builder& values(const std::vector<any_type> &values); query_builder& values(const std::vector<any_type> &values);
query_builder& from(const std::string &table, const std::string &as = ""); 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 #ifndef QUERY_QUERY_INTERMEDIATES_HPP
#define 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_generator.hpp"
#include "matador/sql/column_name_generator.hpp" #include "matador/sql/column_name_generator.hpp"
#include "matador/sql/key_value_generator.hpp" #include "matador/sql/key_value_generator.hpp"
#include "matador/sql/key_value_pair.hpp" #include "matador/sql/key_value_pair.hpp"
#include "matador/sql/placeholder_generator.hpp" #include "matador/sql/placeholder_generator.hpp"
#include "matador/sql/query_builder.hpp"
#include "matador/sql/query_result.hpp" #include "matador/sql/query_result.hpp"
#include "matador/sql/query_data.hpp"
#include "matador/sql/record.hpp" #include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp" #include "matador/sql/schema.hpp"
@ -36,10 +36,10 @@ protected:
class query_intermediate : public basic_query_intermediate class query_intermediate : public basic_query_intermediate
{ {
public: public:
query_intermediate(connection &db, query_builder &query); query_intermediate(connection &db, query_data &data);
protected: protected:
query_builder &builder_; query_data &data_;
}; };
class query_execute_finish : public query_intermediate class query_execute_finish : public query_intermediate
@ -146,7 +146,7 @@ class query_join_intermediate : public query_intermediate
public: public:
using query_intermediate::query_intermediate; 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 class query_from_intermediate : public query_select_finish
@ -154,7 +154,7 @@ class query_from_intermediate : public query_select_finish
public: public:
using query_select_finish::query_select_finish; 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_where_intermediate where(const basic_condition &cond);
query_group_by_intermediate group_by(const std::string &name); query_group_by_intermediate group_by(const std::string &name);
query_order_by_intermediate order_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 class query_start_intermediate : public basic_query_intermediate
{ {
public: public:
explicit query_start_intermediate(connection &s); explicit query_start_intermediate(connection &db);
protected: protected:
query_builder builder_; query_data data_;
}; };
class query_select_intermediate : public query_start_intermediate class query_select_intermediate : public query_start_intermediate
@ -192,16 +192,19 @@ public:
using query_intermediate::query_intermediate; using query_intermediate::query_intermediate;
query_execute_finish values(std::initializer_list<any_type> values); query_execute_finish values(std::initializer_list<any_type> values);
query_execute_finish values(const std::vector<any_type>& values);
template<class Type> template<class Type>
query_execute_finish values() query_execute_finish values()
{ {
Type obj; Type obj;
return {connection_, builder_.values(as_placeholder(obj))}; return {connection_, data_};
// return {connection_, builder_.values(as_placeholder(obj))};
} }
template<class Type> template<class Type>
query_execute_finish values(const Type &obj) 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: public:
explicit query_create_intermediate(connection &db); 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, std::initializer_list<column_definition> columns);
query_execute_finish table(const std::string &table_name, const std::vector<column> &columns); query_execute_finish table(const std::string &table_name, const std::vector<column_definition> &columns);
template<class Type> template<class Type>
query_execute_finish table(const std::string &table_name) query_execute_finish table(const std::string &table_name)
{ {
if (!tables()->exists<Type>()) { if (!tables()->exists<Type>()) {
tables()->attach<Type>(table_name); 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: public:
explicit query_insert_intermediate(connection &s); 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> template<class Type>
query_into_intermediate into(const std::string &table) 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> template<class Type>
query_execute_finish into(const std::string &table, const Type &obj) query_execute_finish into(const std::string &table, const Type &obj)
{ {
return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables())) return {connection_, data_};
.values(value_extractor::extract(obj))}; // return {connection_, builder_.into(table, column_name_generator::generate<Type>(*tables()))
// .values(value_extractor::extract(obj))};
} }
}; };
@ -274,7 +280,8 @@ public:
template<class Type> template<class Type>
query_set_intermediate set(const Type &obj) 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/utils/access.hpp"
#include "matador/sql/column.hpp" #include "matador/sql/column_definition.hpp"
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
@ -13,8 +13,8 @@ namespace matador::sql {
class record class record
{ {
private: private:
using column_by_index = std::vector<column>; using column_by_index = std::vector<column_definition>;
using column_index_pair = std::pair<std::reference_wrapper<column>, size_t>; 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>; using column_by_name_map = std::unordered_map<std::string, column_index_pair>;
public: public:
@ -22,8 +22,8 @@ public:
using const_iterator = column_by_index::const_iterator; using const_iterator = column_by_index::const_iterator;
record() = default; record() = default;
record(std::initializer_list<column> columns); record(std::initializer_list<column_definition> columns);
explicit record(const std::vector<column> &columns); explicit record(const std::vector<column_definition> &columns);
record(const record &x); record(const record &x);
record& operator=(const record &x); record& operator=(const record &x);
record(record&&) noexcept = default; record(record&&) noexcept = default;
@ -43,15 +43,15 @@ public:
append(make_column<Type>(name, size)); append(make_column<Type>(name, size));
} }
void append(column col); void append(column_definition col);
[[nodiscard]] bool has_primary_key() const; [[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_definition& at(const std::string &name) const;
[[nodiscard]] const column& at(size_t index) const; [[nodiscard]] const column_definition& at(size_t index) const;
iterator find(const std::string &column_name); iterator find(const std::string &column_name);
[[nodiscard]] const_iterator find(const std::string &column_name) const; [[nodiscard]] const_iterator find(const std::string &column_name) const;
@ -72,7 +72,7 @@ public:
private: private:
void init(); void init();
void add_to_map(column &col, size_t index); void add_to_map(column_definition &col, size_t index);
private: private:
column_by_index columns_; column_by_index columns_;

View File

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

View File

@ -74,7 +74,7 @@ entity<Type> session::insert(Type *obj)
if (!info) { if (!info) {
return {}; return {};
} }
c->insert().into<Type>(info->name).values(*obj).execute(); c->query().insert().into<Type>(info->name).values(*obj).execute();
return entity{obj}; 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 * given stream
* *
* @tparam R Type og the range (e.g. map, list, vector, etc) * @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 * @param delim The delimiter for the elements
* @return The ostream reference * @return The ostream reference
*/ */

View File

@ -1,7 +1,7 @@
set(SQL_SOURCES set(SQL_SOURCES
sql/dialect.cpp sql/dialect.cpp
sql/query_builder.cpp sql/query_builder.cpp
sql/column.cpp sql/column_definition.cpp
sql/key_value_pair.cpp sql/key_value_pair.cpp
sql/basic_condition.cpp sql/basic_condition.cpp
sql/connection.cpp sql/connection.cpp
@ -28,12 +28,16 @@ set(SQL_SOURCES
sql/result_parameter_binder.cpp sql/result_parameter_binder.cpp
sql/statement.cpp sql/statement.cpp
sql/convert.cpp sql/convert.cpp
sql/column.cpp
sql/query.cpp
sql/query_parts.cpp
sql/query_compiler.cpp
) )
set(SQL_HEADER set(SQL_HEADER
../include/matador/sql/dialect.hpp ../include/matador/sql/dialect.hpp
../include/matador/sql/query_builder.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/data_type_traits.hpp
../include/matador/sql/key_value_pair.hpp ../include/matador/sql/key_value_pair.hpp
../include/matador/sql/basic_condition.hpp ../include/matador/sql/basic_condition.hpp
@ -69,6 +73,34 @@ set(SQL_HEADER
../include/matador/sql/placeholder_generator.hpp ../include/matador/sql/placeholder_generator.hpp
../include/matador/sql/result_parameter_binder.hpp ../include/matador/sql/result_parameter_binder.hpp
../include/matador/sql/convert.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 set(UTILS_HEADER
@ -84,7 +116,8 @@ set(UTILS_HEADER
../include/matador/utils/enum_mapper.hpp ../include/matador/utils/enum_mapper.hpp
../include/matador/utils/types.hpp ../include/matador/utils/types.hpp
../include/matador/utils/foreign_attributes.hpp ../include/matador/utils/foreign_attributes.hpp
../include/matador/utils/fetch_type.hpp) ../include/matador/utils/fetch_type.hpp
)
set(UTILS_SOURCES set(UTILS_SOURCES
utils/field_attributes.cpp utils/field_attributes.cpp
@ -95,8 +128,14 @@ set(UTILS_SOURCES
utils/identifier.cpp utils/identifier.cpp
sql/value_extractor.cpp sql/value_extractor.cpp
utils/logger.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) target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include)
#set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX) #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 "matador/sql/column.hpp"
#include <utility>
namespace matador::sql { 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
{
return name_;
}
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) column operator ""_col(const char *name, size_t len)
{ {
return {std::string(name, len)}; return {{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 { 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) : columns_(columns)
, repo_(repo) , repo_(repo)
{} {}

View File

@ -2,7 +2,7 @@
namespace matador::sql { 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 sql::schema &ts,
const std::string &table_name) const std::string &table_name)
: column_infos_(column_infos) : column_infos_(column_infos)
@ -25,7 +25,7 @@ void column_name_generator::push(const std::string &column_name)
{ {
char str[4]; char str[4];
snprintf(str, 4, "c%02d", ++column_index); 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 std::string condition<column, placeholder, std::enable_if<true>::type>::evaluate(dialect &d, query_context &query) const
{ {
query.bind_vars.emplace_back(field_.name()); query.bind_vars.emplace_back(field_.name);
return d.prepare_identifier(field_.name()) + " " + operand + " " + d.next_placeholder(query.bind_vars); 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) 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 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 += (")"); result += (")");
return 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 { 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)) : connection_info_(std::move(info))
, logger_(stdout, "SQL") , logger_(stdout, "SQL")
, dialect_(backend_provider::instance().connection_dialect(connection_info_.type)) , 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_.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) : connection(connection_info::parse(dns), repo)
{} {}
@ -69,36 +69,6 @@ const connection_info &connection::info() const
return connection_info_; 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 record connection::describe(const std::string &table_name) const
{ {
return std::move(connection_->describe(table_name)); return std::move(connection_->describe(table_name));
@ -120,13 +90,18 @@ size_t connection::execute(const std::string &sql) const
return connection_->execute(sql); 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 query_result<record> connection::fetch(const query_context &q) const
{ {
if (q.prototype.empty() || q.prototype.unknown()) { if (q.prototype.empty() || q.prototype.unknown()) {
const auto table_prototype = describe(q.table_name); const auto table_prototype = describe(q.table_name);
for (auto &col : q.prototype) { 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()) { 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());
} }
} }
} }
@ -160,7 +135,7 @@ const class dialect &connection::dialect() const
return dialect_; return dialect_;
} }
std::shared_ptr<schema> connection::tables() const std::shared_ptr<schema> connection::schema() const
{ {
return schema_; return schema_;
} }

View File

@ -1,5 +1,5 @@
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/sql/column.hpp" #include "matador/sql/column_definition.hpp"
#include "matador/utils/string.hpp" #include "matador/utils/string.hpp"
@ -19,12 +19,12 @@ std::string dialect::prepare_identifier(const column &col) const
{ {
std::string result; std::string result;
if (!col.is_function()) { if (!col.is_function()) {
result = prepare_identifier_string(col.name()); result = prepare_identifier_string(col.name);
} else { } else {
result = sql_func_map_.at(col.function()) + "(" + col.name() + ")"; result = sql_func_map_.at(col.function_) + "(" + col.name + ")";
} }
if (!col.alias().empty()) { if (!col.alias.empty()) {
result += " AS " + col.alias(); result += " AS " + col.alias;
} }
return result; 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/query_builder.hpp"
#include "matador/sql/column_name_generator.hpp" #include "matador/sql/column_name_generator.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/utils/string.hpp" #include "matador/utils/string.hpp"
@ -139,19 +140,19 @@ query_builder &query_builder::select(const std::vector<column> &columns)
if (columns.size() < 2) { if (columns.size() < 2) {
for (const auto &col: columns) { for (const auto &col: columns) {
result.append(dialect_.prepare_identifier(col)); result.append(dialect_.prepare_identifier(col));
query_.result_vars.emplace_back(col.name()); query_.result_vars.emplace_back(col.name);
query_.prototype.append(col); query_.prototype.append(column_definition{col.name});
} }
} else { } else {
auto it = columns.begin(); auto it = columns.begin();
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name()); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column{*it++}); query_.prototype.append(column_definition{(*it++).name});
for (; it != columns.end(); ++it) { for (; it != columns.end(); ++it) {
result.append(", "); result.append(", ");
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name()); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column{*it}); query_.prototype.append(column_definition{(*it).name});
} }
} }
@ -187,9 +188,9 @@ query_builder &query_builder::remove()
return *this; 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 struct fk_context
@ -205,9 +206,9 @@ struct column_context
std::vector<fk_context> foreign_contexts; 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); transition_to(state_t::QUERY_TABLE_CREATE);
@ -256,12 +257,12 @@ query_builder &query_builder::table(const std::string &table)
return *this; 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); 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(); 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()); std::string result = d.prepare_identifier(col.name()) + " " + d.data_type_at(col.type());
if (col.attributes().size() > 0) { 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) column alias(const std::string &column, const std::string &as)
{ {
return {column, as}; return {"", column, as};
} }
column alias(column &&col, const std::string &as) column alias(column &&col, const std::string &as)
{ {
col.alias(as); col.as(as);
return std::move(col); 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/query_intermediates.hpp"
#include "matador/sql/session.hpp" #include "matador/sql/session.hpp"
#include "matador/sql/query_compiler.hpp"
namespace matador::sql { namespace matador::sql {
basic_query_intermediate::basic_query_intermediate(connection &db) 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 std::shared_ptr<schema> basic_query_intermediate::tables() const
{ {
return connection_.tables(); return connection_.schema();
} }
query_result<record> query_select_finish::fetch_all() 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() 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() 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() 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) query_intermediate::query_intermediate(connection &db, query_data &data)
: basic_query_intermediate(db), builder_(query) {} : basic_query_intermediate(db), data_(data) {}
query_offset_intermediate query_order_direction_intermediate::offset(size_t offset) 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) 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) 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) 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() 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() 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) 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) 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) 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) 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) 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) 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) 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) 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) 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_select_intermediate::query_select_intermediate(connection &db, const std::vector<column>& columns)
: query_start_intermediate(s) : 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) 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_insert_intermediate::query_insert_intermediate(connection &s)
: query_start_intermediate(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() 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() 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) 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_create_intermediate::query_create_intermediate(connection &db)
: query_start_intermediate(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_drop_intermediate::query_drop_intermediate(connection &s)
: query_start_intermediate(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) 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) 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) 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_update_intermediate::query_update_intermediate(connection &s, const std::string& table_name)
: query_start_intermediate(s) : 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) 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) 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_delete_intermediate::query_delete_intermediate(connection &s)
: query_start_intermediate(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) 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) query_start_intermediate::query_start_intermediate(connection &db)
: basic_query_intermediate(s) : basic_query_intermediate(db)
, builder_(s.dialect())
{} {}
} }

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 { namespace matador::sql {
record::record(std::initializer_list<column> columns) record::record(std::initializer_list<column_definition> columns)
: columns_(columns) : columns_(columns)
{ {
init(); init();
} }
record::record(const std::vector<column> &columns) record::record(const std::vector<column_definition> &columns)
: columns_(columns) : columns_(columns)
{ {
init(); init();
@ -41,7 +41,7 @@ record &record::operator=(const record &x)
return *this; return *this;
} }
const std::vector<column> &record::columns() const const std::vector<column_definition> &record::columns() const
{ {
return columns_; return columns_;
} }
@ -51,7 +51,7 @@ bool record::has_primary_key() const
return pk_index_ > -1; return pk_index_ > -1;
} }
const column &record::primary_key() const const column_definition &record::primary_key() const
{ {
if (!has_primary_key()) { if (!has_primary_key()) {
throw std::logic_error("record has no 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_]; 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; auto ref = columns_by_name_.at(name).first;
return 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); 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(); 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)); auto &ref = columns_.emplace_back(std::move(col));
add_to_map(ref, columns_.size()-1); 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}); 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)) { 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 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 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) 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(); 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"); 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 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 // adjust columns from given query
for (auto &col : q.prototype) { 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()) { 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); 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); auto columns = column_generator::generate<matador::test::product>(repo);
const std::vector<column> expected_columns = { const std::vector<column_definition> expected_columns = {
column{ "product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL }, column_definition{"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_definition{"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_definition{"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_definition{"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_definition{"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_definition{"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_definition{"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_definition{"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 } column_definition{"discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL }
}; };
REQUIRE(!columns.empty()); REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size()); 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); auto columns = column_generator::generate<matador::test::optional>(repo);
const std::vector<column> expected_columns = { const std::vector<column_definition> expected_columns = {
column{ "id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL }, column_definition{"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_definition{"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 } column_definition{"age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }
}; };
REQUIRE(!columns.empty()); REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size()); REQUIRE(columns.size() == expected_columns.size());

View File

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

View File

@ -1,6 +1,6 @@
#include <catch2/catch_test_macros.hpp> #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/condition.hpp>
#include <matador/sql/dialect_builder.hpp> #include <matador/sql/dialect_builder.hpp>
#include <matador/sql/query_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"); REQUIRE(q.table_name == "person");
q = query.insert().into("person", { q = query.insert().into("person", {
{"", "id", ""}, {"", "name", ""}, {"", "data", ""} { "id", "name", "data" }
}).values({7UL, "george", blob{1, 'A', 3, 4}}).compile(); }).values({7UL, "george", blob{1, 'A', 3, 4}}).compile();
REQUIRE(q.sql == R"(INSERT INTO "person" ("id", "name", "data") VALUES (7, 'george', X'01410304'))"); 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"); 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(); dialect d = dialect_builder::builder().create().build();
query_builder query(d); query_builder query(d);