From a3f467a5a88f3be37f014fcf6a543803a02cf173 Mon Sep 17 00:00:00 2001 From: Sascha Kuehl Date: Sun, 18 Feb 2024 18:12:00 +0100 Subject: [PATCH] query compiler progress --- backends/postgres/src/postgres_connection.cpp | 2 +- backends/sqlite/src/sqlite_connection.cpp | 2 +- backends/tests/QueryRecordTest.cpp | 125 ++++++------ backends/tests/QueryTest.cpp | 73 +++---- backends/tests/StatementTest.cpp | 14 +- backends/tests/TypeTraitsTest.cpp | 14 +- demo/main.cpp | 73 ++++++- include/matador/query/column.hpp | 25 +++ include/matador/query/query.hpp | 22 +++ include/matador/query/query_builder.hpp | 24 +++ include/matador/query/query_compiler.hpp | 37 ++++ include/matador/query/query_data.hpp | 24 +++ include/matador/query/query_intermediates.hpp | 132 +++++++++++++ include/matador/query/query_part_visitor.hpp | 19 ++ include/matador/query/query_parts.hpp | 55 ++++++ include/matador/query/sql_commands.hpp | 31 +++ include/matador/query/table.hpp | 16 ++ include/matador/sql/column.hpp | 179 +++-------------- include/matador/sql/column_definition.hpp | 164 ++++++++++++++++ include/matador/sql/column_generator.hpp | 14 +- include/matador/sql/column_name_generator.hpp | 16 +- include/matador/sql/condition.hpp | 47 +++-- include/matador/sql/connection.hpp | 28 +-- include/matador/sql/data_type_traits.hpp | 10 - include/matador/sql/dialect.hpp | 3 +- include/matador/sql/query.hpp | 48 +++++ include/matador/sql/query_builder.hpp | 9 +- include/matador/sql/query_compiler.hpp | 51 +++++ include/matador/sql/query_data.hpp | 24 +++ include/matador/sql/query_intermediates.hpp | 43 +++-- include/matador/sql/query_part_visitor.hpp | 46 +++++ include/matador/sql/query_parts.hpp | 181 ++++++++++++++++++ include/matador/sql/record.hpp | 22 +-- include/matador/sql/schema.hpp | 3 + include/matador/sql/session.hpp | 2 +- include/matador/sql/table.hpp | 17 ++ include/matador/utils/string.hpp | 2 +- src/CMakeLists.txt | 49 ++++- src/query/column.cpp | 21 ++ src/query/query.cpp | 6 + src/query/query_builder.cpp | 13 ++ src/query/query_compiler.cpp | 33 ++++ src/query/query_intermediates.cpp | 8 + src/query/query_parts.cpp | 30 +++ src/sql/column.cpp | 123 +----------- src/sql/column_definition.cpp | 100 ++++++++++ src/sql/column_generator.cpp | 2 +- src/sql/column_name_generator.cpp | 4 +- src/sql/condition.cpp | 10 +- src/sql/connection.cpp | 45 +---- src/sql/dialect.cpp | 10 +- src/sql/query.cpp | 45 +++++ src/sql/query_builder.cpp | 33 ++-- src/sql/query_compiler.cpp | 105 ++++++++++ src/sql/query_intermediates.cpp | 140 +++++++++----- src/sql/query_parts.cpp | 131 +++++++++++++ src/sql/record.cpp | 16 +- src/sql/schema.cpp | 10 +- src/sql/session.cpp | 4 +- test/ColumnGeneratorTest.cpp | 28 +-- test/ColumnTest.cpp | 6 +- test/QueryBuilderTest.cpp | 6 +- 62 files changed, 1934 insertions(+), 641 deletions(-) create mode 100644 include/matador/query/column.hpp create mode 100644 include/matador/query/query.hpp create mode 100644 include/matador/query/query_builder.hpp create mode 100644 include/matador/query/query_compiler.hpp create mode 100644 include/matador/query/query_data.hpp create mode 100644 include/matador/query/query_intermediates.hpp create mode 100644 include/matador/query/query_part_visitor.hpp create mode 100644 include/matador/query/query_parts.hpp create mode 100644 include/matador/query/sql_commands.hpp create mode 100644 include/matador/query/table.hpp create mode 100644 include/matador/sql/column_definition.hpp create mode 100644 include/matador/sql/query.hpp create mode 100644 include/matador/sql/query_compiler.hpp create mode 100644 include/matador/sql/query_data.hpp create mode 100644 include/matador/sql/query_part_visitor.hpp create mode 100644 include/matador/sql/query_parts.hpp create mode 100644 include/matador/sql/table.hpp create mode 100644 src/query/column.cpp create mode 100644 src/query/query.cpp create mode 100644 src/query/query_builder.cpp create mode 100644 src/query/query_compiler.cpp create mode 100644 src/query/query_intermediates.cpp create mode 100644 src/query/query_parts.cpp create mode 100644 src/sql/column_definition.cpp create mode 100644 src/sql/query.cpp create mode 100644 src/sql/query_compiler.cpp create mode 100644 src/sql/query_parts.cpp diff --git a/backends/postgres/src/postgres_connection.cpp b/backends/postgres/src/postgres_connection.cpp index b51b34f..18db9e9 100644 --- a/backends/postgres/src/postgres_connection.cpp +++ b/backends/postgres/src/postgres_connection.cpp @@ -58,7 +58,7 @@ std::unique_ptr postgres_connection::fetch(const std::st auto type = PQftype(res, i); auto size = PQfmod(res, i); // std::cout << "column " << col_name << ", type " << type << " (size: " << size << ")\n"; - prototype.append({col_name}); + prototype.append(sql::column_definition{col_name}); } return std::move(std::make_unique(std::make_unique(res), std::move(prototype))); } diff --git a/backends/sqlite/src/sqlite_connection.cpp b/backends/sqlite/src/sqlite_connection.cpp index 9ab0612..e66a994 100644 --- a/backends/sqlite/src/sqlite_connection.cpp +++ b/backends/sqlite/src/sqlite_connection.cpp @@ -65,7 +65,7 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values if (context->prototype.empty()) { for(int i = 0; i < column_count; ++i) { - context->prototype.append(sql::column{columns[i]}); + context->prototype.append(sql::column_definition{columns[i]}); } } diff --git a/backends/tests/QueryRecordTest.cpp b/backends/tests/QueryRecordTest.cpp index e5ca4bf..45b26e7 100644 --- a/backends/tests/QueryRecordTest.cpp +++ b/backends/tests/QueryRecordTest.cpp @@ -3,6 +3,7 @@ #include "matador/sql/column.hpp" #include "matador/sql/condition.hpp" #include "matador/sql/connection.hpp" +#include "matador/sql/query_builder.hpp" #include "connection.hpp" @@ -29,7 +30,7 @@ protected: private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.drop().table(table_name).execute(); + db.query().drop().table(table_name).execute(); } } }; @@ -39,7 +40,7 @@ using namespace matador::sql; TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[session][record]") { REQUIRE(!db.exists("person")); - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -49,7 +50,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi REQUIRE(db.exists("person")); - db.drop() + db.query().drop() .table("person") .execute(); @@ -58,7 +59,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with foreign key", "[session][record]") { - db.create() + db.query().create() .table("airplane", { make_pk_column("id"), make_column("brand", 255), @@ -68,7 +69,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore REQUIRE(db.exists("airplane")); - db.create() + db.query().create() .table("flight", { make_pk_column("id"), make_fk_column("airplane_id", "airplane", "id"), @@ -78,13 +79,13 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore REQUIRE(db.exists("flight")); - db.drop() + db.query().drop() .table("flight") .execute(); REQUIRE(!db.exists("flight")); - db.drop() + db.query().drop() .table("airplane") .execute(); @@ -93,7 +94,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -101,14 +102,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi }) .execute(); - auto res = db.insert() + auto res = db.query().insert() .into("person", {"id", "name", "age"}) .values({7, "george", 45}) .execute(); REQUIRE(res == 1); - auto result = db.select({"id", "name", "age"}) + auto result = db.query().select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -125,14 +126,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi REQUIRE(i.at(2).template as() == 45); } - db.drop() + db.query().drop() .table("person") .execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with foreign key", "[session][record]") { - db.create() + db.query().create() .table("airplane", { make_pk_column("id"), make_column("brand", 255), @@ -140,7 +141,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore }) .execute(); - db.create() + db.query().create() .table("flight", { make_pk_column("id"), make_fk_column("airplane_id", "airplane", "id"), @@ -148,23 +149,23 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore }) .execute(); - auto res = db.insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute(); + auto res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute(); REQUIRE(res == 1); - res = db.insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute(); + res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute(); REQUIRE(res == 1); - res = db.insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute(); + res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute(); REQUIRE(res == 1); - auto count = db.select({count_all()}).from("airplane").fetch_value(); + auto count = db.query().select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); - res = db.insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute(); + res = db.query().insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute(); REQUIRE(res == 1); - db.drop().table("flight").execute(); - db.drop().table("airplane").execute(); + db.query().drop().table("flight").execute(); + db.query().drop().table("airplane").execute(); REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("airplane")); @@ -172,7 +173,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -180,14 +181,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi }) .execute(); - auto res = db.insert() + auto res = db.query().insert() .into("person", {"id", "name", "age"}) .values({7, "george", 45}) .execute(); REQUIRE(res == 1); - res = db.update("person") + res = db.query().update("person") .set({{"id", 7}, {"name", "jane"}, {"age", 35}}) @@ -196,7 +197,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi REQUIRE(res == 1); - auto result = db.select({"id", "name", "age"}) + auto result = db.query().select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -213,12 +214,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi REQUIRE(i.at(2).as() == 35); } - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -226,16 +227,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec }) .execute(); - auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - auto result = db.select({"id", "name", "age"}) + auto result = db.query().select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -246,22 +247,22 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec } REQUIRE(expected_names.empty()); - auto rec = db.select({"id", "name", "age"}) + auto rec = db.query().select({"id", "name", "age"}) .from("person") .fetch_one(); REQUIRE(rec.at(1).str() == "george"); - auto name = db.select({"name"}) + auto name = db.query().select({"name"}) .from("person") .fetch_value(); REQUIRE(name == "george"); - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -269,16 +270,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", }) .execute(); - auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - auto result = db.select({"id", "name", "age"}) + auto result = db.query().select({"id", "name", "age"}) .from("person") .order_by("name").asc() .fetch_all(); @@ -290,12 +291,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", } REQUIRE(expected_names.empty()); - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by and order by", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -303,18 +304,18 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an }) .execute(); - auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute(); REQUIRE(res == 1); - auto result = db.select({alias(count("age"), "age_count"), "age"}) + auto result = db.query().select({alias(count("age"), "age_count"), "age"}) .from("person") .group_by("age") .order_by("age_count").desc() @@ -329,41 +330,41 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an expected_values.pop_front(); } - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute delete statement", "[session][record]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), make_column("age") }).execute(); - auto res = db.insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); + res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); REQUIRE(res == 1); - auto count = db.select({count_all()}).from("person").fetch_value(); + auto count = db.query().select({count_all()}).from("person").fetch_value(); REQUIRE(count == 2); - res = db.remove() + res = db.query().remove() .from("person") .where("id"_col == 1) .execute(); REQUIRE(res == 1); - count = db.select({count_all()}).from("person").fetch_value(); + count = db.query().select({count_all()}).from("person").fetch_value(); REQUIRE(count == 1); - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][record]") { - db.create() + db.query().create() .table("quotes", { make_column("from", 255), make_column("to", 255) @@ -379,19 +380,19 @@ TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][recor REQUIRE(field.type() == types[field.index()]); } - db.insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute(); + db.query().insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute(); - auto res = db.select({"from", "to"}).from("quotes").fetch_one(); + auto res = db.query().select({"from", "to"}).from("quotes").fetch_one(); REQUIRE("Berlin" == res.at("from").str()); REQUIRE("London" == res.at("to").str()); - db.update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute(); + db.query().update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute(); - res = db.select({"from", "to"}).from("quotes").fetch_one(); + res = db.query().select({"from", "to"}).from("quotes").fetch_one(); REQUIRE("Hamburg" == res.at("from").str()); REQUIRE("New York" == res.at("to").str()); - db.drop().table("quotes").execute(); + db.query().drop().table("quotes").execute(); } \ No newline at end of file diff --git a/backends/tests/QueryTest.cpp b/backends/tests/QueryTest.cpp index d097cb3..b4fdf5d 100644 --- a/backends/tests/QueryTest.cpp +++ b/backends/tests/QueryTest.cpp @@ -1,7 +1,8 @@ #include "catch2/catch_test_macros.hpp" -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/sql/condition.hpp" +#include "matador/sql/query_builder.hpp" #include "matador/sql/session.hpp" #include "connection.hpp" @@ -36,27 +37,27 @@ private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.drop().table(table_name).execute(); + db.query().drop().table(table_name).execute(); } } }; TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[session]") { - db.create() + db.query().create() .table("airplane") .execute(); REQUIRE(db.exists("airplane")); - db.create() + db.query().create() .table("flight") .execute(); REQUIRE(db.exists("flight")); - db.drop().table("flight").execute(); - db.drop().table("airplane").execute(); + db.query().drop().table("flight").execute(); + db.query().drop().table("airplane").execute(); REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("airplane")); @@ -64,20 +65,20 @@ TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[sess TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[session]") { - db.create() + db.query().create() .table("person") .execute(); person george{7, "george", 45}; george.image.push_back(37); - auto res = db.insert() + auto res = db.query().insert() .into("person", george) .execute(); REQUIRE(res == 1); // fetch person as record - auto result_record = db.select() + auto result_record = db.query().select() .from("person") .where("id"_col == 7) .fetch_all(); @@ -96,7 +97,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[ } // fetch person as person - auto result_person = db.select() + auto result_person = db.query().select() .from("person") .where("id"_col == 7) .fetch_all(); @@ -107,12 +108,12 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[ REQUIRE(i.age == 45); } - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") { - db.create() + db.query().create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -120,7 +121,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") }) .execute(); - auto res = db.insert() + auto res = db.query().insert() .into("person", {{"", "id", ""}, {"", "name", ""}, {"", "color", ""}}) .values({7, "george", "green"}) .execute(); @@ -128,7 +129,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") REQUIRE(res == 1); // fetch person as record - auto result_record = db.select({"id", "name", "color"}) + auto result_record = db.query().select({"id", "name", "color"}) .from("person") .where("id"_col == 7) .fetch_all(); @@ -146,16 +147,16 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") REQUIRE(i.at(2).as() == "green"); } - db.drop().table("person").execute(); + db.query().drop().table("person").execute(); } TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]") { - db.create() + db.query().create() .table("airplane") .execute(); - db.create() + db.query().create() .table("flight") .execute(); @@ -166,35 +167,35 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]" }; for (const auto &plane: planes) { - auto res = db.insert().into("airplane").values(*plane).execute(); + auto res = db.query().insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto count = db.select({count_all()}).from("airplane").fetch_value(); + auto count = db.query().select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); flight f4711{4, planes.at(1), "hans"}; - auto res = db.insert().into("flight").values(f4711).execute(); + auto res = db.query().insert().into("flight").values(f4711).execute(); REQUIRE(res == 1); - auto f = *db.select().from("flight").fetch_all().begin(); + auto f = *db.query().select().from("flight").fetch_all().begin(); REQUIRE(f.id == 4); REQUIRE(f.pilot_name == "hans"); REQUIRE(f.airplane.get() != nullptr); REQUIRE(f.airplane->id == 2); - db.drop().table("flight").execute(); - db.drop().table("airplane").execute(); + db.query().drop().table("flight").execute(); + db.query().drop().table("airplane").execute(); } -TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[session][join]") +TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left", "[session][join_left]") { - db.create() + db.query().create() .table("airplane") .execute(); - db.create() + db.query().create() .table("flight") .execute(); @@ -205,11 +206,11 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[ }; for (const auto &plane: planes) { - auto res = db.insert().into("airplane").values(*plane).execute(); + auto res = db.query().insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto count = db.select({count_all()}).from("airplane").fetch_value(); + auto count = db.query().select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); std::vector> flights{ @@ -220,20 +221,20 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[ }; for (const auto &f: flights) { - auto res = db.insert().into("flight").values(*f).execute(); + auto res = db.query().insert().into("flight").values(*f).execute(); REQUIRE(res == 1); } - auto f = *db.select().from("flight").fetch_all().begin(); + auto f = *db.query().select().from("flight").fetch_all().begin(); REQUIRE(f.id == 4); REQUIRE(f.pilot_name == "hans"); REQUIRE(f.airplane.get() != nullptr); REQUIRE(f.airplane->id == 1); - auto result = db.select({"f.id", "ap.brand", "ap.model", "f.pilot_name"}) - .from("flight", "f") - .join("airplane", "ap") - .on("f.airplane_id", "ap.id") + auto result = db.query().select({"f.id", "ap.brand", "ap.model", "f.pilot_name"}) + .from("flight", "f") + .join_left("airplane", "ap") + .on("f.airplane_id"_col == "ap.id"_col) .order_by("f.id").asc() .fetch_all(); @@ -250,7 +251,7 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join", "[ REQUIRE(r.at(3).as() == expected_result[index++].second); } - db.drop().table("flight").execute(); - db.drop().table("airplane").execute(); + db.query().drop().table("flight").execute(); + db.query().drop().table("airplane").execute(); } \ No newline at end of file diff --git a/backends/tests/StatementTest.cpp b/backends/tests/StatementTest.cpp index 53f5882..9f61c28 100644 --- a/backends/tests/StatementTest.cpp +++ b/backends/tests/StatementTest.cpp @@ -1,6 +1,6 @@ #include -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/sql/condition.hpp" #include "matador/sql/connection.hpp" @@ -18,7 +18,7 @@ public: : db(matador::test::connection::dns) { db.open(); - db.create().table("airplane").execute(); + db.query().create().table("airplane").execute(); } ~StatementTestFixture() @@ -38,7 +38,7 @@ protected: private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.drop().table(table_name).execute(); + db.query().drop().table(table_name).execute(); } } @@ -47,7 +47,7 @@ private: TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement]") { SECTION("Insert with prepared statement and placeholder") { - auto stmt = db.insert() + auto stmt = db.query().insert() .into("airplane") .values().prepare(); @@ -57,7 +57,7 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement stmt.reset(); } - auto result = db.select().from("airplane").fetch_all(); + auto result = db.query().select().from("airplane").fetch_all(); size_t index{0}; for (const auto &i: result) { @@ -69,11 +69,11 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement SECTION("Select with prepared statement") { for (const auto &plane: planes) { - auto res = db.insert().into("airplane").values(*plane).execute(); + auto res = db.query().insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto stmt = db.select().from("airplane").where("brand"_col == _).prepare(); + auto stmt = db.query().select().from("airplane").where("brand"_col == _).prepare(); stmt.bind(0, "Airbus"); diff --git a/backends/tests/TypeTraitsTest.cpp b/backends/tests/TypeTraitsTest.cpp index 7b34c36..1289a01 100644 --- a/backends/tests/TypeTraitsTest.cpp +++ b/backends/tests/TypeTraitsTest.cpp @@ -17,14 +17,14 @@ public: : db(matador::test::connection::dns) { db.open(); - db.create() + db.query().create() .table("location") .execute(); } ~TypeTraitsTestFixture() { - db.drop().table("location").execute(); + db.query().drop().table("location").execute(); } protected: @@ -33,7 +33,7 @@ protected: private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.drop().table(table_name).execute(); + db.query().drop().table(table_name).execute(); } } }; @@ -85,10 +85,10 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ SECTION("Insert and select with direct execution") { location loc{1, "center", {1, 2, 3}, Color::Black}; - auto res = db.insert().into("location").values(loc).execute(); + auto res = db.query().insert().into("location").values(loc).execute(); REQUIRE(res == 1); - auto result = db.select().from("location").fetch_all(); + auto result = db.query().select().from("location").fetch_all(); for (const auto &l: result) { REQUIRE(l.name == "center"); @@ -98,11 +98,11 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ SECTION("Insert and select with prepared statement") { location loc{1, "center", {1, 2, 3}, Color::Black}; - auto stmt = db.insert().into("location").values().prepare(); + auto stmt = db.query().insert().into("location").values().prepare(); auto res = stmt.bind(loc).execute(); REQUIRE(res == 1); - auto result = db.select().from("location"). + auto result = db.query().select().from("location"). template fetch_all(); for (const auto &l: result) { diff --git a/demo/main.cpp b/demo/main.cpp index c7c4e36..affdc22 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -1,9 +1,74 @@ -#include -#include +#include "matador/sql/column.hpp" +#include "matador/sql/condition.hpp" +#include "matador/sql/schema.hpp" +#include "matador/sql/connection.hpp" +#include "matador/sql/entity.hpp" + +#include "matador/utils/access.hpp" + #include -int main() { - const std::string env_var {"MATADOR_BACKENDS_PATH"}; +struct author +{ + unsigned long id{}; + std::string first_name; + std::string last_name; + std::string date_of_birth; + unsigned short year_of_birth{}; + bool distinguished{false}; + + template < typename Operator > + void process(Operator &op) { + namespace field = matador::utils::access; + field::primary_key(op, "id", id); + field::attribute(op, "first_name", first_name, 63); + field::attribute(op, "last_name", last_name, 63); + field::attribute(op, "date_of_birth", date_of_birth, 31); + field::attribute(op, "year_of_birth", year_of_birth); + field::attribute(op, "distinguished", distinguished); + } +}; + +struct book +{ + unsigned long id{}; + matador::sql::entity book_author; + std::string title; + unsigned short published_in{}; + + template < typename Operator > + void process(Operator &op) { + namespace field = matador::utils::access; + field::primary_key(op, "id", id); + field::attribute(op, "title", title, 511); + field::attribute(op, "published_in", published_in); + } +}; + +int main() +{ + using namespace matador::sql; + const std::string env_var{"MATADOR_BACKENDS_PATH"}; + + std::string dns; + auto s = std::make_shared(); + connection c(dns, s); + + auto books = c.query() + .select({"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(); + + // SELECT book.title, book.id, book.author_id, book.published_in, author.name + // FROM book + // INNER JOIN author ON book.author_id = author.id + // WHERE book.published_in < 2008 AND author.name = "Michael Crichton" + // ORDER BY "book.title" ASC + // char var[1024]; // size_t len{}; diff --git a/include/matador/query/column.hpp b/include/matador/query/column.hpp new file mode 100644 index 0000000..88c0a55 --- /dev/null +++ b/include/matador/query/column.hpp @@ -0,0 +1,25 @@ +#ifndef QUERY_COLUMN_HPP +#define QUERY_COLUMN_HPP + +#include + +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 diff --git a/include/matador/query/query.hpp b/include/matador/query/query.hpp new file mode 100644 index 0000000..d1e337d --- /dev/null +++ b/include/matador/query/query.hpp @@ -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 &columns); + query& from(const std::string &table, const std::string &as = ""); + +private: + connection &connection_; +}; + +} +#endif //QUERY_QUERY_HPP diff --git a/include/matador/query/query_builder.hpp b/include/matador/query/query_builder.hpp new file mode 100644 index 0000000..4164bf5 --- /dev/null +++ b/include/matador/query/query_builder.hpp @@ -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 + +namespace matador::query { + +class query_builder +{ +public: + explicit query_builder(const std::shared_ptr &scm); + query_select_intermediate select(std::initializer_list columns); + +private: + std::shared_ptr schema_; +}; + +} +#endif //QUERY_QUERY_BUILDER_HPP diff --git a/include/matador/query/query_compiler.hpp b/include/matador/query/query_compiler.hpp new file mode 100644 index 0000000..1c11fe2 --- /dev/null +++ b/include/matador/query/query_compiler.hpp @@ -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 +#include + +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 diff --git a/include/matador/query/query_data.hpp b/include/matador/query/query_data.hpp new file mode 100644 index 0000000..32de085 --- /dev/null +++ b/include/matador/query/query_data.hpp @@ -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 +#include + +namespace matador::query { + +struct query_data +{ + SqlCommands command; + std::vector> parts; + std::vector columns; + std::unordered_map table_map_by_index; + using table_data_ref = std::reference_wrapper; + std::unordered_map table_map_by_name; +}; + +} +#endif //QUERY_QUERY_DATA_HPP diff --git a/include/matador/query/query_intermediates.hpp b/include/matador/query/query_intermediates.hpp new file mode 100644 index 0000000..4980b20 --- /dev/null +++ b/include/matador/query/query_intermediates.hpp @@ -0,0 +1,132 @@ +#ifndef QUERY_QUERY_INTERMEDIATES_HPP +#define QUERY_QUERY_INTERMEDIATES_HPP + +#include "matador/sql/schema.hpp" + +#include +#include + +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 &scm); + +protected: + sql::schema& schema() const; + +private: + std::shared_ptr 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 diff --git a/include/matador/query/query_part_visitor.hpp b/include/matador/query/query_part_visitor.hpp new file mode 100644 index 0000000..f0086ea --- /dev/null +++ b/include/matador/query/query_part_visitor.hpp @@ -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 diff --git a/include/matador/query/query_parts.hpp b/include/matador/query/query_parts.hpp new file mode 100644 index 0000000..2593394 --- /dev/null +++ b/include/matador/query/query_parts.hpp @@ -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 columns); + void accept(query_part_visitor &visitor) override; + +private: + std::vector 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 diff --git a/include/matador/query/sql_commands.hpp b/include/matador/query/sql_commands.hpp new file mode 100644 index 0000000..f7a06e5 --- /dev/null +++ b/include/matador/query/sql_commands.hpp @@ -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 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 diff --git a/include/matador/query/table.hpp b/include/matador/query/table.hpp new file mode 100644 index 0000000..24dd9e0 --- /dev/null +++ b/include/matador/query/table.hpp @@ -0,0 +1,16 @@ +#ifndef QUERY_TABLE_HPP +#define QUERY_TABLE_HPP + +#include +#include + +namespace matador::query { + +struct table_data +{ + std::type_index index; + std::string name; +}; + +} +#endif //QUERY_TABLE_HPP diff --git a/include/matador/sql/column.hpp b/include/matador/sql/column.hpp index 9b8a4e1..9eeb273 100644 --- a/include/matador/sql/column.hpp +++ b/include/matador/sql/column.hpp @@ -1,174 +1,45 @@ #ifndef QUERY_COLUMN_HPP #define QUERY_COLUMN_HPP -#include "matador/sql/any_type.hpp" -#include "matador/sql/any_type_to_visitor.hpp" -#include "matador/sql/data_type_traits.hpp" - -#include "matador/utils/field_attributes.hpp" - -#include -#include +#include namespace matador::sql { -enum class null_option : uint8_t { - NULLABLE, NOT_NULL +enum class sql_function_t { + NONE, + COUNT, + AVG, + SUM, + MIN, + MAX }; -class column { -public: - column(sql_function_t func, std::string name); - column(const char *name, std::string alias = ""); // NOLINT(*-explicit-constructor) - column(std::string name, std::string alias = ""); // NOLINT(*-explicit-constructor) +struct column +{ + column(const char *name) : name(name) {} // NOLINT(*-explicit-constructor) + column(std::string name) : name(std::move(name)) {} // NOLINT(*-explicit-constructor) + column(sql_function_t func, std::string name) : name(std::move(name)), function_(func) {} // NOLINT(*-explicit-constructor) + column(std::string table_name, std::string name, std::string as) + : table(std::move(table_name)) + , name(std::move(name)) + , alias(std::move(as)) {} // NOLINT(*-explicit-constructor) - column(const column&) = default; - column& operator=(const column&) = default; - column(column&&) noexcept = default; - column& operator=(column&&) noexcept = default; - - template - explicit column(std::string name, utils::field_attributes attr) - : column(std::move(name), data_type_traits::builtin_type(attr.size()), attr) - {} - - template - column(std::string name, const Type &, utils::field_attributes attr, null_option null_opt) - : column(std::move(name), data_type_traits::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 - 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::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(value_); + column& as(std::string a) { + alias = std::move(a); + return *this; } - [[nodiscard]] std::string str() const; - - template - void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes) - { - type_ = data_type_traits::builtin_type(attr.size()); - attributes_ = attr; - value_ = value; + [[nodiscard]] bool is_function() const { + return function_ != sql_function_t::NONE; } - void set(const std::string &value, const utils::field_attributes &attr) - { - type_ = data_type_traits::builtin_type(attr.size()); - attributes_ = attr; - value_ = value; - } - - void set(const char *value, const utils::field_attributes &attr) - { - type_ = data_type_traits::builtin_type(attr.size()); - attributes_ = attr; - value_ = value; - } - - template - Type as() const - { - const Type* ptr= std::get_if(&value_); - if (ptr) { - return *ptr; - } - any_type_to_visitor visitor; - std::visit(visitor, const_cast(value_)); - return visitor.result; - } - - [[nodiscard]] bool is_function() const; - [[nodiscard]] sql_function_t function() const; - -private: - template - void process(Operator &op) - { - op.on_attribute(name_.c_str(), value_, type_, attributes_); - } - - using data_type_index = std::vector; - -private: - friend class record; - - static const data_type_index data_type_index_; - - std::string name_; - size_t index_{}; - utils::field_attributes attributes_; - null_option null_option_{null_option::NOT_NULL}; - data_type_t type_{data_type_t::type_unknown}; - any_type value_; + std::string table; + std::string name; + std::string alias; sql_function_t function_{sql_function_t::NONE}; - std::string alias_; - std::string ref_table_; - std::string ref_column_; }; -/** - * User defined literal to have a shortcut creating a column object - * @param name Name of the column - * @param len Length of the column name - * @return A column object with given name - */ column operator "" _col(const char *name, size_t len); -column make_column(const std::string &name, data_type_t type, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL); - -template < typename Type > -column make_column(const std::string &name, utils::field_attributes attr = utils::null_attributes, null_option null_opt = null_option::NOT_NULL) -{ - return make_column(name, data_type_traits::builtin_type(0), attr, null_opt); -} -template <> -column make_column(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(name, { size, utils::constraints::PRIMARY_KEY }); -} - -template <> -column make_pk_column(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::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::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL}; -} - -template <> -column make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column); - } #endif //QUERY_COLUMN_HPP diff --git a/include/matador/sql/column_definition.hpp b/include/matador/sql/column_definition.hpp new file mode 100644 index 0000000..3076ff9 --- /dev/null +++ b/include/matador/sql/column_definition.hpp @@ -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 +#include + +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 + explicit column_definition(std::string name, utils::field_attributes attr) + : column_definition(std::move(name), data_type_traits::builtin_type(attr.size()), attr) + {} + + template + column_definition(std::string name, const Type &, utils::field_attributes attr, null_option null_opt) + : column_definition(std::move(name), data_type_traits::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 + 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::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(value_); + } + + [[nodiscard]] std::string str() const; + + template + void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes) + { + type_ = data_type_traits::builtin_type(attr.size()); + attributes_ = attr; + value_ = value; + } + + void set(const std::string &value, const utils::field_attributes &attr) + { + type_ = data_type_traits::builtin_type(attr.size()); + attributes_ = attr; + value_ = value; + } + + void set(const char *value, const utils::field_attributes &attr) + { + type_ = data_type_traits::builtin_type(attr.size()); + attributes_ = attr; + value_ = value; + } + + template + Type as() const + { + const Type* ptr= std::get_if(&value_); + if (ptr) { + return *ptr; + } + any_type_to_visitor visitor; + std::visit(visitor, const_cast(value_)); + return visitor.result; + } + +private: + template + void process(Operator &op) + { + op.on_attribute(name_.c_str(), value_, type_, attributes_); + } + + using data_type_index = std::vector; + +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::builtin_type(0), attr, null_opt); +} +template <> +column_definition make_column(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(name, { size, utils::constraints::PRIMARY_KEY }); +} + +template <> +column_definition make_pk_column(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::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::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL}; +} + +template <> +column_definition make_fk_column(const std::string &name, size_t size, const std::string &ref_table, const std::string &ref_column); + +} +#endif //QUERY_COLUMN_DEFINITION_HPP diff --git a/include/matador/sql/column_generator.hpp b/include/matador/sql/column_generator.hpp index 7d4d499..d18797d 100644 --- a/include/matador/sql/column_generator.hpp +++ b/include/matador/sql/column_generator.hpp @@ -1,7 +1,7 @@ #ifndef QUERY_COLUMN_GENERATOR_HPP #define QUERY_COLUMN_GENERATOR_HPP -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/sql/data_type_traits.hpp" #include "matador/utils/access.hpp" @@ -21,10 +21,10 @@ public: fk_column_generator() = default; template - column generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column) + column_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column) { utils::access::process(*this, x); - return column{id, type_, 0, ref_table, ref_column, { utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL}; + return column_definition{id, type_, 0, ref_table, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL}; } template @@ -53,15 +53,15 @@ private: class column_generator { private: - column_generator(std::vector &columns, const schema &repo); + column_generator(std::vector &columns, const schema &repo); public: ~column_generator() = default; template < class Type > - static std::vector generate(const schema &repo) + static std::vector generate(const schema &repo) { - std::vector columns; + std::vector columns; column_generator gen(columns, repo); Type obj; matador::utils::access::process(gen, obj); @@ -101,7 +101,7 @@ private: private: size_t index_ = 0; - std::vector &columns_; + std::vector &columns_; const schema &repo_; fk_column_generator fk_column_generator_; diff --git a/include/matador/sql/column_name_generator.hpp b/include/matador/sql/column_name_generator.hpp index c271463..8f39877 100644 --- a/include/matador/sql/column_name_generator.hpp +++ b/include/matador/sql/column_name_generator.hpp @@ -5,6 +5,7 @@ #include "matador/utils/field_attributes.hpp" #include "matador/utils/foreign_attributes.hpp" +#include "matador/sql/column.hpp" #include "matador/sql/schema.hpp" #include @@ -13,29 +14,22 @@ namespace matador::sql { -struct column_info -{ - std::string table; - std::string name; - std::string alias; -}; - class column_name_generator { private: - column_name_generator(std::vector &column_infos, const sql::schema &ts, const std::string &table_name); + column_name_generator(std::vector &column_infos, const sql::schema &ts, const std::string &table_name); public: ~column_name_generator() = default; template < class Type > - static std::vector generate(const sql::schema &ts) + static std::vector generate(const sql::schema &ts) { const auto info = ts.info(); if (!info) { return {}; } - std::vector columns; + std::vector columns; column_name_generator gen(columns, ts, info.value().name); Type obj; matador::utils::access::process(gen, obj); @@ -93,7 +87,7 @@ private: private: std::stack table_name_stack_; - std::vector &column_infos_; + std::vector &column_infos_; const sql::schema &table_schema_; int column_index{0}; }; diff --git a/include/matador/sql/condition.hpp b/include/matador/sql/condition.hpp index 6b59759..a6f7609 100644 --- a/include/matador/sql/condition.hpp +++ b/include/matador/sql/condition.hpp @@ -7,6 +7,7 @@ #include "matador/sql/query_context.hpp" #include +#include namespace matador::sql { @@ -55,8 +56,8 @@ public: std::string evaluate(dialect &d, query_context &query) const override { - query.bind_vars.emplace_back(field_.name()); - return d.prepare_identifier(field_.name()) + " " + operand + " " + std::to_string(value); + query.bind_vars.emplace_back(field_.name); + return d.prepare_identifier(field_.name) + " " + operand + " " + std::to_string(value); } }; @@ -75,8 +76,8 @@ public: std::string evaluate(dialect &d, query_context &query) const override { - query.bind_vars.emplace_back(field_.name()); - return d.prepare_identifier(field_.name()) + " " + operand + " '" + value + "'"; + query.bind_vars.emplace_back(field_.name); + return d.prepare_identifier(field_.name) + " " + operand + " '" + value + "'"; } }; @@ -96,7 +97,7 @@ public: std::string evaluate(dialect &d, query_context &query) const override { - return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_.name()); + return std::to_string(value) + " " + operand + " " + d.prepare_identifier(field_.name); } }; @@ -115,7 +116,7 @@ public: std::string evaluate(dialect &d, query_context &query) const override { - return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_.name()); + return "'" + std::to_string(value) + "' " + operand + " " + d.prepare_identifier(field_.name); } }; @@ -158,10 +159,10 @@ public: std::string evaluate(dialect &d, query_context &query) const override { auto count = size(); for (size_t i = 0; i < count; ++i) { - query.bind_vars.emplace_back(field_.name()); + query.bind_vars.emplace_back(field_.name); } - std::string result = d.prepare_identifier(field_.name()) + " IN ("; + std::string result = d.prepare_identifier(field_.name) + " IN ("; if (args_.size() < 2) { for (const auto &val : args_) { result.append(std::to_string(val)); @@ -261,9 +262,9 @@ public: * @return A condition BETWEEN part of the query */ std::string evaluate(dialect &d, query_context &query) const override { - query.bind_vars.emplace_back(field_.name()); - query.bind_vars.emplace_back(field_.name()); - return d.prepare_identifier(field_.name()) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second); + query.bind_vars.emplace_back(field_.name); + query.bind_vars.emplace_back(field_.name); + return d.prepare_identifier(field_.name) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second); } private: @@ -355,6 +356,28 @@ private: std::string operand; }; +template<> +class condition : public basic_column_condition +{ +public: + condition(const column &a, basic_condition::operand_t op, column b) + : basic_column_condition(a, op) + , other_column_(std::move(b)) {} + /** + * @brief Evaluates the condition + * + * @param d The d used to evaluate + * @return The evaluated string based on the compile type + */ + std::string evaluate(dialect &d, query_context &query) const override + { + return d.prepare_identifier(field_.name) + " " + operand + " " + d.prepare_identifier(other_column_.name); + } + +private: + column other_column_; +}; + /** * @file condition.hpp * @brief Contains functions to create query conditions @@ -441,6 +464,8 @@ condition operator==(const column &col, T val) return condition(col, basic_condition::operand_t::EQUAL, val); } +condition operator==(const column &a, const column &b); + /** * @brief Condition equality method for a column and a query * diff --git a/include/matador/sql/connection.hpp b/include/matador/sql/connection.hpp index 60c96a3..9789eed 100644 --- a/include/matador/sql/connection.hpp +++ b/include/matador/sql/connection.hpp @@ -4,11 +4,12 @@ #include "matador/sql/connection_info.hpp" #include "matador/sql/connection_impl.hpp" #include "matador/sql/dialect.hpp" -#include "matador/sql/query_intermediates.hpp" +#include "matador/sql/query.hpp" #include "matador/sql/query_context.hpp" #include "matador/sql/query_result.hpp" #include "matador/sql/record.hpp" #include "matador/sql/statement.hpp" +#include "matador/sql/schema.hpp" #include "matador/utils/logger.hpp" @@ -19,8 +20,8 @@ namespace matador::sql { class connection { public: - explicit connection(connection_info info, const std::shared_ptr &repo = std::make_shared()); - explicit connection(const std::string& dns, const std::shared_ptr &repo = std::make_shared()); + explicit connection(connection_info info, const std::shared_ptr &repo = std::make_shared()); + explicit connection(const std::string& dns, const std::shared_ptr &repo = std::make_shared()); connection(const connection &x); connection& operator=(const connection &x); connection(connection &&x) noexcept = default; @@ -31,19 +32,12 @@ public: [[nodiscard]] bool is_open() const; [[nodiscard]] const connection_info& info() const; - query_create_intermediate create(); - query_drop_intermediate drop(); - template < class Type > - query_select_intermediate select(); - query_select_intermediate select(std::initializer_list columns); - query_insert_intermediate insert(); - query_update_intermediate update(const std::string &table); - query_delete_intermediate remove(); - [[nodiscard]] record describe(const std::string &table_name) const; [[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const; [[nodiscard]] bool exists(const std::string &table_name) const; + sql::query query() const; + query_result fetch(const query_context &q) const; [[nodiscard]] std::unique_ptr fetch(const std::string &sql) const; [[nodiscard]] size_t execute(const std::string &sql) const; @@ -51,21 +45,15 @@ public: statement prepare(query_context &&query) const; const class dialect& dialect() const; - std::shared_ptr tables() const; + std::shared_ptr schema() const; private: connection_info connection_info_; std::unique_ptr connection_; utils::logger logger_; const class dialect &dialect_; - std::shared_ptr schema_; + std::shared_ptr schema_; }; -template -query_select_intermediate connection::select() -{ - return query_select_intermediate{*this, column_generator::generate(*schema_)}; -} - } #endif //QUERY_CONNECTION_HPP diff --git a/include/matador/sql/data_type_traits.hpp b/include/matador/sql/data_type_traits.hpp index d18ef19..0c9f432 100644 --- a/include/matador/sql/data_type_traits.hpp +++ b/include/matador/sql/data_type_traits.hpp @@ -41,16 +41,6 @@ enum class data_type_t : uint8_t { type_unknown /*!< Data type unknown */ }; -enum class sql_function_t { - NONE, - COUNT, - AVG, - SUM, - MIN, - MAX -}; - - /** * @tparam T The type of the traits * @brief Type traits for database types diff --git a/include/matador/sql/dialect.hpp b/include/matador/sql/dialect.hpp index 57a528c..34d92bf 100644 --- a/include/matador/sql/dialect.hpp +++ b/include/matador/sql/dialect.hpp @@ -1,6 +1,7 @@ #ifndef QUERY_DIALECT_HPP #define QUERY_DIALECT_HPP +#include "matador/sql/column.hpp" #include "matador/sql/data_type_traits.hpp" #include @@ -11,8 +12,6 @@ namespace matador::sql { -class column; - class dialect final { public: diff --git a/include/matador/sql/query.hpp b/include/matador/sql/query.hpp new file mode 100644 index 0000000..04979b7 --- /dev/null +++ b/include/matador/sql/query.hpp @@ -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 columns); + query_select_intermediate select(std::initializer_list 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 +query_select_intermediate query::select() +{ + return query_select_intermediate{connection_, column_name_generator::generate(this->schema())}; +} + +template +query_select_intermediate query::select(std::initializer_list columns) +{ + return query_select_intermediate{connection_, column_name_generator::generate(this->schema())}; +} + +} +#endif //QUERY_QUERY_HPP diff --git a/include/matador/sql/query_builder.hpp b/include/matador/sql/query_builder.hpp index 5d4cc5d..bf392aa 100644 --- a/include/matador/sql/query_builder.hpp +++ b/include/matador/sql/query_builder.hpp @@ -2,6 +2,7 @@ #define QUERY_QUERY_BUILDER_HPP #include "matador/sql/basic_condition.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/sql/column.hpp" #include "matador/sql/dialect.hpp" #include "matador/sql/key_value_pair.hpp" @@ -123,11 +124,11 @@ public: query_builder& update(const std::string &table); query_builder& remove(); - query_builder& table(const std::string &table, std::initializer_list columns); - query_builder& table(const std::string &table, const std::vector &columns); + query_builder& table(const std::string &table, std::initializer_list columns); + query_builder& table(const std::string &table, const std::vector &columns); query_builder& table(const std::string &table); - query_builder& into(const std::string &table, std::initializer_list column_names); - query_builder& into(const std::string &table, const std::vector &column_names); + query_builder& into(const std::string &table, std::initializer_list column_names); + query_builder& into(const std::string &table, const std::vector &column_names); query_builder& values(std::initializer_list values); query_builder& values(const std::vector &values); query_builder& from(const std::string &table, const std::string &as = ""); diff --git a/include/matador/sql/query_compiler.hpp b/include/matador/sql/query_compiler.hpp new file mode 100644 index 0000000..11c9da4 --- /dev/null +++ b/include/matador/sql/query_compiler.hpp @@ -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 +#include + +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 diff --git a/include/matador/sql/query_data.hpp b/include/matador/sql/query_data.hpp new file mode 100644 index 0000000..918fc95 --- /dev/null +++ b/include/matador/sql/query_data.hpp @@ -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 +#include + +namespace matador::sql { + +struct query_data +{ +// SqlCommands command; + std::vector> parts; + std::vector columns; + std::unordered_map table_map_by_index; + using table_ref = std::reference_wrapper; + std::unordered_map table_map_by_name; +}; + +} + +#endif //QUERY_QUERY_DATA_HPP diff --git a/include/matador/sql/query_intermediates.hpp b/include/matador/sql/query_intermediates.hpp index 151971b..170b36c 100644 --- a/include/matador/sql/query_intermediates.hpp +++ b/include/matador/sql/query_intermediates.hpp @@ -1,14 +1,14 @@ #ifndef QUERY_QUERY_INTERMEDIATES_HPP #define QUERY_QUERY_INTERMEDIATES_HPP -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/sql/column_generator.hpp" #include "matador/sql/column_name_generator.hpp" #include "matador/sql/key_value_generator.hpp" #include "matador/sql/key_value_pair.hpp" #include "matador/sql/placeholder_generator.hpp" -#include "matador/sql/query_builder.hpp" #include "matador/sql/query_result.hpp" +#include "matador/sql/query_data.hpp" #include "matador/sql/record.hpp" #include "matador/sql/statement.hpp" #include "matador/sql/schema.hpp" @@ -36,10 +36,10 @@ protected: class query_intermediate : public basic_query_intermediate { public: - query_intermediate(connection &db, query_builder &query); + query_intermediate(connection &db, query_data &data); protected: - query_builder &builder_; + query_data &data_; }; class query_execute_finish : public query_intermediate @@ -146,7 +146,7 @@ class query_join_intermediate : public query_intermediate public: using query_intermediate::query_intermediate; - query_on_intermediate on(const std::string &column, const std::string &join_column); + query_on_intermediate on(const basic_condition &cond); }; class query_from_intermediate : public query_select_finish @@ -154,7 +154,7 @@ class query_from_intermediate : public query_select_finish public: using query_select_finish::query_select_finish; - query_join_intermediate join(const std::string &join_table_name, const std::string &as); + query_join_intermediate join_left(const std::string &join_table_name, const std::string &as = ""); query_where_intermediate where(const basic_condition &cond); query_group_by_intermediate group_by(const std::string &name); query_order_by_intermediate order_by(const std::string &name); @@ -163,10 +163,10 @@ public: class query_start_intermediate : public basic_query_intermediate { public: - explicit query_start_intermediate(connection &s); + explicit query_start_intermediate(connection &db); protected: - query_builder builder_; + query_data data_; }; class query_select_intermediate : public query_start_intermediate @@ -192,16 +192,19 @@ public: using query_intermediate::query_intermediate; query_execute_finish values(std::initializer_list values); + query_execute_finish values(const std::vector& values); template query_execute_finish values() { Type obj; - return {connection_, builder_.values(as_placeholder(obj))}; + return {connection_, data_}; +// return {connection_, builder_.values(as_placeholder(obj))}; } template query_execute_finish values(const Type &obj) { - return {connection_, builder_.values(value_extractor::extract(obj))}; + return {connection_, data_}; +// return {connection_, builder_.values(value_extractor::extract(obj))}; } }; @@ -210,15 +213,16 @@ class query_create_intermediate : public query_start_intermediate public: explicit query_create_intermediate(connection &db); - query_execute_finish table(const std::string &table_name, std::initializer_list columns); - query_execute_finish table(const std::string &table_name, const std::vector &columns); + query_execute_finish table(const std::string &table_name, std::initializer_list columns); + query_execute_finish table(const std::string &table_name, const std::vector &columns); template query_execute_finish table(const std::string &table_name) { if (!tables()->exists()) { tables()->attach(table_name); } - return {connection_, builder_.table(table_name, column_generator::generate(*tables()))}; + return {connection_, data_}; +// return {connection_, builder_.table(table_name, column_generator::generate(*tables()))}; } }; @@ -235,17 +239,19 @@ class query_insert_intermediate : public query_start_intermediate public: explicit query_insert_intermediate(connection &s); - query_into_intermediate into(const std::string &table, std::initializer_list column_names); + query_into_intermediate into(const std::string &table, std::initializer_list column_names); template query_into_intermediate into(const std::string &table) { - return {connection_, builder_.into(table, column_name_generator::generate(*tables()))}; + return {connection_, data_}; +// return {connection_, builder_.into(table, column_name_generator::generate(*tables()))}; } template query_execute_finish into(const std::string &table, const Type &obj) { - return {connection_, builder_.into(table, column_name_generator::generate(*tables())) - .values(value_extractor::extract(obj))}; + return {connection_, data_}; +// return {connection_, builder_.into(table, column_name_generator::generate(*tables())) +// .values(value_extractor::extract(obj))}; } }; @@ -274,7 +280,8 @@ public: template 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))}; } }; diff --git a/include/matador/sql/query_part_visitor.hpp b/include/matador/sql/query_part_visitor.hpp new file mode 100644 index 0000000..1823945 --- /dev/null +++ b/include/matador/sql/query_part_visitor.hpp @@ -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 diff --git a/include/matador/sql/query_parts.hpp b/include/matador/sql/query_parts.hpp new file mode 100644 index 0000000..d95caf6 --- /dev/null +++ b/include/matador/sql/query_parts.hpp @@ -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 + +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 columns); + void accept(query_part_visitor &visitor) override; + + [[nodiscard]] const std::vector& columns() const; + +private: + std::vector 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 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 values); + +private: + void accept(query_part_visitor &visitor) override; + +private: + std::vector 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 diff --git a/include/matador/sql/record.hpp b/include/matador/sql/record.hpp index 38cfc50..cb2a983 100644 --- a/include/matador/sql/record.hpp +++ b/include/matador/sql/record.hpp @@ -3,7 +3,7 @@ #include "matador/utils/access.hpp" -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include #include @@ -13,8 +13,8 @@ namespace matador::sql { class record { private: - using column_by_index = std::vector; - using column_index_pair = std::pair, size_t>; + using column_by_index = std::vector; + using column_index_pair = std::pair, size_t>; using column_by_name_map = std::unordered_map; public: @@ -22,8 +22,8 @@ public: using const_iterator = column_by_index::const_iterator; record() = default; - record(std::initializer_list columns); - explicit record(const std::vector &columns); + record(std::initializer_list columns); + explicit record(const std::vector &columns); record(const record &x); record& operator=(const record &x); record(record&&) noexcept = default; @@ -43,15 +43,15 @@ public: append(make_column(name, size)); } - void append(column col); + void append(column_definition col); [[nodiscard]] bool has_primary_key() const; - [[nodiscard]] const column& primary_key() const; + [[nodiscard]] const column_definition& primary_key() const; - [[nodiscard]] const std::vector& columns() const; + [[nodiscard]] const std::vector& columns() const; - [[nodiscard]] const column& at(const std::string &name) const; - [[nodiscard]] const column& at(size_t index) const; + [[nodiscard]] const column_definition& at(const std::string &name) const; + [[nodiscard]] const column_definition& at(size_t index) const; iterator find(const std::string &column_name); [[nodiscard]] const_iterator find(const std::string &column_name) const; @@ -72,7 +72,7 @@ public: private: void init(); - void add_to_map(column &col, size_t index); + void add_to_map(column_definition &col, size_t index); private: column_by_index columns_; diff --git a/include/matador/sql/schema.hpp b/include/matador/sql/schema.hpp index 62b5be1..952bbf1 100644 --- a/include/matador/sql/schema.hpp +++ b/include/matador/sql/schema.hpp @@ -28,6 +28,8 @@ public: using iterator = repository::iterator; using const_iterator = repository::const_iterator; + std::string name() const; + template const table_info& attach(const std::string &table_name) { @@ -68,6 +70,7 @@ public: [[nodiscard]] bool empty() const; private: + std::string name_; repository repository_; }; diff --git a/include/matador/sql/session.hpp b/include/matador/sql/session.hpp index 5522490..af03b61 100644 --- a/include/matador/sql/session.hpp +++ b/include/matador/sql/session.hpp @@ -74,7 +74,7 @@ entity session::insert(Type *obj) if (!info) { return {}; } - c->insert().into(info->name).values(*obj).execute(); + c->query().insert().into(info->name).values(*obj).execute(); return entity{obj}; } diff --git a/include/matador/sql/table.hpp b/include/matador/sql/table.hpp new file mode 100644 index 0000000..2e440b2 --- /dev/null +++ b/include/matador/sql/table.hpp @@ -0,0 +1,17 @@ +#ifndef QUERY_TABLE_HPP +#define QUERY_TABLE_HPP + +#include +#include + +namespace matador::sql { + +struct table +{ + std::type_index index; + std::string name; +}; + +} + +#endif //QUERY_TABLE_HPP diff --git a/include/matador/utils/string.hpp b/include/matador/utils/string.hpp index a27fab7..9f2f704 100644 --- a/include/matador/utils/string.hpp +++ b/include/matador/utils/string.hpp @@ -38,7 +38,7 @@ std::string to_string(const blob &data); * given stream * * @tparam R Type og the range (e.g. map, list, vector, etc) - * @param range The range with the elements to join + * @param range The range with the elements to join_left * @param delim The delimiter for the elements * @return The ostream reference */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b4184b8..128bc0d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ set(SQL_SOURCES sql/dialect.cpp sql/query_builder.cpp - sql/column.cpp + sql/column_definition.cpp sql/key_value_pair.cpp sql/basic_condition.cpp sql/connection.cpp @@ -28,12 +28,16 @@ set(SQL_SOURCES sql/result_parameter_binder.cpp sql/statement.cpp sql/convert.cpp + sql/column.cpp + sql/query.cpp + sql/query_parts.cpp + sql/query_compiler.cpp ) set(SQL_HEADER ../include/matador/sql/dialect.hpp ../include/matador/sql/query_builder.hpp - ../include/matador/sql/column.hpp + ../include/matador/sql/column_definition.hpp ../include/matador/sql/data_type_traits.hpp ../include/matador/sql/key_value_pair.hpp ../include/matador/sql/basic_condition.hpp @@ -69,6 +73,34 @@ set(SQL_HEADER ../include/matador/sql/placeholder_generator.hpp ../include/matador/sql/result_parameter_binder.hpp ../include/matador/sql/convert.hpp + ../include/matador/sql/query.hpp + ../include/matador/sql/query_parts.hpp + ../include/matador/sql/query_part_visitor.hpp + ../include/matador/sql/query_compiler.hpp + ../include/matador/sql/query_data.hpp + ../include/matador/sql/table.hpp +) + +set(QUERY_SOURCES + query/query.cpp + query/query_compiler.cpp + query/query_parts.cpp + query/column.cpp + query/query_builder.cpp + query/query_intermediates.cpp +) + +set(QUERY_HEADER + ../include/matador/query/query.hpp + ../include/matador/query/query_part_visitor.hpp + ../include/matador/query/query_compiler.hpp + ../include/matador/query/query_parts.hpp + ../include/matador/query/column.hpp + ../include/matador/query/query_builder.hpp + ../include/matador/query/query_intermediates.hpp + ../include/matador/query/sql_commands.hpp + ../include/matador/query/query_data.hpp + ../include/matador/query/table.hpp ) set(UTILS_HEADER @@ -84,7 +116,8 @@ set(UTILS_HEADER ../include/matador/utils/enum_mapper.hpp ../include/matador/utils/types.hpp ../include/matador/utils/foreign_attributes.hpp - ../include/matador/utils/fetch_type.hpp) + ../include/matador/utils/fetch_type.hpp +) set(UTILS_SOURCES utils/field_attributes.cpp @@ -95,8 +128,14 @@ set(UTILS_SOURCES utils/identifier.cpp sql/value_extractor.cpp utils/logger.cpp - utils/foreign_attributes.cpp) + utils/foreign_attributes.cpp +) + +add_library(matador STATIC + ${SQL_SOURCES} ${SQL_HEADER} +# ${QUERY_SOURCES} ${QUERY_HEADER} + ${UTILS_SOURCES} ${UTILS_HEADER} +) -add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER}) target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include) #set_target_properties(matador PROPERTIES LINKER_LANGUAGE CXX) diff --git a/src/query/column.cpp b/src/query/column.cpp new file mode 100644 index 0000000..6ad324a --- /dev/null +++ b/src/query/column.cpp @@ -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; +} + +} \ No newline at end of file diff --git a/src/query/query.cpp b/src/query/query.cpp new file mode 100644 index 0000000..24b03ff --- /dev/null +++ b/src/query/query.cpp @@ -0,0 +1,6 @@ +#include "matador/query/query.hpp" + +namespace matador::sql { + + +} \ No newline at end of file diff --git a/src/query/query_builder.cpp b/src/query/query_builder.cpp new file mode 100644 index 0000000..4b7c832 --- /dev/null +++ b/src/query/query_builder.cpp @@ -0,0 +1,13 @@ +#include "matador/query/query_builder.hpp" + +namespace matador::query { + +query_builder::query_builder(const std::shared_ptr &scm) +: schema_(scm) {} + +query_select_intermediate query_builder::select(std::initializer_list columns) +{ + return query_select_intermediate{schema_}; +} + +} \ No newline at end of file diff --git a/src/query/query_compiler.cpp b/src/query/query_compiler.cpp new file mode 100644 index 0000000..299e6ed --- /dev/null +++ b/src/query/query_compiler.cpp @@ -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) +{ + +} + +} \ No newline at end of file diff --git a/src/query/query_intermediates.cpp b/src/query/query_intermediates.cpp new file mode 100644 index 0000000..d3ec52c --- /dev/null +++ b/src/query/query_intermediates.cpp @@ -0,0 +1,8 @@ +#include "matador/query/query_intermediates.hpp" + +namespace matador::query { + +query_intermediate::query_intermediate(const std::shared_ptr &scm) +: schema_(scm) {} + +} \ No newline at end of file diff --git a/src/query/query_parts.cpp b/src/query/query_parts.cpp new file mode 100644 index 0000000..fd6d233 --- /dev/null +++ b/src/query/query_parts.cpp @@ -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 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); +} +} \ No newline at end of file diff --git a/src/sql/column.cpp b/src/sql/column.cpp index 06dc701..2c98439 100644 --- a/src/sql/column.cpp +++ b/src/sql/column.cpp @@ -1,129 +1,10 @@ #include "matador/sql/column.hpp" -#include - namespace matador::sql { -column::column(sql_function_t func, std::string name) - : name_(std::move(name)), type_(data_type_t::type_int), attributes_(utils::null_attributes), function_(func) -{} - -column::column(const char *name, std::string alias) - : name_(name), attributes_(utils::null_attributes), alias_(std::move(alias)) -{} - -column::column(std::string name, std::string alias) - : name_(std::move(name)), attributes_(utils::null_attributes), alias_(std::move(alias)) -{} - -column::column(std::string name, data_type_t type, utils::field_attributes attr, null_option null_opt, size_t index) - : name_(std::move(name)), index_(index), type_(type), attributes_(attr), null_option_(null_opt) -{} - -column::column(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column, - utils::field_attributes attr, null_option null_opt) - : name_(std::move(name)) - , index_(index) - , type_(type) - , attributes_(attr) - , null_option_(null_opt) - , ref_table_(std::move(ref_table)) - , ref_column_(std::move(ref_column)) -{} - -const std::string &column::name() const +column operator ""_col(const char *name, size_t len) { - return name_; + return {{name, len}}; } -size_t column::index() const -{ - return index_; -} - -const utils::field_attributes &column::attributes() const -{ - return attributes_; -} - -bool column::is_nullable() const -{ - return null_option_ == null_option::NULLABLE; -} - -data_type_t column::type() const -{ - return type_; -} - -const std::string &column::alias() const -{ - return alias_; -} - -const std::string &column::ref_table() const -{ - return ref_table_; -} - -const std::string &column::ref_column() const -{ - return ref_column_; -} - -void column::type(data_type_t type) -{ - type_ = type; -} - -void column::alias(const std::string &as) -{ - alias_ = as; -} - -std::string column::str() const -{ - any_type_to_visitor visitor; - std::visit(visitor, const_cast(value_)); - return visitor.result; -} - -bool column::is_function() const -{ - return function_ != sql_function_t::NONE; -} - -sql_function_t column::function() const -{ - return function_; -} - -column operator "" _col(const char *name, size_t len) -{ - return {std::string(name, len)}; -} - -column make_column(const std::string &name, data_type_t type, utils::field_attributes attr, null_option null_opt) -{ - return {name, type, attr, null_opt}; -} - -template<> -column make_column(const std::string &name, utils::field_attributes attr, null_option null_opt) -{ - return make_column(name, data_type_traits::builtin_type(attr.size()), attr, null_opt); -} - -template<> -column make_pk_column(const std::string &name, size_t size) -{ - return make_column(name, {size, utils::constraints::FOREIGN_KEY}); -} - -template<> -[[maybe_unused]] 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::builtin_type(size), 0, ref_table, ref_column, {size, utils::constraints::FOREIGN_KEY}, null_option::NOT_NULL}; -} } \ No newline at end of file diff --git a/src/sql/column_definition.cpp b/src/sql/column_definition.cpp new file mode 100644 index 0000000..1e2bd27 --- /dev/null +++ b/src/sql/column_definition.cpp @@ -0,0 +1,100 @@ +#include "matador/sql/column_definition.hpp" + +#include + +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 visitor; + std::visit(visitor, const_cast(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(const std::string &name, utils::field_attributes attr, null_option null_opt) +{ + return make_column(name, data_type_traits::builtin_type(attr.size()), attr, null_opt); +} + +template<> +column_definition make_pk_column(const std::string &name, size_t size) +{ + return make_column(name, {size, utils::constraints::FOREIGN_KEY}); +} + +template<> +[[maybe_unused]] 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::builtin_type(size), 0, ref_table, ref_column, {size, utils::constraints::FOREIGN_KEY}, null_option::NOT_NULL}; +} +} diff --git a/src/sql/column_generator.cpp b/src/sql/column_generator.cpp index 8e13720..ae4472c 100644 --- a/src/sql/column_generator.cpp +++ b/src/sql/column_generator.cpp @@ -3,7 +3,7 @@ namespace matador::sql { -column_generator::column_generator(std::vector &columns, const schema &repo) +column_generator::column_generator(std::vector &columns, const schema &repo) : columns_(columns) , repo_(repo) {} diff --git a/src/sql/column_name_generator.cpp b/src/sql/column_name_generator.cpp index b10aa69..d2358a0 100644 --- a/src/sql/column_name_generator.cpp +++ b/src/sql/column_name_generator.cpp @@ -2,7 +2,7 @@ namespace matador::sql { -column_name_generator::column_name_generator(std::vector &column_infos, +column_name_generator::column_name_generator(std::vector &column_infos, const sql::schema &ts, const std::string &table_name) : column_infos_(column_infos) @@ -25,7 +25,7 @@ void column_name_generator::push(const std::string &column_name) { char str[4]; snprintf(str, 4, "c%02d", ++column_index); - column_infos_.emplace_back(column_info{table_name_stack_.top(), column_name, str}); + column_infos_.emplace_back(table_name_stack_.top(), column_name, str); } } \ No newline at end of file diff --git a/src/sql/condition.cpp b/src/sql/condition.cpp index 628824a..bb5ca7f 100644 --- a/src/sql/condition.cpp +++ b/src/sql/condition.cpp @@ -8,8 +8,8 @@ condition::type>::condition(const colu std::string condition::type>::evaluate(dialect &d, query_context &query) const { - query.bind_vars.emplace_back(field_.name()); - return d.prepare_identifier(field_.name()) + " " + operand + " " + d.next_placeholder(query.bind_vars); + query.bind_vars.emplace_back(field_.name); + return d.prepare_identifier(field_.name) + " " + operand + " " + d.next_placeholder(query.bind_vars); } condition::condition(column col, basic_condition::operand_t op, query_context &q) @@ -18,9 +18,13 @@ condition::condition(column col, basic_condition::operand std::string condition::evaluate(dialect &d, query_context &query) const { - std::string result(d.prepare_identifier(field_.name()) + " " + operand + " ("); + std::string result(d.prepare_identifier(field_.name) + " " + operand + " ("); result += (")"); return result; } +condition operator==(const column &a, const column &b) +{ + return {a, basic_condition::operand_t::EQUAL, b}; +} } \ No newline at end of file diff --git a/src/sql/connection.cpp b/src/sql/connection.cpp index 579701e..ca00dd2 100644 --- a/src/sql/connection.cpp +++ b/src/sql/connection.cpp @@ -8,7 +8,7 @@ namespace matador::sql { -connection::connection(connection_info info, const std::shared_ptr &repo) +connection::connection(connection_info info, const std::shared_ptr &repo) : connection_info_(std::move(info)) , logger_(stdout, "SQL") , dialect_(backend_provider::instance().connection_dialect(connection_info_.type)) @@ -17,7 +17,7 @@ connection::connection(connection_info info, const std::shared_ptr &repo connection_.reset(backend_provider::instance().create_connection(connection_info_.type, connection_info_)); } -connection::connection(const std::string& dns, const std::shared_ptr &repo) +connection::connection(const std::string& dns, const std::shared_ptr &repo) : connection(connection_info::parse(dns), repo) {} @@ -69,36 +69,6 @@ const connection_info &connection::info() const return connection_info_; } -query_create_intermediate connection::create() -{ - return query_create_intermediate(*this); -} - -query_drop_intermediate connection::drop() -{ - return query_drop_intermediate{*this}; -} - -query_select_intermediate connection::select(std::initializer_list columns) -{ - return {*this, columns}; -} - -query_insert_intermediate connection::insert() -{ - return query_insert_intermediate{*this}; -} - -query_update_intermediate connection::update(const std::string &table) -{ - return query_update_intermediate{*this, table}; -} - -query_delete_intermediate connection::remove() -{ - return query_delete_intermediate{*this}; -} - record connection::describe(const std::string &table_name) const { return std::move(connection_->describe(table_name)); @@ -120,15 +90,20 @@ size_t connection::execute(const std::string &sql) const return connection_->execute(sql); } +sql::query connection::query() const +{ + return sql::query(*const_cast(this)); +} + query_result connection::fetch(const query_context &q) const { if (q.prototype.empty() || q.prototype.unknown()) { const auto table_prototype = describe(q.table_name); for (auto &col : q.prototype) { if (const auto rit = table_prototype.find(col.name()); col.type() == data_type_t::type_unknown && rit != table_prototype.end()) { - const_cast(col).type(rit->type()); + const_cast(col).type(rit->type()); } - } + } } // auto it = prototypes_.find(q.table_name); // if (it == prototypes_.end()) { @@ -160,7 +135,7 @@ const class dialect &connection::dialect() const return dialect_; } -std::shared_ptr connection::tables() const +std::shared_ptr connection::schema() const { return schema_; } diff --git a/src/sql/dialect.cpp b/src/sql/dialect.cpp index dbd272b..6a43e57 100644 --- a/src/sql/dialect.cpp +++ b/src/sql/dialect.cpp @@ -1,5 +1,5 @@ #include "matador/sql/dialect.hpp" -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" #include "matador/utils/string.hpp" @@ -19,12 +19,12 @@ std::string dialect::prepare_identifier(const column &col) const { std::string result; if (!col.is_function()) { - result = prepare_identifier_string(col.name()); + result = prepare_identifier_string(col.name); } else { - result = sql_func_map_.at(col.function()) + "(" + col.name() + ")"; + result = sql_func_map_.at(col.function_) + "(" + col.name + ")"; } - if (!col.alias().empty()) { - result += " AS " + col.alias(); + if (!col.alias.empty()) { + result += " AS " + col.alias; } return result; } diff --git a/src/sql/query.cpp b/src/sql/query.cpp new file mode 100644 index 0000000..d95ffc9 --- /dev/null +++ b/src/sql/query.cpp @@ -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 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(); +} + +} \ No newline at end of file diff --git a/src/sql/query_builder.cpp b/src/sql/query_builder.cpp index 7488d42..f3786d9 100644 --- a/src/sql/query_builder.cpp +++ b/src/sql/query_builder.cpp @@ -1,5 +1,6 @@ #include "matador/sql/query_builder.hpp" #include "matador/sql/column_name_generator.hpp" +#include "matador/sql/column.hpp" #include "matador/sql/dialect.hpp" #include "matador/utils/string.hpp" @@ -139,19 +140,19 @@ query_builder &query_builder::select(const std::vector &columns) if (columns.size() < 2) { for (const auto &col: columns) { result.append(dialect_.prepare_identifier(col)); - query_.result_vars.emplace_back(col.name()); - query_.prototype.append(col); + query_.result_vars.emplace_back(col.name); + query_.prototype.append(column_definition{col.name}); } } else { auto it = columns.begin(); result.append(dialect_.prepare_identifier(*it)); - query_.result_vars.emplace_back(it->name()); - query_.prototype.append(column{*it++}); + query_.result_vars.emplace_back(it->name); + query_.prototype.append(column_definition{(*it++).name}); for (; it != columns.end(); ++it) { result.append(", "); result.append(dialect_.prepare_identifier(*it)); - query_.result_vars.emplace_back(it->name()); - query_.prototype.append(column{*it}); + query_.result_vars.emplace_back(it->name); + query_.prototype.append(column_definition{(*it).name}); } } @@ -187,9 +188,9 @@ query_builder &query_builder::remove() return *this; } -query_builder &query_builder::table(const std::string &table, std::initializer_list columns) +query_builder &query_builder::table(const std::string &table, std::initializer_list columns) { - return this->table(table, std::vector{columns}); + return this->table(table, std::vector{columns}); } struct fk_context @@ -205,9 +206,9 @@ struct column_context std::vector 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 &columns) +query_builder &query_builder::table(const std::string &table, const std::vector &columns) { transition_to(state_t::QUERY_TABLE_CREATE); @@ -256,12 +257,12 @@ query_builder &query_builder::table(const std::string &table) return *this; } -query_builder &query_builder::into(const std::string &table, std::initializer_list column_names) +query_builder &query_builder::into(const std::string &table, std::initializer_list column_names) { - return into(table, std::vector{column_names}); + return into(table, std::vector{column_names}); } -query_builder &query_builder::into(const std::string &table, const std::vector &column_names) +query_builder &query_builder::into(const std::string &table, const std::vector &column_names) { transition_to(state_t::QUERY_INTO); @@ -490,7 +491,7 @@ void query_builder::initialize(query_builder::command_t cmd, query_builder::stat query_parts_.clear(); } -std::string build_create_column(const column &col, const dialect &d, column_context &context) +std::string build_create_column(const column_definition &col, const dialect &d, column_context &context) { std::string result = d.prepare_identifier(col.name()) + " " + d.data_type_at(col.type()); if (col.attributes().size() > 0) { @@ -514,12 +515,12 @@ std::string build_create_column(const column &col, const dialect &d, column_cont column alias(const std::string &column, const std::string &as) { - return {column, as}; + return {"", column, as}; } column alias(column &&col, const std::string &as) { - col.alias(as); + col.as(as); return std::move(col); } diff --git a/src/sql/query_compiler.cpp b/src/sql/query_compiler.cpp new file mode 100644 index 0000000..eb94628 --- /dev/null +++ b/src/sql/query_compiler.cpp @@ -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) +{ + +} + +} \ No newline at end of file diff --git a/src/sql/query_intermediates.cpp b/src/sql/query_intermediates.cpp index 0834549..26cc349 100644 --- a/src/sql/query_intermediates.cpp +++ b/src/sql/query_intermediates.cpp @@ -1,5 +1,6 @@ #include "matador/sql/query_intermediates.hpp" #include "matador/sql/session.hpp" +#include "matador/sql/query_compiler.hpp" namespace matador::sql { basic_query_intermediate::basic_query_intermediate(connection &db) @@ -7,219 +8,252 @@ basic_query_intermediate::basic_query_intermediate(connection &db) std::shared_ptr basic_query_intermediate::tables() const { - return connection_.tables(); + return connection_.schema(); } query_result query_select_finish::fetch_all() { - return connection_.fetch(builder_.compile()); + query_compiler compiler(connection_.dialect()); + return connection_.fetch(compiler.compile(&data_)); } record query_select_finish::fetch_one() { - return *connection_.fetch(builder_.compile()).begin().get(); + query_compiler compiler(connection_.dialect()); + return *connection_.fetch(compiler.compile(&data_)).begin().get(); } std::unique_ptr query_select_finish::fetch() { - return connection_.fetch(builder_.compile().sql); + query_compiler compiler(connection_.dialect()); + return connection_.fetch(compiler.compile(&data_).sql); } statement query_select_finish::prepare() { - return connection_.prepare(builder_.compile()); + query_compiler compiler(connection_.dialect()); + return connection_.prepare(compiler.compile(&data_)); } -query_intermediate::query_intermediate(connection &db, query_builder &query) -: basic_query_intermediate(db), builder_(query) {} +query_intermediate::query_intermediate(connection &db, query_data &data) +: basic_query_intermediate(db), data_(data) {} query_offset_intermediate query_order_direction_intermediate::offset(size_t offset) { - return {connection_, builder_}; + return {connection_, data_}; } query_limit_intermediate query_offset_intermediate::limit(size_t limit) { - return {connection_, builder_}; + return {connection_, data_}; } query_limit_intermediate query_order_direction_intermediate::limit(size_t limit) { - return {connection_, builder_}; + return {connection_, data_}; } query_order_by_intermediate query_group_by_intermediate::order_by(const std::string &name) { - return {connection_, builder_.order_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.order_by(name)}; } query_order_direction_intermediate query_order_by_intermediate::asc() { - return {connection_, builder_.asc()}; + return {connection_, data_}; +// return {connection_, builder_.asc()}; } query_order_direction_intermediate query_order_by_intermediate::desc() { - return {connection_, builder_.desc()}; + return {connection_, data_}; +// return {connection_, builder_.desc()}; } query_group_by_intermediate query_from_intermediate::group_by(const std::string &name) { - return {connection_, builder_.group_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.group_by(name)}; } query_order_by_intermediate query_from_intermediate::order_by(const std::string &name) { - return {connection_, builder_.order_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.order_by(name)}; } query_group_by_intermediate query_where_intermediate::group_by(const std::string &name) { - return {connection_, builder_.group_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.group_by(name)}; } query_order_by_intermediate query_where_intermediate::order_by(const std::string &name) { - return {connection_, builder_.order_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.order_by(name)}; } query_join_intermediate query_on_intermediate::join(const std::string &join_table_name, const std::string &as) { - return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)}; + return {connection_, data_}; +// return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)}; } query_where_intermediate query_on_intermediate::where(const basic_condition &cond) { - return {connection_, builder_.where(cond)}; + return {connection_, data_}; +// return {connection_, builder_.where(cond)}; } query_group_by_intermediate query_on_intermediate::group_by(const std::string &name) { - return {connection_, builder_.group_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.group_by(name)}; } query_order_by_intermediate query_on_intermediate::order_by(const std::string &name) { - return {connection_, builder_.order_by(name)}; + return {connection_, data_}; +// return {connection_, builder_.order_by(name)}; } -query_on_intermediate query_join_intermediate::on(const std::string &column, const std::string &join_column) +query_on_intermediate query_join_intermediate::on(const basic_condition &cond) { - return {connection_, builder_.on(column, join_column)}; + return {connection_, data_}; +// return {connection_, builder_.on(column, join_column)}; } -query_join_intermediate query_from_intermediate::join(const std::string &join_table_name, const std::string &as) +query_join_intermediate query_from_intermediate::join_left(const std::string &join_table_name, const std::string &as) { - return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)}; + return {connection_, data_}; +// return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)}; } query_where_intermediate query_from_intermediate::where(const basic_condition &cond) { - return query_where_intermediate{connection_, builder_.where(cond)}; + return query_where_intermediate{connection_, data_}; +// return query_where_intermediate{connection_, builder_.where(cond)}; } -query_select_intermediate::query_select_intermediate(connection &s, const std::vector& columns) -: query_start_intermediate(s) +query_select_intermediate::query_select_intermediate(connection &db, const std::vector& columns) +: query_start_intermediate(db) { - builder_.select(columns); + data_.parts.push_back(std::make_unique(columns)); } query_from_intermediate query_select_intermediate::from(const std::string &table, const std::string &as) { - return {connection_, builder_.from(table, as)}; + return {connection_, data_}; +// return {connection_, builder_.from(table, as)}; } query_insert_intermediate::query_insert_intermediate(connection &s) : query_start_intermediate(s) { - builder_.insert(); + data_.parts.push_back(std::make_unique()); } -query_into_intermediate query_insert_intermediate::into(const std::string &table, std::initializer_list column_names) +query_into_intermediate query_insert_intermediate::into(const std::string &table, std::initializer_list column_names) { - return {connection_, builder_.into(table, column_names)}; + return {connection_, data_}; +// return {connection_, builder_.into(table, column_names)}; } size_t query_execute_finish::execute() { - return connection_.execute(builder_.compile().sql); + query_compiler compiler(connection_.dialect()); + return connection_.execute(compiler.compile(&data_).sql); } statement query_execute_finish::prepare() { - return connection_.prepare(builder_.compile()); + query_compiler compiler(connection_.dialect()); + return connection_.prepare(compiler.compile(&data_)); } query_execute_finish query_into_intermediate::values(std::initializer_list values) { - return {connection_, builder_.values(values)}; + return this->values(std::vector(values)); +} + +query_execute_finish query_into_intermediate::values(const std::vector &values) +{ + return {connection_, data_}; } query_create_intermediate::query_create_intermediate(connection &db) : query_start_intermediate(db) { - builder_.create(); + data_.parts.push_back(std::make_unique()); } -query_execute_finish query_create_intermediate::table(const std::string &table_name, std::initializer_list columns) +query_execute_finish query_create_intermediate::table(const std::string &table_name, std::initializer_list columns) { - return table(table_name, std::vector{columns}); + return table(table_name, std::vector{columns}); } -query_execute_finish query_create_intermediate::table(const std::string &table_name, const std::vector &columns) +query_execute_finish query_create_intermediate::table(const std::string &table_name, const std::vector &columns) { - return {connection_, builder_.table(table_name, columns)}; + return {connection_, data_}; +// return {connection_, builder_.table(table_name, columns)}; } query_drop_intermediate::query_drop_intermediate(connection &s) : query_start_intermediate(s) { - builder_.drop(); + data_.parts.push_back(std::make_unique()); } query_execute_finish query_drop_intermediate::table(const std::string &table) { - return {connection_, builder_.table(table)}; + return {connection_, data_}; +// return {connection_, builder_.table(table)}; } query_execute_finish query_execute_where_intermediate::limit(int limit) { - return {connection_, builder_.limit(limit)}; + return {connection_, data_}; +// return {connection_, builder_.limit(limit)}; } query_execute_where_intermediate query_set_intermediate::where(const basic_condition &cond) { - return {connection_, builder_.where(cond)}; + return {connection_, data_}; +// return {connection_, builder_.where(cond)}; } query_update_intermediate::query_update_intermediate(connection &s, const std::string& table_name) : query_start_intermediate(s) { - builder_.update(table_name); + data_.parts.push_back(std::make_unique(table_name)); } query_set_intermediate query_update_intermediate::set(std::initializer_list columns) { - return {connection_, builder_.set(columns)}; + return {connection_, data_}; +// return {connection_, builder_.set(columns)}; } query_execute_where_intermediate query_delete_from_intermediate::where(const basic_condition &cond) { - return {connection_, builder_.where(cond)}; + return {connection_, data_}; +// return {connection_, builder_.where(cond)}; } query_delete_intermediate::query_delete_intermediate(connection &s) : query_start_intermediate(s) { - builder_.remove(); + data_.parts.push_back(std::make_unique()); } query_delete_from_intermediate query_delete_intermediate::from(const std::string &table) { - return {connection_, builder_.from(table)}; + return {connection_, data_}; +// return {connection_, builder_.from(table)}; } -query_start_intermediate::query_start_intermediate(connection &s) -: basic_query_intermediate(s) -, builder_(s.dialect()) +query_start_intermediate::query_start_intermediate(connection &db) +: basic_query_intermediate(db) {} } \ No newline at end of file diff --git a/src/sql/query_parts.cpp b/src/sql/query_parts.cpp new file mode 100644 index 0000000..a40c706 --- /dev/null +++ b/src/sql/query_parts.cpp @@ -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 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& 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 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); +} + +} \ No newline at end of file diff --git a/src/sql/record.cpp b/src/sql/record.cpp index 1b934cd..fada43a 100644 --- a/src/sql/record.cpp +++ b/src/sql/record.cpp @@ -5,13 +5,13 @@ namespace matador::sql { -record::record(std::initializer_list columns) +record::record(std::initializer_list columns) : columns_(columns) { init(); } -record::record(const std::vector &columns) +record::record(const std::vector &columns) : columns_(columns) { init(); @@ -41,7 +41,7 @@ record &record::operator=(const record &x) return *this; } -const std::vector &record::columns() const +const std::vector &record::columns() const { return columns_; } @@ -51,7 +51,7 @@ bool record::has_primary_key() const return pk_index_ > -1; } -const column &record::primary_key() const +const column_definition &record::primary_key() const { if (!has_primary_key()) { throw std::logic_error("record has no primary key"); @@ -60,13 +60,13 @@ const column &record::primary_key() const return columns_[pk_index_]; } -const column &record::at(const std::string &name) const +const column_definition &record::at(const std::string &name) const { auto ref = columns_by_name_.at(name).first; return columns_by_name_.at(name).first; } -const column &record::at(size_t index) const +const column_definition &record::at(size_t index) const { return columns_.at(index); } @@ -82,7 +82,7 @@ record::const_iterator record::find(const std::string &column_name) const { return it != columns_by_name_.end() ? columns_.begin() + it->second.second : columns_.end(); } -void record::append(column col) +void record::append(column_definition col) { auto &ref = columns_.emplace_back(std::move(col)); add_to_map(ref, columns_.size()-1); @@ -149,7 +149,7 @@ void record::init() } } -void record::add_to_map(column &col, size_t index) +void record::add_to_map(column_definition &col, size_t index) { columns_by_name_.emplace(col.name(), column_index_pair {std::ref(col), index}); if (utils::is_constraint_set(col.attributes().options(), utils::constraints::PRIMARY_KEY)) { diff --git a/src/sql/schema.cpp b/src/sql/schema.cpp index a48b764..9afcddd 100644 --- a/src/sql/schema.cpp +++ b/src/sql/schema.cpp @@ -7,12 +7,17 @@ namespace matador::sql { void table_info::create(connection &conn) const { - conn.create().table(name, prototype.columns()).execute(); + conn.query().create().table(name, prototype.columns()).execute(); } void table_info::drop(connection &conn) const { - conn.drop().table(name).execute(); + conn.query().drop().table(name).execute(); +} + +std::string schema::name() const +{ + return name_; } const table_info& schema::attach(const std::type_index ti, const table_info& table) @@ -71,4 +76,5 @@ bool schema::empty() const { return repository_.empty(); } + } \ No newline at end of file diff --git a/src/sql/session.cpp b/src/sql/session.cpp index 87cdcd1..a598e42 100644 --- a/src/sql/session.cpp +++ b/src/sql/session.cpp @@ -25,7 +25,7 @@ void session::drop_table(const std::string &table_name) throw std::logic_error("no database connection available"); } - c->drop().table(table_name).execute(); + c->query().drop().table(table_name).execute(); } query_result session::fetch(const query_context &q) const @@ -41,7 +41,7 @@ query_result session::fetch(const query_context &q) const // adjust columns from given query for (auto &col : q.prototype) { if (const auto rit = it->second.find(col.name()); col.type() == data_type_t::type_unknown && rit != it->second.end()) { - const_cast(col).type(rit->type()); + const_cast(col).type(rit->type()); } } auto res = c->fetch(q.sql); diff --git a/test/ColumnGeneratorTest.cpp b/test/ColumnGeneratorTest.cpp index f826e6a..dff98f9 100644 --- a/test/ColumnGeneratorTest.cpp +++ b/test/ColumnGeneratorTest.cpp @@ -14,16 +14,16 @@ TEST_CASE("Generate columns from object", "[column generator]") { auto columns = column_generator::generate(repo); - const std::vector expected_columns = { - column{ "product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL }, - column{ "supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL }, - column{ "category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL }, - column{ "quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL }, - column{ "unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, - column{ "units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, - column{ "units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, - column{ "reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, - column{ "discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL } + const std::vector expected_columns = { + column_definition{"product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL }, + column_definition{"supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL }, + column_definition{"category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL }, + column_definition{"quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL }, + column_definition{"unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, + column_definition{"units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, + column_definition{"units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, + column_definition{"reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }, + column_definition{"discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL } }; REQUIRE(!columns.empty()); REQUIRE(columns.size() == expected_columns.size()); @@ -40,10 +40,10 @@ TEST_CASE("Generate columns from object with nullable columns", "[column generat auto columns = column_generator::generate(repo); - const std::vector expected_columns = { - column{ "id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL }, - column{ "name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL }, - column{ "age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL } + const std::vector expected_columns = { + column_definition{"id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL }, + column_definition{"name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL }, + column_definition{"age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL } }; REQUIRE(!columns.empty()); REQUIRE(columns.size() == expected_columns.size()); diff --git a/test/ColumnTest.cpp b/test/ColumnTest.cpp index 273e4fe..ab607b7 100644 --- a/test/ColumnTest.cpp +++ b/test/ColumnTest.cpp @@ -1,11 +1,11 @@ #include -#include "matador/sql/column.hpp" +#include "matador/sql/column_definition.hpp" using namespace matador::sql; TEST_CASE("Create empty column", "[column]") { - column c("name"); + column_definition c("name"); REQUIRE(c.name() == "name"); REQUIRE(c.index() == 0); @@ -25,7 +25,7 @@ TEST_CASE("Create empty column", "[column]") { } TEST_CASE("Copy and move column", "[column]") { - column c("name"); + column_definition c("name"); c.set(std::string{"george"}, 255); REQUIRE(c.name() == "name"); REQUIRE(c.index() == 0); diff --git a/test/QueryBuilderTest.cpp b/test/QueryBuilderTest.cpp index bde479c..cfb788e 100644 --- a/test/QueryBuilderTest.cpp +++ b/test/QueryBuilderTest.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include #include @@ -164,7 +164,7 @@ TEST_CASE("Create, insert and select a blob column", "[query][blob]") { REQUIRE(q.table_name == "person"); q = query.insert().into("person", { - {"", "id", ""}, {"", "name", ""}, {"", "data", ""} + { "id", "name", "data" } }).values({7UL, "george", blob{1, 'A', 3, 4}}).compile(); REQUIRE(q.sql == R"(INSERT INTO "person" ("id", "name", "data") VALUES (7, 'george', X'01410304'))"); @@ -176,7 +176,7 @@ TEST_CASE("Create, insert and select a blob column", "[query][blob]") { REQUIRE(q.table_name == "person"); } -TEST_CASE("Select statement with join", "[query][join]") { +TEST_CASE("Select statement with join_left", "[query][join_left]") { dialect d = dialect_builder::builder().create().build(); query_builder query(d);