From 6f5326941e141eadad74f2059af46f07640e7c6b Mon Sep 17 00:00:00 2001 From: Sascha Kuehl Date: Sat, 24 Feb 2024 18:16:23 +0100 Subject: [PATCH] query parts progress --- backends/tests/QueryRecordTest.cpp | 126 +++++++------- backends/tests/QueryTest.cpp | 68 ++++---- backends/tests/StatementTest.cpp | 14 +- backends/tests/TypeTraitsTest.cpp | 16 +- demo/main.cpp | 101 +++++++++-- include/matador/sql/column_definition.hpp | 2 + include/matador/sql/condition.hpp | 14 +- include/matador/sql/connection.hpp | 8 +- include/matador/sql/key_value_pair.hpp | 4 +- include/matador/sql/query.hpp | 14 +- include/matador/sql/query_compiler.hpp | 7 +- include/matador/sql/query_intermediates.hpp | 107 ++++++------ include/matador/sql/query_part_visitor.hpp | 13 ++ include/matador/sql/query_parts.hpp | 114 ++++++++++++- include/matador/sql/record.hpp | 5 +- include/matador/sql/schema.hpp | 2 + include/matador/sql/session.hpp | 10 +- src/sql/column_definition.cpp | 7 + src/sql/condition.cpp | 4 +- src/sql/connection.cpp | 16 +- src/sql/key_value_pair.cpp | 12 +- src/sql/query.cpp | 24 ++- src/sql/query_builder.cpp | 68 ++++---- src/sql/query_compiler.cpp | 180 +++++++++++++++++++- src/sql/query_intermediates.cpp | 168 +++++++++--------- src/sql/query_parts.cpp | 127 +++++++++++++- src/sql/record.cpp | 13 +- src/sql/schema.cpp | 7 +- src/sql/session.cpp | 9 +- test/ColumnGeneratorTest.cpp | 4 +- test/ColumnNameGeneratorTest.cpp | 4 +- 31 files changed, 887 insertions(+), 381 deletions(-) diff --git a/backends/tests/QueryRecordTest.cpp b/backends/tests/QueryRecordTest.cpp index 45b26e7..1b3bad0 100644 --- a/backends/tests/QueryRecordTest.cpp +++ b/backends/tests/QueryRecordTest.cpp @@ -14,6 +14,7 @@ class QueryRecordFixture public: QueryRecordFixture() : db(matador::test::connection::dns) + , schema(std::make_shared(db.dialect().default_schema_name())) { db.open(); } @@ -26,11 +27,12 @@ public: protected: matador::sql::connection db; + std::shared_ptr schema; private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.query().drop().table(table_name).execute(); + db.query(schema).drop().table(table_name).execute(); } } }; @@ -40,7 +42,7 @@ using namespace matador::sql; TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[session][record]") { REQUIRE(!db.exists("person")); - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -50,7 +52,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement", "[sessi REQUIRE(db.exists("person")); - db.query().drop() + db.query(schema).drop() .table("person") .execute(); @@ -59,7 +61,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.query().create() + db.query(schema).create() .table("airplane", { make_pk_column("id"), make_column("brand", 255), @@ -69,7 +71,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore REQUIRE(db.exists("airplane")); - db.query().create() + db.query(schema).create() .table("flight", { make_pk_column("id"), make_fk_column("airplane_id", "airplane", "id"), @@ -79,13 +81,13 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore REQUIRE(db.exists("flight")); - db.query().drop() + db.query(schema).drop() .table("flight") .execute(); REQUIRE(!db.exists("flight")); - db.query().drop() + db.query(schema).drop() .table("airplane") .execute(); @@ -94,7 +96,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Create and drop table statement with fore TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -102,14 +104,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi }) .execute(); - auto res = db.query().insert() + auto res = db.query(schema).insert() .into("person", {"id", "name", "age"}) .values({7, "george", 45}) .execute(); REQUIRE(res == 1); - auto result = db.query().select({"id", "name", "age"}) + auto result = db.query(schema).select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -126,14 +128,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement", "[sessi REQUIRE(i.at(2).template as() == 45); } - db.query().drop() + db.query(schema).drop() .table("person") .execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with foreign key", "[session][record]") { - db.query().create() + db.query(schema).create() .table("airplane", { make_pk_column("id"), make_column("brand", 255), @@ -141,7 +143,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore }) .execute(); - db.query().create() + db.query(schema).create() .table("flight", { make_pk_column("id"), make_fk_column("airplane_id", "airplane", "id"), @@ -149,23 +151,23 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore }) .execute(); - auto res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute(); + auto res = db.query(schema).insert().into("airplane", {"id", "brand", "model"}).values({1, "Airbus", "A380"}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute(); + res = db.query(schema).insert().into("airplane", {"id", "brand", "model"}).values({2, "Boeing", "707"}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute(); + res = db.query(schema).insert().into("airplane", {"id", "brand", "model"}).values({3, "Boeing", "747"}).execute(); REQUIRE(res == 1); - auto count = db.query().select({count_all()}).from("airplane").fetch_value(); + auto count = db.query(schema).select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); - res = db.query().insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute(); + res = db.query(schema).insert().into("flight", {"id", "airplane_id", "pilot_name"}).values({4, 1, "George"}).execute(); REQUIRE(res == 1); - db.query().drop().table("flight").execute(); - db.query().drop().table("airplane").execute(); + db.query(schema).drop().table("flight").execute(); + db.query(schema).drop().table("airplane").execute(); REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("airplane")); @@ -173,7 +175,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute insert record statement with fore TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -181,14 +183,14 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi }) .execute(); - auto res = db.query().insert() + auto res = db.query(schema).insert() .into("person", {"id", "name", "age"}) .values({7, "george", 45}) .execute(); REQUIRE(res == 1); - res = db.query().update("person") + res = db.query(schema).update("person") .set({{"id", 7}, {"name", "jane"}, {"age", 35}}) @@ -197,7 +199,7 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi REQUIRE(res == 1); - auto result = db.query().select({"id", "name", "age"}) + auto result = db.query(schema).select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -214,12 +216,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute update record statement", "[sessi REQUIRE(i.at(2).as() == 35); } - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -227,16 +229,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec }) .execute(); - auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - auto result = db.query().select({"id", "name", "age"}) + auto result = db.query(schema).select({"id", "name", "age"}) .from("person") .fetch_all(); @@ -247,22 +249,22 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement", "[session][rec } REQUIRE(expected_names.empty()); - auto rec = db.query().select({"id", "name", "age"}) + auto rec = db.query(schema).select({"id", "name", "age"}) .from("person") .fetch_one(); REQUIRE(rec.at(1).str() == "george"); - auto name = db.query().select({"name"}) + auto name = db.query(schema).select({"name"}) .from("person") .fetch_value(); REQUIRE(name == "george"); - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -270,16 +272,16 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", }) .execute(); - auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({2, "jane", 32}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({3, "michael", 67}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - auto result = db.query().select({"id", "name", "age"}) + auto result = db.query(schema).select({"id", "name", "age"}) .from("person") .order_by("name").asc() .fetch_all(); @@ -291,12 +293,12 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with order by", } REQUIRE(expected_names.empty()); - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by and order by", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -304,18 +306,18 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an }) .execute(); - auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({3, "michael", 13}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({4, "bob", 13}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({5, "charlie", 67}).execute(); REQUIRE(res == 1); - auto result = db.query().select({alias(count("age"), "age_count"), "age"}) + auto result = db.query(schema).select({alias(count("age"), "age_count"), "age"}) .from("person") .group_by("age") .order_by("age_count").desc() @@ -330,41 +332,41 @@ TEST_CASE_METHOD(QueryRecordFixture, " Execute select statement with group by an expected_values.pop_front(); } - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Execute delete statement", "[session][record]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), make_column("age") }).execute(); - auto res = db.query().insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); + auto res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({1, "george", 45}).execute(); REQUIRE(res == 1); - res = db.query().insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); + res = db.query(schema).insert().into("person", {"id", "name", "age"}).values({2, "jane", 45}).execute(); REQUIRE(res == 1); - auto count = db.query().select({count_all()}).from("person").fetch_value(); + auto count = db.query(schema).select({count_all()}).from("person").fetch_value(); REQUIRE(count == 2); - res = db.query().remove() + res = db.query(schema).remove() .from("person") .where("id"_col == 1) .execute(); REQUIRE(res == 1); - count = db.query().select({count_all()}).from("person").fetch_value(); + count = db.query(schema).select({count_all()}).from("person").fetch_value(); REQUIRE(count == 1); - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][record]") { - db.query().create() + db.query(schema).create() .table("quotes", { make_column("from", 255), make_column("to", 255) @@ -380,19 +382,19 @@ TEST_CASE_METHOD(QueryRecordFixture, " Test quoted identifier", "[session][recor REQUIRE(field.type() == types[field.index()]); } - db.query().insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute(); + db.query(schema).insert().into("quotes", {"from", "to"}).values({"Berlin", "London"}).execute(); - auto res = db.query().select({"from", "to"}).from("quotes").fetch_one(); + auto res = db.query(schema).select({"from", "to"}).from("quotes").fetch_one(); REQUIRE("Berlin" == res.at("from").str()); REQUIRE("London" == res.at("to").str()); - db.query().update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute(); + db.query(schema).update("quotes").set({{"from", "Hamburg"}, {"to", "New York"}}).where("from"_col == "Berlin").execute(); - res = db.query().select({"from", "to"}).from("quotes").fetch_one(); + res = db.query(schema).select({"from", "to"}).from("quotes").fetch_one(); REQUIRE("Hamburg" == res.at("from").str()); REQUIRE("New York" == res.at("to").str()); - db.query().drop().table("quotes").execute(); + db.query(schema).drop().table("quotes").execute(); } \ No newline at end of file diff --git a/backends/tests/QueryTest.cpp b/backends/tests/QueryTest.cpp index 3ac9cbd..8b95f8d 100644 --- a/backends/tests/QueryTest.cpp +++ b/backends/tests/QueryTest.cpp @@ -19,6 +19,7 @@ class QueryFixture public: QueryFixture() : db(matador::test::connection::dns) + , schema(std::make_shared(db.dialect().default_schema_name())) { db.open(); } @@ -32,32 +33,33 @@ public: protected: matador::sql::connection db; + std::shared_ptr schema; private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.query().drop().table(table_name).execute(); + db.query(schema).drop().table(table_name).execute(); } } }; TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[session]") { - db.query().create() + db.query(schema).create() .table("airplane") .execute(); REQUIRE(db.exists("airplane")); - db.query().create() + db.query(schema).create() .table("flight") .execute(); REQUIRE(db.exists("flight")); - db.query().drop().table("flight").execute(); - db.query().drop().table("airplane").execute(); + db.query(schema).drop().table("flight").execute(); + db.query(schema).drop().table("airplane").execute(); REQUIRE(!db.exists("flight")); REQUIRE(!db.exists("airplane")); @@ -65,20 +67,22 @@ TEST_CASE_METHOD(QueryFixture, " Create table with foreign key relation", "[sess TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[session]") { - db.query().create() + db.query(schema).create() .table("person") .execute(); person george{7, "george", 45}; george.image.push_back(37); - auto res = db.query().insert() - .into("person", george) + auto res = db.query(schema) + .insert() + .into("person") + .values(george) .execute(); REQUIRE(res == 1); // fetch person as record - auto result_record = db.query().select() + auto result_record = db.query(schema).select() .from("person") .where("id"_col == 7) .fetch_all(); @@ -97,7 +101,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[ } // fetch person as person - auto result_person = db.query().select() + auto result_person = db.query(schema).select() .from("person") .where("id"_col == 7) .fetch_all(); @@ -108,12 +112,12 @@ TEST_CASE_METHOD(QueryFixture, " Execute select statement with where clause", "[ REQUIRE(i.age == 45); } - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") { - db.query().create() + db.query(schema).create() .table("person", { make_pk_column("id"), make_column("name", 255), @@ -121,7 +125,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") }) .execute(); - auto res = db.query().insert() + auto res = db.query(schema).insert() .into("person", {{"", "id", ""}, {"", "name", ""}, {"", "color", ""}}) .values({7, "george", "green"}) .execute(); @@ -129,7 +133,7 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") REQUIRE(res == 1); // fetch person as record - auto result_record = db.query().select({"id", "name", "color"}) + auto result_record = db.query(schema).select({"id", "name", "color"}) .from("person") .where("id"_col == 7) .fetch_all(); @@ -147,16 +151,16 @@ TEST_CASE_METHOD(QueryFixture, " Execute insert statement", "[session]") REQUIRE(i.at(2).as() == "green"); } - db.query().drop().table("person").execute(); + db.query(schema).drop().table("person").execute(); } TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]") { - db.query().create() + db.query(schema).create() .table("airplane") .execute(); - db.query().create() + db.query(schema).create() .table("flight") .execute(); @@ -167,35 +171,35 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key", "[session]" }; for (const auto &plane: planes) { - auto res = db.query().insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto count = db.query().select({count_all()}).from("airplane").fetch_value(); + auto count = db.query(schema).select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); flight f4711{4, planes.at(1), "hans"}; - auto res = db.query().insert().into("flight").values(f4711).execute(); + auto res = db.query(schema).insert().into("flight").values(f4711).execute(); REQUIRE(res == 1); - auto f = *db.query().select().from("flight").fetch_all().begin(); + auto f = *db.query(schema).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.query().drop().table("flight").execute(); - db.query().drop().table("airplane").execute(); + db.query(schema).drop().table("flight").execute(); + db.query(schema).drop().table("airplane").execute(); } TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left", "[session][join_left]") { - db.query().create() + db.query(schema).create() .table("airplane") .execute(); - db.query().create() + db.query(schema).create() .table("flight") .execute(); @@ -206,11 +210,11 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left }; for (const auto &plane: planes) { - auto res = db.query().insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto count = db.query().select({count_all()}).from("airplane").fetch_value(); + auto count = db.query(schema).select({count_all()}).from("airplane").fetch_value(); REQUIRE(count == 3); std::vector> flights{ @@ -221,17 +225,17 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left }; for (const auto &f: flights) { - auto res = db.query().insert().into("flight").values(*f).execute(); + auto res = db.query(schema).insert().into("flight").values(*f).execute(); REQUIRE(res == 1); } - auto f = *db.query().select().from("flight").fetch_all().begin(); + auto f = *db.query(schema).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.query().select({"f.id", "ap.brand", "ap.model", "f.pilot_name"}) + auto result = db.query(schema).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) @@ -251,7 +255,7 @@ TEST_CASE_METHOD(QueryFixture, " Select statement with foreign key and join_left REQUIRE(r.at(3).as() == expected_result[index++].second); } - db.query().drop().table("flight").execute(); - db.query().drop().table("airplane").execute(); + db.query(schema).drop().table("flight").execute(); + db.query(schema).drop().table("airplane").execute(); } \ No newline at end of file diff --git a/backends/tests/StatementTest.cpp b/backends/tests/StatementTest.cpp index aeef342..11580e4 100644 --- a/backends/tests/StatementTest.cpp +++ b/backends/tests/StatementTest.cpp @@ -16,9 +16,10 @@ class StatementTestFixture public: StatementTestFixture() : db(matador::test::connection::dns) + , schema(std::make_shared(db.dialect().default_schema_name())) { db.open(); - db.query().create().table("airplane").execute(); + db.query(schema).create().table("airplane").execute(); } ~StatementTestFixture() @@ -28,6 +29,7 @@ public: protected: matador::sql::connection db; + std::shared_ptr schema; std::vector> planes{ make_entity(1, "Airbus", "A380"), @@ -38,7 +40,7 @@ protected: private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.query().drop().table(table_name).execute(); + db.query(schema).drop().table(table_name).execute(); } } @@ -48,7 +50,7 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement { table ap{"airplane"}; SECTION("Insert with prepared statement and placeholder") { - auto stmt = db.query().insert() + auto stmt = db.query(schema).insert() .into("airplane") .values().prepare(); @@ -58,7 +60,7 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement stmt.reset(); } - auto result = db.query().select().from(ap).fetch_all(); + auto result = db.query(schema).select().from(ap).fetch_all(); size_t index{0}; for (const auto &i: result) { @@ -70,11 +72,11 @@ TEST_CASE_METHOD(StatementTestFixture, " Create prepared statement", "[statement SECTION("Select with prepared statement") { for (const auto &plane: planes) { - auto res = db.query().insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); REQUIRE(res == 1); } - auto stmt = db.query().select().from(ap).where("brand"_col == _).prepare(); + auto stmt = db.query(schema).select().from(ap).where("brand"_col == _).prepare(); stmt.bind(0, "Airbus"); diff --git a/backends/tests/TypeTraitsTest.cpp b/backends/tests/TypeTraitsTest.cpp index 1289a01..f74b511 100644 --- a/backends/tests/TypeTraitsTest.cpp +++ b/backends/tests/TypeTraitsTest.cpp @@ -15,25 +15,27 @@ class TypeTraitsTestFixture public: TypeTraitsTestFixture() : db(matador::test::connection::dns) + , schema(std::make_shared(db.dialect().default_schema_name())) { db.open(); - db.query().create() + db.query(schema).create() .table("location") .execute(); } ~TypeTraitsTestFixture() { - db.query().drop().table("location").execute(); + db.query(schema).drop().table("location").execute(); } protected: matador::sql::connection db; + std::shared_ptr schema; private: void drop_table_if_exists(const std::string &table_name) { if (db.exists(table_name)) { - db.query().drop().table(table_name).execute(); + db.query(schema).drop().table(table_name).execute(); } } }; @@ -85,10 +87,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.query().insert().into("location").values(loc).execute(); + auto res = db.query(schema).insert().into("location").values(loc).execute(); REQUIRE(res == 1); - auto result = db.query().select().from("location").fetch_all(); + auto result = db.query(schema).select().from("location").fetch_all(); for (const auto &l: result) { REQUIRE(l.name == "center"); @@ -98,11 +100,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.query().insert().into("location").values().prepare(); + auto stmt = db.query(schema).insert().into("location").values().prepare(); auto res = stmt.bind(loc).execute(); REQUIRE(res == 1); - auto result = db.query().select().from("location"). + auto result = db.query(schema).select().from("location"). template fetch_all(); for (const auto &l: result) { diff --git a/demo/main.cpp b/demo/main.cpp index 1869ae6..b263fc9 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -61,26 +61,97 @@ int main() std::string dns{"sqlite://demo.db"}; // std::string dns{"memory://test"}; - auto s = std::make_shared(); + auto s = std::make_shared("main"); s->attach("authors"); s->attach("books"); - connection c(dns, s); + connection c(dns); + c.open(); - auto books = c.query() - .select({qh::authors.first_name}) + auto create_authors_sql = c.query(s) + .create() + .table(qh::authors) +// .str(); + .execute(); + + c.query(s).create().table(qh::books).execute(); + + std::cout << "SQL: " << create_authors_sql << "\n"; + + auto mc = make_entity(); + mc->id = 1; + mc->first_name = "Michael"; + mc->last_name = "Crichton"; + mc->date_of_birth = "19.8.1954"; + mc->year_of_birth = 1954; + mc->distinguished = true; + auto insert_authors_sql = c.query(s) + .insert() + .into(qh::authors) + .values(*mc) + .execute(); +// .str(); + + std::cout << "SQL: " << insert_authors_sql << "\n"; + + auto result = c.query(s) + .select() + .from(qh::authors) + .fetch_all(); + + for (const auto &row : result) { + std::cout << "Author " << row.at(qh::authors.first_name) << "\n"; + } + + auto update_authors_sql = c.query(s) + .update(qh::authors) + .set({{qh::authors.first_name, "Stephen"}, {qh::authors.last_name, "King"}}) + .where(qh::authors.last_name == "Crichton") + .execute(); +// .str(); + + std::cout << "SQL: " << update_authors_sql << "\n"; + + auto authors = c.query(s) + .select() + .from(qh::authors) + .fetch_all(); + + for (const auto &a : authors) { + std::cout << "Author " << a.first_name << "\n"; + } + + c.query(s) + .insert() + .into(qh::books) + .values({2, "It", mc->id, 1980}) + .execute(); + + c.query(s) + .insert() + .into(qh::books) + .values({3, "Misery", mc->id, 1984}) + .execute(); + + auto select_books_sql = c.query(s) + .select({qh::authors.last_name}) .from(qh::books) .join_left(qh::authors) .on(qh::books.author_id == qh::authors.id) - .where(qh::books.published_in < 2008 && qh::authors.first_name == "Michael Crichton") + .where(qh::books.published_in < 2008 && qh::authors.last_name == "King") + .group_by(qh::books.published_in) .order_by(qh::books.title).asc() - .offset(2) - .limit(5) - .str(); +// .offset(2) +// .limit(5) +// .str(); + .fetch_all(); // .fetch_all(); - std::cout << "SQL: " << books << "\n"; +// std::cout << "SQL: " << select_books_sql << "\n"; + for (const auto &r : select_books_sql) { + std::cout << "R: " << r.at(qh::books.title) << ", " << r.at(qh::authors.last_name) << "\n"; + } // SELECT book.title, book.id, book.author_id, book.published_in, author.name // FROM book // INNER JOIN author ON book.author_id = author.id @@ -88,7 +159,6 @@ int main() // ORDER BY "book.title" ASC // OFFSET 2 LIMIT 5 - // char var[1024]; // size_t len{}; // const auto error = getenv_s(&len, var, 1024, env_var.c_str()); @@ -97,5 +167,16 @@ int main() // } else { // std::cout << "env var: " << var << "\n"; // } + + c.query(s).drop().table(qh::books).execute(); + + auto drop_authors_sql = c.query(s) + .drop() + .table(qh::authors) +// .str(); + .execute(); + + std::cout << "SQL: " << drop_authors_sql << "\n"; + return 0; } diff --git a/include/matador/sql/column_definition.hpp b/include/matador/sql/column_definition.hpp index 3076ff9..cf4fbe7 100644 --- a/include/matador/sql/column_definition.hpp +++ b/include/matador/sql/column_definition.hpp @@ -96,6 +96,8 @@ public: return visitor.result; } + friend std::ostream& operator<<(std::ostream &out, const column_definition &col); + private: template void process(Operator &op) diff --git a/include/matador/sql/condition.hpp b/include/matador/sql/condition.hpp index a6f7609..a85f5d7 100644 --- a/include/matador/sql/condition.hpp +++ b/include/matador/sql/condition.hpp @@ -57,7 +57,7 @@ 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); + return d.prepare_identifier(field_) + " " + operand + " " + std::to_string(value); } }; @@ -77,7 +77,7 @@ 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 + "'"; + return d.prepare_identifier(field_) + " " + operand + " '" + value + "'"; } }; @@ -97,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_); } }; @@ -116,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_); } }; @@ -162,7 +162,7 @@ public: query.bind_vars.emplace_back(field_.name); } - std::string result = d.prepare_identifier(field_.name) + " IN ("; + std::string result = d.prepare_identifier(field_) + " IN ("; if (args_.size() < 2) { for (const auto &val : args_) { result.append(std::to_string(val)); @@ -264,7 +264,7 @@ public: 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); + return d.prepare_identifier(field_) + " BETWEEN " + std::to_string(range_.first) + " AND " + std::to_string(range_.second); } private: @@ -371,7 +371,7 @@ public: */ std::string evaluate(dialect &d, query_context &query) const override { - return d.prepare_identifier(field_.name) + " " + operand + " " + d.prepare_identifier(other_column_.name); + return d.prepare_identifier(field_) + " " + operand + " " + d.prepare_identifier(other_column_); } private: diff --git a/include/matador/sql/connection.hpp b/include/matador/sql/connection.hpp index 9789eed..54ff079 100644 --- a/include/matador/sql/connection.hpp +++ b/include/matador/sql/connection.hpp @@ -20,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); + explicit connection(const std::string& dns); connection(const connection &x); connection& operator=(const connection &x); connection(connection &&x) noexcept = default; @@ -36,7 +36,7 @@ public: [[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; + sql::query query(const std::shared_ptr &schema) const; query_result fetch(const query_context &q) const; [[nodiscard]] std::unique_ptr fetch(const std::string &sql) const; @@ -45,14 +45,12 @@ public: statement prepare(query_context &&query) const; const class dialect& dialect() 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_; }; } diff --git a/include/matador/sql/key_value_pair.hpp b/include/matador/sql/key_value_pair.hpp index fe543a3..ca78fa1 100644 --- a/include/matador/sql/key_value_pair.hpp +++ b/include/matador/sql/key_value_pair.hpp @@ -2,13 +2,15 @@ #define QUERY_KEY_VALUE_PAIR_HPP #include "matador/sql/any_type.hpp" +#include "matador/sql/column.hpp" namespace matador::sql { class key_value_pair { public: - key_value_pair(const std::string &name, any_type value); + key_value_pair(const sql::column &col, any_type value); + key_value_pair(std::string name, any_type value); key_value_pair(const char *name, any_type value); [[nodiscard]] const std::string& name() const; diff --git a/include/matador/sql/query.hpp b/include/matador/sql/query.hpp index c062ad4..e66e6d4 100644 --- a/include/matador/sql/query.hpp +++ b/include/matador/sql/query.hpp @@ -10,7 +10,7 @@ class connection; class query { public: - explicit query(connection &c); + explicit query(connection &db, const std::shared_ptr &schema); query(const query &) = delete; query& operator=(const query &) = delete; @@ -22,28 +22,26 @@ public: 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_update_intermediate update(const sql::table &table); query_delete_intermediate remove(); -private: - [[nodiscard]] const sql::schema& schema() const; - private: connection &connection_; + std::shared_ptr schema_; }; template query_select_intermediate query::select() { - return query_select_intermediate{connection_, column_name_generator::generate(this->schema())}; + return query_select_intermediate{connection_, schema_, column_name_generator::generate(*schema_)}; } template query_select_intermediate query::select(std::initializer_list columns) { - auto cols = column_name_generator::generate(this->schema()); + auto cols = column_name_generator::generate(*schema_); cols.insert(cols.end(), columns); - return query_select_intermediate{connection_, cols}; + return query_select_intermediate{connection_, schema_, cols}; } } diff --git a/include/matador/sql/query_compiler.hpp b/include/matador/sql/query_compiler.hpp index 3d30834..3373b5b 100644 --- a/include/matador/sql/query_compiler.hpp +++ b/include/matador/sql/query_compiler.hpp @@ -31,17 +31,22 @@ private: 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_offset_part &offset_part) override; + void visit(query_limit_part &limit_part) override; void visit(query_insert_part &insert_part) override; + void visit(query_into_part &into_part) override; void visit(query_values_part &values_part) override; void visit(query_update_part &update_part) override; + void visit(query_set_part &set_part) override; void visit(query_delete_part &delete_part) override; void visit(query_create_part &create_part) override; + void visit(query_create_table_part &create_table_part) override; void visit(query_drop_part &drop_part) override; + void visit(query_drop_table_part &drop_table_part) override; private: const sql::dialect &dialect_; diff --git a/include/matador/sql/query_intermediates.hpp b/include/matador/sql/query_intermediates.hpp index f4509ce..9e4eecb 100644 --- a/include/matador/sql/query_intermediates.hpp +++ b/include/matador/sql/query_intermediates.hpp @@ -24,19 +24,17 @@ class connection; class basic_query_intermediate { public: - explicit basic_query_intermediate(connection &db); - -protected: - [[nodiscard]] std::shared_ptr tables() const; + explicit basic_query_intermediate(connection &db, const std::shared_ptr &schema); protected: connection &connection_; + std::shared_ptr schema_; }; class query_intermediate : public basic_query_intermediate { public: - query_intermediate(connection &db, query_data &data); + query_intermediate(connection &db, const std::shared_ptr &schema, query_data &data); protected: query_data &data_; @@ -49,6 +47,7 @@ public: size_t execute(); statement prepare(); + [[nodiscard]] std::string str() const; }; class query_select_finish : public query_intermediate @@ -109,7 +108,7 @@ class query_group_by_intermediate : public query_select_finish public: using query_select_finish::query_select_finish; - query_order_by_intermediate order_by(const std::string &name); + query_order_by_intermediate order_by(const column &col); }; class query_order_by_intermediate : public query_intermediate @@ -126,7 +125,7 @@ class query_where_intermediate : public query_select_finish public: using query_select_finish::query_select_finish; - query_group_by_intermediate group_by(const std::string &name); + query_group_by_intermediate group_by(const column &col); query_order_by_intermediate order_by(const column &col); }; @@ -137,14 +136,14 @@ class query_on_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 table &t); template query_where_intermediate where(const Condition &cond) { data_.parts.push_back(std::make_unique(cond)); - return {connection_, data_}; + return {connection_, schema_, data_}; } - query_group_by_intermediate group_by(const std::string &name); + query_group_by_intermediate group_by(const column &col); query_order_by_intermediate order_by(const column &col); }; @@ -157,7 +156,7 @@ public: query_on_intermediate on(const Condition &cond) { data_.parts.push_back(std::make_unique(cond)); - return {connection_, data_}; + return {connection_, schema_, data_}; } }; @@ -167,15 +166,20 @@ public: using query_select_finish::query_select_finish; query_join_intermediate join_left(const table &t); - 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); + template + query_where_intermediate where(const Condition &cond) + { + data_.parts.push_back(std::make_unique(cond)); + return {connection_, schema_, data_}; + } + query_group_by_intermediate group_by(const column &col); + query_order_by_intermediate order_by(const column &col); }; class query_start_intermediate : public basic_query_intermediate { public: - explicit query_start_intermediate(connection &db); + explicit query_start_intermediate(connection &db, const std::shared_ptr &schema); protected: query_data data_; @@ -184,7 +188,7 @@ protected: class query_select_intermediate : public query_start_intermediate { public: - query_select_intermediate(connection &s, const std::vector& columns); + query_select_intermediate(connection &db, const std::shared_ptr &schema, const std::vector& columns); query_from_intermediate from(const table& t); }; @@ -209,61 +213,54 @@ public: query_execute_finish values() { Type obj; - return {connection_, data_}; -// return {connection_, builder_.values(as_placeholder(obj))}; + data_.parts.push_back(std::make_unique(as_placeholder(obj))); + return {connection_, schema_, data_}; } template query_execute_finish values(const Type &obj) { - return {connection_, data_}; -// return {connection_, builder_.values(value_extractor::extract(obj))}; + data_.parts.push_back(std::make_unique(value_extractor::extract(obj))); + return {connection_, schema_, data_}; } }; class query_create_intermediate : public query_start_intermediate { public: - explicit query_create_intermediate(connection &db); + explicit query_create_intermediate(connection &db, const std::shared_ptr &schema); - 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 sql::table &table, std::initializer_list columns); + query_execute_finish table(const sql::table &table, const std::vector &columns); template - query_execute_finish table(const std::string &table_name) + query_execute_finish table(const sql::table &table) { - if (!tables()->exists()) { - tables()->attach(table_name); + if (!schema_->exists()) { + schema_->attach(table.name); } - return {connection_, data_}; -// return {connection_, builder_.table(table_name, column_generator::generate(*tables()))}; + data_.parts.push_back(std::make_unique(table, column_generator::generate(*schema_))); + return {connection_, schema_, data_}; } }; class query_drop_intermediate : query_start_intermediate { public: - explicit query_drop_intermediate(connection &s); + explicit query_drop_intermediate(connection &db, const std::shared_ptr &schema); - query_execute_finish table(const std::string &table); + query_execute_finish table(const sql::table &table); }; class query_insert_intermediate : public query_start_intermediate { public: - explicit query_insert_intermediate(connection &s); + explicit query_insert_intermediate(connection &db, const std::shared_ptr &schema); - query_into_intermediate into(const std::string &table, std::initializer_list column_names); + query_into_intermediate into(const sql::table &table, std::initializer_list column_names); template - query_into_intermediate into(const std::string &table) - { - 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_, data_}; -// return {connection_, builder_.into(table, column_name_generator::generate(*tables())) -// .values(value_extractor::extract(obj))}; + query_into_intermediate into(const sql::table &table) + {; + data_.parts.push_back(std::make_unique(table, column_name_generator::generate(*schema_))); + return {connection_, schema_, data_}; } }; @@ -280,20 +277,25 @@ class query_set_intermediate : public query_execute_finish public: using query_execute_finish::query_execute_finish; - query_execute_where_intermediate where(const basic_condition &cond); + template + query_execute_where_intermediate where(const Condition &cond) + { + data_.parts.push_back(std::make_unique(cond)); + return {connection_, schema_, data_}; + } }; class query_update_intermediate : public query_start_intermediate { public: - query_update_intermediate(connection &s, const std::string& table_name); + query_update_intermediate(connection &db, const std::shared_ptr &schema, const sql::table& table); query_set_intermediate set(std::initializer_list columns); template query_set_intermediate set(const Type &obj) { - return {connection_, data_}; -// return {connection_, builder_.set(key_value_generator::generate(obj))}; + data_.parts.push_back(std::make_unique(key_value_generator::generate(obj))); + return {connection_, schema_, data_}; } }; @@ -302,15 +304,20 @@ class query_delete_from_intermediate : public query_execute_finish public: using query_execute_finish::query_execute_finish; - query_execute_where_intermediate where(const basic_condition &cond); + template + query_execute_where_intermediate where(const Condition &cond) + { + data_.parts.push_back(std::make_unique(cond)); + return {connection_, schema_, data_}; + } }; class query_delete_intermediate : public query_start_intermediate { public: - explicit query_delete_intermediate(connection &s); + explicit query_delete_intermediate(connection &db, const std::shared_ptr &schema); - query_delete_from_intermediate from(const std::string &table); + query_delete_from_intermediate from(const sql::table &table); }; } diff --git a/include/matador/sql/query_part_visitor.hpp b/include/matador/sql/query_part_visitor.hpp index c57b39c..00f5123 100644 --- a/include/matador/sql/query_part_visitor.hpp +++ b/include/matador/sql/query_part_visitor.hpp @@ -12,12 +12,18 @@ class query_group_by_part; class query_order_by_part; class query_order_by_asc_part; class query_order_by_desc_part; +class query_offset_part; +class query_limit_part; class query_insert_part; +class query_into_part; class query_values_part; class query_update_part; +class query_set_part; class query_delete_part; class query_create_part; +class query_create_table_part; class query_drop_part; +class query_drop_table_part; class query_part_visitor { @@ -33,16 +39,23 @@ public: 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_offset_part &offset_part) = 0; + virtual void visit(query_limit_part &limit_part) = 0; virtual void visit(query_insert_part &insert_part) = 0; + virtual void visit(query_into_part &into_part) = 0; virtual void visit(query_values_part &values_part) = 0; virtual void visit(query_update_part &update_part) = 0; + virtual void visit(query_set_part &set_part) = 0; virtual void visit(query_delete_part &delete_part) = 0; virtual void visit(query_create_part &create_part) = 0; + virtual void visit(query_create_table_part &create_table_part) = 0; + virtual void visit(query_drop_part &drop_part) = 0; + virtual void visit(query_drop_table_part &drop_table_part) = 0; }; } diff --git a/include/matador/sql/query_parts.hpp b/include/matador/sql/query_parts.hpp index e42aca0..154b926 100644 --- a/include/matador/sql/query_parts.hpp +++ b/include/matador/sql/query_parts.hpp @@ -6,6 +6,7 @@ #include "matador/sql/column.hpp" #include "matador/sql/column_definition.hpp" #include "matador/sql/dialect.hpp" +#include "matador/sql/key_value_pair.hpp" #include "matador/sql/table.hpp" #include @@ -98,7 +99,7 @@ public: : query_part(dialect::token_t::WHERE) , condition_(new Condition(cond)) {} - const basic_condition& condition() const; + [[nodiscard]] const basic_condition& condition() const; private: void accept(query_part_visitor &visitor) override; @@ -116,13 +117,18 @@ protected: std::string table_name_; }; -class query_group_by_part : public query_table_name_part +class query_group_by_part : public query_part { public: - explicit query_group_by_part(const std::string &table_name); + explicit query_group_by_part(sql::column col); + + [[nodiscard]] const sql::column& column() const; private: void accept(query_part_visitor &visitor) override; + +private: + sql::column column_; }; class query_order_by_part : public query_part @@ -130,7 +136,7 @@ class query_order_by_part : public query_part public: explicit query_order_by_part(sql::column col); - const sql::column& column() const; + [[nodiscard]] const sql::column& column() const; private: void accept(query_part_visitor &visitor) override; @@ -157,6 +163,34 @@ private: void accept(query_part_visitor &visitor) override; }; +class query_offset_part : public query_part +{ +public: + explicit query_offset_part(size_t offset); + + size_t offset() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + size_t offset_; +}; + +class query_limit_part : public query_part +{ +public: + explicit query_limit_part(size_t limit); + + size_t limit() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + size_t limit_; +}; + class query_insert_part : public query_part { public: @@ -166,13 +200,30 @@ private: void accept(query_part_visitor &visitor) override; }; +class query_into_part : public query_part +{ +public: + query_into_part(sql::table t, std::vector columns); + + [[nodiscard]] const sql::table& table() const; + [[nodiscard]] const std::vector& columns() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + sql::table table_; + std::vector columns_; +}; /** * Represents the SQL VALUES part */ class query_values_part : public query_part { public: - query_values_part(std::initializer_list values); + query_values_part(std::vector values); + + [[nodiscard]] const std::vector& values() const; private: void accept(query_part_visitor &visitor) override; @@ -181,13 +232,32 @@ private: std::vector values_; }; -class query_update_part : public query_table_name_part +class query_update_part : public query_part { public: - explicit query_update_part(const std::string &table_name); + explicit query_update_part(sql::table table); + + [[nodiscard]] const sql::table& table() const; private: void accept(query_part_visitor &visitor) override; + +private: + sql::table table_; +}; + +class query_set_part : public query_part +{ +public: + explicit query_set_part(const std::vector& key_value_pairs); + + [[nodiscard]] const std::vector& key_values() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + std::vector key_value_pairs_; }; class query_delete_part : public query_part @@ -208,6 +278,22 @@ private: void accept(query_part_visitor &visitor) override; }; +class query_create_table_part : public query_part +{ +public: + query_create_table_part(sql::table table, std::vector columns); + + [[nodiscard]] const sql::table& table() const; + const std::vector& columns() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + sql::table table_; + std::vector columns_; +}; + class query_drop_part : public query_part { public: @@ -217,5 +303,19 @@ private: void accept(query_part_visitor &visitor) override; }; +class query_drop_table_part : public query_part +{ +public: + explicit query_drop_table_part(sql::table table); + + [[nodiscard]] const sql::table& table() const; + +private: + void accept(query_part_visitor &visitor) override; + +private: + sql::table table_; +}; + } #endif //QUERY_QUERY_PARTS_HPP diff --git a/include/matador/sql/record.hpp b/include/matador/sql/record.hpp index cb2a983..3d01dc5 100644 --- a/include/matador/sql/record.hpp +++ b/include/matador/sql/record.hpp @@ -10,6 +10,8 @@ namespace matador::sql { +struct column; + class record { private: @@ -50,7 +52,8 @@ public: [[nodiscard]] const std::vector& columns() const; - [[nodiscard]] const column_definition& at(const std::string &name) const; + [[nodiscard]] const column_definition& at(const column &col) 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); diff --git a/include/matador/sql/schema.hpp b/include/matador/sql/schema.hpp index 4f39d4e..2780c66 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; + explicit schema(std::string name); + [[nodiscard]] std::string name() const; template diff --git a/include/matador/sql/session.hpp b/include/matador/sql/session.hpp index af03b61..09ef79a 100644 --- a/include/matador/sql/session.hpp +++ b/include/matador/sql/session.hpp @@ -56,25 +56,25 @@ private: connection_pool &pool_; const class dialect &dialect_; - schema schema_; + std::shared_ptr schema_; mutable std::unordered_map prototypes_; }; template void session::attach(const std::string &table_name) { - schema_.attach(table_name); + schema_->attach(table_name); } template entity session::insert(Type *obj) { auto c = pool_.acquire(); - auto info = schema_.info(); + auto info = schema_->info(); if (!info) { return {}; } - c->query().insert().into(info->name).values(*obj).execute(); + c->query(schema_).insert().into(info->name).values(*obj).execute(); return entity{obj}; } @@ -82,7 +82,7 @@ entity session::insert(Type *obj) template void session::drop_table() { - auto info = schema_.info(); + auto info = schema_->info(); if (info) { return drop_table(info.name); } diff --git a/src/sql/column_definition.cpp b/src/sql/column_definition.cpp index 1e2bd27..fdc6862 100644 --- a/src/sql/column_definition.cpp +++ b/src/sql/column_definition.cpp @@ -1,5 +1,6 @@ #include "matador/sql/column_definition.hpp" +#include #include namespace matador::sql { @@ -74,6 +75,12 @@ std::string column_definition::str() const return visitor.result; } +std::ostream& operator<<(std::ostream &out, const column_definition &col) +{ + out << col.str(); + return out; +} + 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}; diff --git a/src/sql/condition.cpp b/src/sql/condition.cpp index bb5ca7f..44a8991 100644 --- a/src/sql/condition.cpp +++ b/src/sql/condition.cpp @@ -9,7 +9,7 @@ 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); + return d.prepare_identifier(field_) + " " + operand + " " + d.next_placeholder(query.bind_vars); } condition::condition(column col, basic_condition::operand_t op, query_context &q) @@ -18,7 +18,7 @@ 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_) + " " + operand + " ("); result += (")"); return result; } diff --git a/src/sql/connection.cpp b/src/sql/connection.cpp index ca00dd2..7ebbf64 100644 --- a/src/sql/connection.cpp +++ b/src/sql/connection.cpp @@ -8,17 +8,16 @@ namespace matador::sql { -connection::connection(connection_info info, const std::shared_ptr &repo) +connection::connection(connection_info info) : connection_info_(std::move(info)) , logger_(stdout, "SQL") , dialect_(backend_provider::instance().connection_dialect(connection_info_.type)) -, schema_(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_info::parse(dns), repo) +connection::connection(const std::string& dns) +: connection(connection_info::parse(dns)) {} connection::connection(const connection &x) @@ -90,9 +89,9 @@ size_t connection::execute(const std::string &sql) const return connection_->execute(sql); } -sql::query connection::query() const +sql::query connection::query(const std::shared_ptr &schema) const { - return sql::query(*const_cast(this)); + return sql::query(*const_cast(this), schema); } query_result connection::fetch(const query_context &q) const @@ -135,9 +134,4 @@ const class dialect &connection::dialect() const return dialect_; } -std::shared_ptr connection::schema() const -{ - return schema_; -} - } diff --git a/src/sql/key_value_pair.cpp b/src/sql/key_value_pair.cpp index d908998..22e53f8 100644 --- a/src/sql/key_value_pair.cpp +++ b/src/sql/key_value_pair.cpp @@ -1,8 +1,16 @@ +#include + #include "matador/sql/key_value_pair.hpp" namespace matador::sql { -key_value_pair::key_value_pair(const std::string &name, any_type value) -: name_(name) + +key_value_pair::key_value_pair(std::string name, any_type value) +: name_(std::move(name)) +, value_(std::move(value)) { +} + +key_value_pair::key_value_pair(const column &col, any_type value) +: name_(col.name) , value_(std::move(value)) { } diff --git a/src/sql/query.cpp b/src/sql/query.cpp index d95ffc9..5170374 100644 --- a/src/sql/query.cpp +++ b/src/sql/query.cpp @@ -3,43 +3,39 @@ namespace matador::sql { -query::query(connection &c) -: connection_(c) +query::query(connection &db, const std::shared_ptr &schema) +: connection_(db) +, schema_(schema) {} query_create_intermediate query::create() { - return query_create_intermediate(connection_); + return query_create_intermediate(connection_, schema_); } query_drop_intermediate query::drop() { - return query_drop_intermediate{connection_}; + return query_drop_intermediate{connection_, schema_}; } query_select_intermediate query::select(std::initializer_list columns) { - return {connection_, columns}; + return {connection_, schema_, columns}; } query_insert_intermediate query::insert() { - return query_insert_intermediate{connection_}; + return query_insert_intermediate{connection_, schema_}; } -query_update_intermediate query::update(const std::string &table) +query_update_intermediate query::update(const sql::table &table) { - return query_update_intermediate{connection_, table}; + return query_update_intermediate{connection_, schema_, table}; } query_delete_intermediate query::remove() { - return query_delete_intermediate{connection_}; -} - -const sql::schema& query::schema() const -{ - return *connection_.schema(); + return query_delete_intermediate{connection_, schema_}; } } \ No newline at end of file diff --git a/src/sql/query_builder.cpp b/src/sql/query_builder.cpp index f3786d9..fbdf79e 100644 --- a/src/sql/query_builder.cpp +++ b/src/sql/query_builder.cpp @@ -206,7 +206,7 @@ struct column_context std::vector foreign_contexts; }; -std::string build_create_column(const column_definition &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) { @@ -219,18 +219,18 @@ query_builder &query_builder::table(const std::string &table, const std::vector< column_context context; - if (columns.size() < 2) { - for (const auto &col: columns) { - result.append(build_create_column(col, dialect_, context)); - } - } else { - auto it = columns.begin(); - result.append(build_create_column(*it++, dialect_, context)); - for (; it != columns.end(); ++it) { - result.append(", "); - result.append(build_create_column(*it, dialect_, context)); - } - } +// if (columns.size() < 2) { +// for (const auto &col: columns) { +// result.append(build_create_column(col, dialect_, context)); +// } +// } else { +// auto it = columns.begin(); +// result.append(build_create_column(*it++, dialect_, context)); +// for (; it != columns.end(); ++it) { +// result.append(", "); +// result.append(build_create_column(*it, dialect_, context)); +// } +// } if (!context.primary_keys.empty()) { result.append(", CONSTRAINT PK_" + table + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")"); @@ -491,27 +491,27 @@ void query_builder::initialize(query_builder::command_t cmd, query_builder::stat query_parts_.clear(); } -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) { - result.append("(" + std::to_string(col.attributes().size()) + ")"); - } - if (!col.is_nullable()) { - result.append(" NOT NULL"); - } - if (is_constraint_set(col.attributes().options(), utils::constraints::UNIQUE)) { - result.append(" UNIQUE"); - } - if (is_constraint_set(col.attributes().options(), utils::constraints::PRIMARY_KEY)) { - context.primary_keys.emplace_back(col.name()); - } - if (is_constraint_set(col.attributes().options(), utils::constraints::FOREIGN_KEY)) { - context.foreign_contexts.push_back({col.name(), col.ref_table(), col.ref_column()}); - } - - return result; -} +//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) { +// result.append("(" + std::to_string(col.attributes().size()) + ")"); +// } +// if (!col.is_nullable()) { +// result.append(" NOT NULL"); +// } +// if (is_constraint_set(col.attributes().options(), utils::constraints::UNIQUE)) { +// result.append(" UNIQUE"); +// } +// if (is_constraint_set(col.attributes().options(), utils::constraints::PRIMARY_KEY)) { +// context.primary_keys.emplace_back(col.name()); +// } +// if (is_constraint_set(col.attributes().options(), utils::constraints::FOREIGN_KEY)) { +// context.foreign_contexts.push_back({col.name(), col.ref_table(), col.ref_column()}); +// } +// +// return result; +//} column alias(const std::string &column, const std::string &as) { diff --git a/src/sql/query_compiler.cpp b/src/sql/query_compiler.cpp index c7a7f80..be6b5bc 100644 --- a/src/sql/query_compiler.cpp +++ b/src/sql/query_compiler.cpp @@ -2,11 +2,14 @@ #include "matador/sql/query_data.hpp" #include "matador/sql/column_definition.hpp" #include "matador/sql/dialect.hpp" +#include "matador/sql/query_builder.hpp" + +#include "matador/utils/string.hpp" namespace matador::sql { query_compiler::query_compiler(const sql::dialect &d) - : dialect_(d) +: dialect_(d) {} query_context query_compiler::compile(const query_data *data) @@ -50,6 +53,7 @@ void query_compiler::visit(query_select_part &select_part) void query_compiler::visit(query_from_part &from_part) { + query_.table_name = from_part.table().name; if (dialect_.default_schema_name().empty()) { query_.sql += " " + dialect_.token_at(dialect::token_t::FROM) + " " + dialect_.prepare_identifier(from_part.table().name) + @@ -85,7 +89,7 @@ void query_compiler::visit(query_where_part &where_part) void query_compiler::visit(query_group_by_part &group_by_part) { - + query_.sql += " " + dialect_.token_at(dialect::token_t::GROUP_BY) + " " + dialect_.prepare_identifier(group_by_part.column()); } void query_compiler::visit(query_order_by_part &order_by_part) @@ -96,27 +100,85 @@ void query_compiler::visit(query_order_by_part &order_by_part) void query_compiler::visit(query_order_by_asc_part &order_by_asc_part) { - + query_.sql += " " + dialect_.token_at(dialect::token_t::ASC); } void query_compiler::visit(query_order_by_desc_part &order_by_desc_part) { + query_.sql += " " + dialect_.token_at(dialect::token_t::DESC); +} +void query_compiler::visit(query_offset_part &offset_part) +{ + query_.sql += " " + dialect_.token_at(dialect::token_t::OFFSET) + " " + std::to_string(offset_part.offset()); +} + +void query_compiler::visit(query_limit_part &limit_part) +{ + query_.sql += " " + dialect_.token_at(dialect::token_t::LIMIT) + " " + std::to_string(limit_part.limit()); } void query_compiler::visit(query_insert_part &insert_part) { + query_.sql = dialect_.token_at(dialect::token_t::INSERT); +} +void query_compiler::visit(query_into_part &into_part) +{ + query_.table_name = into_part.table().name; + query_.sql += " " + dialect_.token_at(dialect::token_t::INTO) + + " " + dialect_.prepare_identifier(into_part.table().name); + + std::string result{"("}; + if (into_part.columns().size() < 2) { + for (const auto &col: into_part.columns()) { + result.append(dialect_.prepare_identifier(col.name)); + } + } else { + auto it = into_part.columns().begin(); + result.append(dialect_.prepare_identifier((it++)->name)); + for (; it != into_part.columns().end(); ++it) { + result.append(", "); + result.append(dialect_.prepare_identifier(it->name)); + } + } + result += (")"); + query_.sql += " " + result; } void query_compiler::visit(query_values_part &values_part) { + query_.sql += " " + dialect_.token_at(dialect::token_t::VALUES); + detail::any_type_to_string_visitor value_to_string(dialect_, query_); + + std::string result{"("}; + if (values_part.values().size() < 2) { + for (auto val: values_part.values()) { + std::visit(value_to_string, val); + result.append(value_to_string.result); + } + } else { + auto it = values_part.values().begin(); + auto val = *it++; + std::visit(value_to_string, val); + result.append(value_to_string.result); + for (; it != values_part.values().end(); ++it) { + result.append(", "); + val = *it; + std::visit(value_to_string, val); + result.append(value_to_string.result); + } + } + result += (")"); + + query_.sql += " " + result; } void query_compiler::visit(query_update_part &update_part) { - + query_.table_name = update_part.table().name; + query_.sql = dialect_.token_at(dialect::token_t::UPDATE) + " " + dialect_.prepare_identifier(update_part.table().name); } void query_compiler::visit(query_delete_part &delete_part) @@ -126,12 +188,122 @@ void query_compiler::visit(query_delete_part &delete_part) void query_compiler::visit(query_create_part &create_part) { + query_.sql = dialect_.token_at(dialect::token_t::CREATE); +} +struct fk_context +{ + std::string column; + std::string ref_table; + std::string ref_column; +}; + +struct column_context +{ + std::vector primary_keys; + std::vector foreign_contexts; +}; + + std::string build_create_column(const column_definition &col, const dialect &d, column_context &context); + +void query_compiler::visit(query_create_table_part &create_table_part) +{ + query_.sql += " " + dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(create_table_part.table().name) + " "; + query_.table_name = create_table_part.table().name; + + std::string result = "("; + + column_context context; + + if (create_table_part.columns().size() < 2) { + for (const auto &col: create_table_part.columns()) { + result.append(build_create_column(col, dialect_, context)); + } + } else { + auto it = create_table_part.columns().begin(); + result.append(build_create_column(*it++, dialect_, context)); + for (; it != create_table_part.columns().end(); ++it) { + result.append(", "); + result.append(build_create_column(*it, dialect_, context)); + } + } + + if (!context.primary_keys.empty()) { + result.append(", CONSTRAINT PK_" + create_table_part.table().name + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")"); + } + for (const auto &fk: context.foreign_contexts) { + result += ", CONSTRAINT FK_" + create_table_part.table().name; + result += "_" + fk.column; + result += " FOREIGN KEY (" + fk.column + ")"; + result += " REFERENCES " + fk.ref_table + "(" + fk.ref_column + ")"; + } + + result += ")"; + query_.sql += result; } void query_compiler::visit(query_drop_part &drop_part) { + query_.sql = dialect_.token_at(dialect::token_t::DROP); +} +void query_compiler::visit(query_set_part &set_part) +{ + query_.sql += " " + dialect_.token_at(dialect::token_t::SET) + " "; + + detail::any_type_to_string_visitor value_to_string(dialect_, query_); + std::string result; + if (set_part.key_values().size() < 2) { + for (const auto &col: set_part.key_values()) { + result.append(dialect_.prepare_identifier(col.name()) + "="); + auto var = col.value(); + std::visit(value_to_string, var); + result.append(value_to_string.result); + } + } else { + auto it = set_part.key_values().begin(); + result.append(dialect_.prepare_identifier(it->name()) + "="); + auto var = (it++)->value(); + std::visit(value_to_string, var); + result.append(value_to_string.result); + for (; it != set_part.key_values().end(); ++it) { + result.append(", "); + result.append(dialect_.prepare_identifier((*it).name()) + "="); + var = it->value(); + std::visit(value_to_string, var); + result.append(value_to_string.result); + } + } + + query_.sql += result; +} + +void query_compiler::visit(query_drop_table_part &drop_table_part) +{ + query_.sql += " " + dialect_.token_at(dialect::token_t::TABLE) + " " + dialect_.prepare_identifier(drop_table_part.table().name); + query_.table_name = drop_table_part.table().name; +} + +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) { + result.append("(" + std::to_string(col.attributes().size()) + ")"); + } + if (!col.is_nullable()) { + result.append(" NOT NULL"); + } + if (is_constraint_set(col.attributes().options(), utils::constraints::UNIQUE)) { + result.append(" UNIQUE"); + } + if (is_constraint_set(col.attributes().options(), utils::constraints::PRIMARY_KEY)) { + context.primary_keys.emplace_back(col.name()); + } + if (is_constraint_set(col.attributes().options(), utils::constraints::FOREIGN_KEY)) { + context.foreign_contexts.push_back({col.name(), col.ref_table(), col.ref_column()}); + } + + return result; } } \ No newline at end of file diff --git a/src/sql/query_intermediates.cpp b/src/sql/query_intermediates.cpp index 751acc7..04b7827 100644 --- a/src/sql/query_intermediates.cpp +++ b/src/sql/query_intermediates.cpp @@ -4,13 +4,9 @@ #include "matador/sql/condition.hpp" namespace matador::sql { -basic_query_intermediate::basic_query_intermediate(connection &db) -: connection_(db) {} - -std::shared_ptr basic_query_intermediate::tables() const -{ - return connection_.schema(); -} +basic_query_intermediate::basic_query_intermediate(connection &db, const std::shared_ptr & schema) +: connection_(db) +, schema_(schema) {} query_result query_select_finish::fetch_all() { @@ -42,100 +38,95 @@ statement query_select_finish::prepare() return connection_.prepare(compiler.compile(&data_)); } -query_intermediate::query_intermediate(connection &db, query_data &data) -: basic_query_intermediate(db), data_(data) {} +query_intermediate::query_intermediate(connection &db, const std::shared_ptr &schema, query_data &data) +: basic_query_intermediate(db, schema), data_(data) {} query_offset_intermediate query_order_direction_intermediate::offset(size_t offset) { - return {connection_, data_}; + data_.parts.push_back(std::make_unique(offset)); + return {connection_, schema_, data_}; } query_limit_intermediate query_offset_intermediate::limit(size_t limit) { - return {connection_, data_}; + data_.parts.push_back(std::make_unique(limit)); + return {connection_, schema_, data_}; } query_limit_intermediate query_order_direction_intermediate::limit(size_t limit) { - return {connection_, data_}; + data_.parts.push_back(std::make_unique(limit)); + return {connection_, schema_, data_}; } -query_order_by_intermediate query_group_by_intermediate::order_by(const std::string &name) +query_order_by_intermediate query_group_by_intermediate::order_by(const column &col) { - return {connection_, data_}; -// return {connection_, builder_.order_by(name)}; + data_.parts.push_back(std::make_unique(col)); + return {connection_, schema_, data_}; } query_order_direction_intermediate query_order_by_intermediate::asc() { - return {connection_, data_}; -// return {connection_, builder_.asc()}; + data_.parts.push_back(std::make_unique()); + return {connection_, schema_, data_}; } query_order_direction_intermediate query_order_by_intermediate::desc() { - return {connection_, data_}; -// return {connection_, builder_.desc()}; + data_.parts.push_back(std::make_unique()); + return {connection_, schema_, data_}; } -query_group_by_intermediate query_from_intermediate::group_by(const std::string &name) +query_group_by_intermediate query_from_intermediate::group_by(const column &col) { - return {connection_, data_}; -// return {connection_, builder_.group_by(name)}; + data_.parts.push_back(std::make_unique(col)); + return {connection_, schema_, data_}; } -query_order_by_intermediate query_from_intermediate::order_by(const std::string &name) +query_order_by_intermediate query_from_intermediate::order_by(const column &col) { - return {connection_, data_}; -// return {connection_, builder_.order_by(name)}; + data_.parts.push_back(std::make_unique(col)); + return {connection_, schema_, data_}; } -query_group_by_intermediate query_where_intermediate::group_by(const std::string &name) +query_group_by_intermediate query_where_intermediate::group_by(const column &col) { - return {connection_, data_}; -// return {connection_, builder_.group_by(name)}; + data_.parts.push_back(std::make_unique(col)); + return {connection_, schema_, data_}; } query_order_by_intermediate query_where_intermediate::order_by(const column &col) { data_.parts.push_back(std::make_unique(col)); - return {connection_, data_}; -// return {connection_, builder_.order_by(name)}; + return {connection_, schema_, data_}; } -query_join_intermediate query_on_intermediate::join(const std::string &join_table_name, const std::string &as) +query_join_intermediate query_on_intermediate::join_left(const table &t) { - return {connection_, data_}; -// return {connection_, builder_.join(join_table_name, join_type_t::INNER, as)}; + data_.parts.push_back(std::make_unique(t)); + return {connection_, schema_, data_}; } -query_group_by_intermediate query_on_intermediate::group_by(const std::string &name) +query_group_by_intermediate query_on_intermediate::group_by(const column &col) { - return {connection_, data_}; -// return {connection_, builder_.group_by(name)}; + data_.parts.push_back(std::make_unique(col)); + return {connection_, schema_, data_}; } query_order_by_intermediate query_on_intermediate::order_by(const column &col) { data_.parts.push_back(std::make_unique(col)); - return {connection_, data_}; -// return {connection_, builder_.order_by(name)}; + return {connection_, schema_, data_}; } query_join_intermediate query_from_intermediate::join_left(const table &t) { data_.parts.push_back(std::make_unique(t)); - return {connection_, data_}; + return {connection_, schema_, data_}; } -query_where_intermediate query_from_intermediate::where(const basic_condition &cond) -{ - return query_where_intermediate{connection_, data_}; -// return query_where_intermediate{connection_, builder_.where(cond)}; -} - -query_select_intermediate::query_select_intermediate(connection &db, const std::vector& columns) -: query_start_intermediate(db) +query_select_intermediate::query_select_intermediate(connection &db, const std::shared_ptr &schema, const std::vector& columns) +: query_start_intermediate(db, schema) { data_.parts.push_back(std::make_unique(columns)); } @@ -143,20 +134,19 @@ query_select_intermediate::query_select_intermediate(connection &db, const std:: query_from_intermediate query_select_intermediate::from(const table& t) { data_.parts.push_back(std::make_unique(t)); - return {connection_, data_}; -// return {connection_, builder_.from(table, as)}; + return {connection_, schema_, data_}; } -query_insert_intermediate::query_insert_intermediate(connection &s) -: query_start_intermediate(s) +query_insert_intermediate::query_insert_intermediate(connection &db, const std::shared_ptr &schema) +: query_start_intermediate(db, schema) { 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 sql::table &table, std::initializer_list column_names) { - return {connection_, data_}; -// return {connection_, builder_.into(table, column_names)}; + data_.parts.push_back(std::make_unique(table, column_names)); + return {connection_, schema_, data_}; } size_t query_execute_finish::execute() @@ -171,6 +161,12 @@ statement query_execute_finish::prepare() return connection_.prepare(compiler.compile(&data_)); } +std::string query_execute_finish::str() const +{ + query_compiler compiler(connection_.dialect()); + return compiler.compile(&data_).sql; +} + query_execute_finish query_into_intermediate::values(std::initializer_list values) { return this->values(std::vector(values)); @@ -178,80 +174,68 @@ query_execute_finish query_into_intermediate::values(std::initializer_list &values) { - return {connection_, data_}; + data_.parts.push_back(std::make_unique(values)); + return {connection_, schema_, data_}; } -query_create_intermediate::query_create_intermediate(connection &db) -: query_start_intermediate(db) { +query_create_intermediate::query_create_intermediate(connection &db, const std::shared_ptr &schema) +: query_start_intermediate(db, schema) { 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 sql::table &table, std::initializer_list columns) { - return table(table_name, std::vector{columns}); + return this->table(table, 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 sql::table &table, const std::vector &columns) { - return {connection_, data_}; -// return {connection_, builder_.table(table_name, columns)}; + data_.parts.push_back(std::make_unique(table, columns)); + return {connection_, schema_, data_}; } -query_drop_intermediate::query_drop_intermediate(connection &s) -: query_start_intermediate(s) +query_drop_intermediate::query_drop_intermediate(connection &db, const std::shared_ptr &schema) +: query_start_intermediate(db, schema) { data_.parts.push_back(std::make_unique()); } -query_execute_finish query_drop_intermediate::table(const std::string &table) +query_execute_finish query_drop_intermediate::table(const sql::table &table) { - return {connection_, data_}; -// return {connection_, builder_.table(table)}; + data_.parts.push_back(std::make_unique(table)); + return {connection_, schema_, data_}; } query_execute_finish query_execute_where_intermediate::limit(int limit) { - return {connection_, data_}; + return {connection_, schema_, data_}; // return {connection_, builder_.limit(limit)}; } -query_execute_where_intermediate query_set_intermediate::where(const basic_condition &cond) +query_update_intermediate::query_update_intermediate(connection &db, const std::shared_ptr &schema, const sql::table& table) +: query_start_intermediate(db, schema) { - 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) -{ - data_.parts.push_back(std::make_unique(table_name)); + data_.parts.push_back(std::make_unique(table)); } query_set_intermediate query_update_intermediate::set(std::initializer_list columns) { - return {connection_, data_}; -// return {connection_, builder_.set(columns)}; + data_.parts.push_back(std::make_unique(columns)); + return {connection_, schema_, data_}; } -query_execute_where_intermediate query_delete_from_intermediate::where(const basic_condition &cond) -{ - return {connection_, data_}; -// return {connection_, builder_.where(cond)}; -} - -query_delete_intermediate::query_delete_intermediate(connection &s) -: query_start_intermediate(s) +query_delete_intermediate::query_delete_intermediate(connection &db, const std::shared_ptr &schema) +: query_start_intermediate(db, schema) { data_.parts.push_back(std::make_unique()); } -query_delete_from_intermediate query_delete_intermediate::from(const std::string &table) +query_delete_from_intermediate query_delete_intermediate::from(const sql::table &table) { - return {connection_, data_}; -// return {connection_, builder_.from(table)}; + return {connection_, schema_, data_}; } -query_start_intermediate::query_start_intermediate(connection &db) -: basic_query_intermediate(db) +query_start_intermediate::query_start_intermediate(connection &db, const std::shared_ptr &schema) +: basic_query_intermediate(db, schema) {} } \ No newline at end of file diff --git a/src/sql/query_parts.cpp b/src/sql/query_parts.cpp index 6549260..dff05a8 100644 --- a/src/sql/query_parts.cpp +++ b/src/sql/query_parts.cpp @@ -74,10 +74,16 @@ query_table_name_part::query_table_name_part(sql::dialect::token_t token, std::s : 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) +query_group_by_part::query_group_by_part(sql::column col) +: query_part(dialect::token_t::GROUP_BY) +, column_(std::move(col)) {} +const sql::column &query_group_by_part::column() const +{ + return column_; +} + void query_group_by_part::accept(query_part_visitor &visitor) { visitor.visit(*this); @@ -108,7 +114,7 @@ void query_order_by_asc_part::accept(query_part_visitor &visitor) } query_order_by_desc_part::query_order_by_desc_part() - : query_part(dialect::token_t::DESC) +: query_part(dialect::token_t::DESC) {} void query_order_by_desc_part::accept(query_part_visitor &visitor) @@ -116,6 +122,34 @@ void query_order_by_desc_part::accept(query_part_visitor &visitor) visitor.visit(*this); } +query_offset_part::query_offset_part(size_t offset) +: query_part(dialect::token_t::OFFSET) +, offset_(offset) {} + +size_t query_offset_part::offset() const +{ + return offset_; +} + +void query_offset_part::accept(query_part_visitor &visitor) +{ + visitor.visit(*this); +} + +query_limit_part::query_limit_part(size_t limit) +: query_part(dialect::token_t::LIMIT) +, limit_(limit) {} + +size_t query_limit_part::limit() const +{ + return limit_; +} + +void query_limit_part::accept(query_part_visitor &visitor) +{ + visitor.visit(*this); +} + query_insert_part::query_insert_part() : query_part(dialect::token_t::INSERT) {} @@ -124,23 +158,68 @@ void query_insert_part::accept(query_part_visitor &visitor) visitor.visit(*this); } -query_values_part::query_values_part(std::initializer_list values) +query_into_part::query_into_part(sql::table t, std::vector columns) +: query_part(dialect::token_t::INSERT) +, table_(std::move(t)) +, columns_(std::move(columns)) {} + +const sql::table &query_into_part::table() const +{ + return table_; +} + +const std::vector &query_into_part::columns() const +{ + return columns_; +} + +void query_into_part::accept(query_part_visitor &visitor) +{ + visitor.visit(*this); +} + +query_values_part::query_values_part(std::vector values) : query_part(sql::dialect::token_t::VALUES) -, values_(values) {} +, values_(std::move(values)) {} + +const std::vector& query_values_part::values() const +{ + return 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) {} +query_update_part::query_update_part(sql::table table) +: query_part(dialect::token_t::UPDATE) +, table_(std::move(table)) {} + +const sql::table& query_update_part::table() const +{ + return table_; +} void query_update_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } +query_set_part::query_set_part(const std::vector& key_value_pairs) +: query_part(sql::dialect::token_t::SET) +, key_value_pairs_(key_value_pairs) {} + +const std::vector &query_set_part::key_values() const +{ + return key_value_pairs_; +} + +void query_set_part::accept(query_part_visitor &visitor) +{ + visitor.visit(*this); +} + query_delete_part::query_delete_part() : query_part(sql::dialect::token_t::REMOVE) {} @@ -157,6 +236,26 @@ void query_create_part::accept(query_part_visitor &visitor) visitor.visit(*this); } +query_create_table_part::query_create_table_part(sql::table table, std::vector columns) +: query_part(sql::dialect::token_t::TABLE) +, table_(std::move(table)) +, columns_(std::move(columns)) {} + +const sql::table &query_create_table_part::table() const +{ + return table_; +} + +const std::vector &query_create_table_part::columns() const +{ + return columns_; +} + +void query_create_table_part::accept(query_part_visitor &visitor) +{ + visitor.visit(*this); +} + query_drop_part::query_drop_part() : query_part(sql::dialect::token_t::DROP) {} @@ -165,4 +264,18 @@ void query_drop_part::accept(query_part_visitor &visitor) visitor.visit(*this); } +query_drop_table_part::query_drop_table_part(sql::table table) +: query_part(sql::dialect::token_t::TABLE) +, table_(std::move(table)) {} + +const sql::table &query_drop_table_part::table() const +{ + return table_; +} + +void query_drop_table_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 fada43a..5954cca 100644 --- a/src/sql/record.cpp +++ b/src/sql/record.cpp @@ -1,4 +1,5 @@ #include "matador/sql/record.hpp" +#include "matador/sql/column.hpp" #include #include @@ -60,12 +61,18 @@ const column_definition &record::primary_key() const return columns_[pk_index_]; } -const column_definition &record::at(const std::string &name) const +const column_definition &record::at(const column &col) const { - auto ref = columns_by_name_.at(name).first; - return columns_by_name_.at(name).first; + auto ref = columns_by_name_.at(col.name).first; + return columns_by_name_.at(col.name).first; } +//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_definition &record::at(size_t index) const { return columns_.at(index); diff --git a/src/sql/schema.cpp b/src/sql/schema.cpp index 9afcddd..eaa3d61 100644 --- a/src/sql/schema.cpp +++ b/src/sql/schema.cpp @@ -7,14 +7,17 @@ namespace matador::sql { void table_info::create(connection &conn) const { - conn.query().create().table(name, prototype.columns()).execute(); +// conn.query().create().table(name, prototype.columns()).execute(); } void table_info::drop(connection &conn) const { - conn.query().drop().table(name).execute(); +// conn.query().drop().table(name).execute(); } +schema::schema(std::string name) +: name_(std::move(name)) {} + std::string schema::name() const { return name_; diff --git a/src/sql/session.cpp b/src/sql/session.cpp index a598e42..eb5be91 100644 --- a/src/sql/session.cpp +++ b/src/sql/session.cpp @@ -8,12 +8,13 @@ namespace matador::sql { session::session(connection_pool &pool) : pool_(pool) -, dialect_(backend_provider::instance().connection_dialect(pool_.info().type)) {} +, dialect_(backend_provider::instance().connection_dialect(pool_.info().type)) +, schema_(std::make_shared(dialect_.default_schema_name())){} void session::create_schema() { auto c = pool_.acquire(); - for (const auto &t : schema_) { + for (const auto &t : *schema_) { t.second.create(*c); } } @@ -25,7 +26,7 @@ void session::drop_table(const std::string &table_name) throw std::logic_error("no database connection available"); } - c->query().drop().table(table_name).execute(); + c->query(schema_).drop().table(table_name).execute(); } query_result session::fetch(const query_context &q) const @@ -90,7 +91,7 @@ bool session::table_exists(const std::string &table_name) const const schema& session::tables() const { - return schema_; + return *schema_; } const class dialect &session::dialect() const diff --git a/test/ColumnGeneratorTest.cpp b/test/ColumnGeneratorTest.cpp index dff98f9..b5c7570 100644 --- a/test/ColumnGeneratorTest.cpp +++ b/test/ColumnGeneratorTest.cpp @@ -10,7 +10,7 @@ using namespace matador::sql; using namespace matador::utils; TEST_CASE("Generate columns from object", "[column generator]") { - schema repo; + schema repo("main"); auto columns = column_generator::generate(repo); @@ -36,7 +36,7 @@ TEST_CASE("Generate columns from object", "[column generator]") { } TEST_CASE("Generate columns from object with nullable columns", "[column generator]") { - schema repo; + schema repo("main"); auto columns = column_generator::generate(repo); diff --git a/test/ColumnNameGeneratorTest.cpp b/test/ColumnNameGeneratorTest.cpp index a3c0950..c1a3c8e 100644 --- a/test/ColumnNameGeneratorTest.cpp +++ b/test/ColumnNameGeneratorTest.cpp @@ -9,7 +9,7 @@ using namespace matador::sql; TEST_CASE("Generate column names from object", "[column name generator]") { - schema s; + schema s("main"); s.attach("product"); auto columns = column_name_generator::generate(s); @@ -34,7 +34,7 @@ TEST_CASE("Generate column names from object", "[column name generator]") { } TEST_CASE("Generate column names for object with has many relation", "[column][relation]") { - schema s; + schema s("main"); s.attach("product"); s.attach("order_details"); s.attach("order");