From 930b9d1aa41e19d269a384cefe13bdb605338082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Thu, 8 Jan 2026 15:14:31 +0100 Subject: [PATCH] added timestamp code, support columns for group by and order by and tested load has-many eager code --- .../postgres/src/postgres_result_reader.cpp | 14 +- backends/postgres/test/CMakeLists.txt | 2 + demo/main.cpp | 455 +++++++++--------- include/matador/object/attribute.hpp | 1 + include/matador/object/collection.hpp | 6 +- .../query_create_intermediate.hpp | 3 +- .../query_execute_where_intermediate.hpp | 1 + .../intermediates/query_from_intermediate.hpp | 9 +- .../query_group_by_intermediate.hpp | 1 + .../query_where_intermediate.hpp | 4 +- .../matador/query/internal/query_parts.hpp | 12 +- include/matador/query/meta_table_macro.hpp | 2 +- include/matador/query/query.hpp | 1 - include/matador/utils/access.hpp | 4 - include/matador/utils/identifier.hpp | 1 + include/matador/utils/value.hpp | 13 +- source/core/object/attribute.cpp | 4 + source/core/utils/identifier.cpp | 76 ++- source/core/utils/value.cpp | 4 + .../query_create_intermediate.cpp | 9 + .../query_execute_where_intermediate.cpp | 7 +- .../intermediates/query_from_intermediate.cpp | 14 +- .../query_group_by_intermediate.cpp | 9 +- .../query_where_intermediate.cpp | 14 +- source/orm/query/internal/query_parts.cpp | 343 +++++++------ source/orm/query/query.cpp | 7 - source/orm/query/query_compiler.cpp | 29 +- test/backends/QueryRecordTest.cpp | 3 +- test/backends/QueryTest.cpp | 108 +++++ test/models/shipment.hpp | 43 ++ test/orm/backend/test_result_reader.cpp | 2 +- test/utils/record_printer.cpp | 72 +++ test/utils/record_printer.hpp | 43 ++ todo.md | 383 +-------------- 34 files changed, 853 insertions(+), 846 deletions(-) create mode 100644 test/models/shipment.hpp create mode 100644 test/utils/record_printer.cpp create mode 100644 test/utils/record_printer.hpp diff --git a/backends/postgres/src/postgres_result_reader.cpp b/backends/postgres/src/postgres_result_reader.cpp index 68dab4b..59777e6 100644 --- a/backends/postgres/src/postgres_result_reader.cpp +++ b/backends/postgres/src/postgres_result_reader.cpp @@ -2,6 +2,7 @@ #include "matador/utils/convert.hpp" #include "matador/utils/value.hpp" +#include "matador/utils/string.hpp" namespace matador::backends::postgres { postgres_result_reader::postgres_result_reader(PGresult *result) @@ -104,18 +105,25 @@ void postgres_result_reader::read_value(const char * /*id*/, const size_t index, void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::date_type_t &value) { if (const auto val = column(index); strlen(val) > 0) { - // value = time::parse(val, "%Y-%m-%d %T.%f"); + if (const auto res = utils::to(std::string(val)); res.is_ok()) { + value = res.value(); + } } } void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::time_type_t &value) { if (const auto val = column(index); strlen(val) > 0) { - // value.set(val, matador::utils::date_format::ISO8601); + if (const auto res = utils::to(std::string(val)); res.is_ok()) { + value = res.value(); + } } } -void postgres_result_reader::read_value(const char * /*id*/, size_t index, utils::timestamp_type_t &value) { +void postgres_result_reader::read_value(const char * /*id*/, const size_t index, utils::timestamp_type_t &value) { if (const auto val = column(index); strlen(val) > 0) { + if (const auto res = utils::to(std::string(val)); res.is_ok()) { + value = res.value(); + } } } diff --git a/backends/postgres/test/CMakeLists.txt b/backends/postgres/test/CMakeLists.txt index d7e535e..e5cef92 100644 --- a/backends/postgres/test/CMakeLists.txt +++ b/backends/postgres/test/CMakeLists.txt @@ -31,6 +31,8 @@ set(TEST_SOURCES ../../../test/backends/StatementCacheTest.cpp ../../../test/backends/StatementTest.cpp ../../../test/backends/TypeTraitsTest.cpp + ../../../test/utils/record_printer.hpp + ../../../test/utils/record_printer.cpp ) set(LIBRARY_TEST_TARGET PostgresTests) diff --git a/demo/main.cpp b/demo/main.cpp index 36b7a88..7c454d2 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -1,9 +1,11 @@ #include "matador/sql/connection.hpp" +#include "matador/sql/connection_pool.hpp" #include "matador/query/criteria.hpp" #include "matador/query/query.hpp" #include "matador/query/table_column.hpp" #include "matador/query/meta_table_macro.hpp" +#include "matador/query/schema.hpp" #include "matador/object/object_ptr.hpp" #include "matador/object/repository.hpp" @@ -15,129 +17,129 @@ #include struct author { - unsigned int id{}; - std::string first_name; - std::string last_name; - std::string date_of_birth; - unsigned short year_of_birth{}; - bool distinguished{false}; + unsigned int id{}; + std::string first_name; + std::string last_name; + std::string date_of_birth; + unsigned short year_of_birth{}; + bool distinguished{false}; - template - void process( Operator& op ) { - namespace field = matador::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 ); - } + template + void process(Operator &op) { + namespace field = matador::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 int id{}; - matador::object::object_ptr book_author; - std::string title; - unsigned short published_in{}; + unsigned int id{}; + matador::object::object_ptr book_author; + std::string title; + unsigned short published_in{}; - template - void process( Operator& op ) { - namespace field = matador::access; - field::primary_key( op, "id", id ); - field::attribute( op, "title", title, 511 ); - field::has_one( op, "author_id", book_author, matador::utils::CascadeNoneFetchLazy ); - field::attribute( op, "published_in", published_in ); - } + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::attribute(op, "title", title, 511); + field::belongs_to(op, "author_id", book_author, matador::utils::CascadeNoneFetchLazy); + field::attribute(op, "published_in", published_in); + } }; struct payload { - unsigned int id{}; + unsigned int id{}; - template - void process( Operator& op ) { - namespace field = matador::access; - field::primary_key( op, "id", id ); - } + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + } }; struct job { - enum class job_state { - Pending, - Running, - Succeeded, - Failed, - Canceled - }; + enum class job_state { + Pending, + Running, + Succeeded, + Failed, + Canceled + }; - enum class job_mode { - Foreground, - Background - }; + enum class job_mode { + Foreground, + Background + }; - unsigned int id{}; - matador::object::object_ptr data; - std::string type; - std::string description; - job_state state; - job_mode mode; + unsigned int id{}; + matador::object::object_ptr data; + std::string type; + std::string description; + job_state state; + job_mode mode; - template - void process( Operator& op ) { - namespace field = matador::access; - field::primary_key( op, "id", id ); - field::belongs_to( op, "payload", data, matador::utils::CascadeNoneFetchLazy ); - field::attribute( op, "type", type, 511 ); - field::attribute( op, "description", description, 511 ); - field::attribute( op, "state", state ); - field::attribute( op, "mode", mode ); - } + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::belongs_to(op, "payload", data, matador::utils::CascadeNoneFetchLazy); + field::attribute(op, "type", type, 511); + field::attribute(op, "description", description, 511); + field::attribute(op, "state", state); + field::attribute(op, "mode", mode); + } }; static const matador::utils::enum_mapper job_state_enum({ - {job::job_state::Pending, "Pending"}, - {job::job_state::Running, "Running"}, - {job::job_state::Succeeded, "Succeeded"}, - {job::job_state::Failed, "Failed"}, - {job::job_state::Canceled, "Canceled"} - }); + {job::job_state::Pending, "Pending"}, + {job::job_state::Running, "Running"}, + {job::job_state::Succeeded, "Succeeded"}, + {job::job_state::Failed, "Failed"}, + {job::job_state::Canceled, "Canceled"} +}); static const matador::utils::enum_mapper job_mode_enum({ - {job::job_mode::Foreground, "Foreground"}, - {job::job_mode::Background, "Background"} - }); + {job::job_mode::Foreground, "Foreground"}, + {job::job_mode::Background, "Background"} +}); template<> struct matador::utils::data_type_traits { - static basic_type type(const std::size_t size) { return data_type_traits::type(size); } + static basic_type type(const std::size_t size) { return data_type_traits::type(size); } - static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_state &value) { - std::string enum_string; - reader.read_value(id, index, enum_string, 64); - if (const auto enum_opt = job_state_enum.to_enum(enum_string)) { - value = enum_opt.value(); - } + static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_state &value) { + std::string enum_string; + reader.read_value(id, index, enum_string, 64); + if (const auto enum_opt = job_state_enum.to_enum(enum_string)) { + value = enum_opt.value(); } + } - static void write_value(attribute_writer &binder, const size_t index, const job::job_state &value) { - binder.write_value(index, job_state_enum.to_string(value)); - } + static void write_value(attribute_writer &binder, const size_t index, const job::job_state &value) { + binder.write_value(index, job_state_enum.to_string(value)); + } }; template<> struct matador::utils::data_type_traits { - static basic_type type( const std::size_t size) { return data_type_traits::type(size); } + static basic_type type(const std::size_t size) { return data_type_traits::type(size); } - static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_mode &value) { - std::string enum_string; - reader.read_value(id, index, enum_string, 64); - if (const auto enum_opt = job_mode_enum.to_enum(enum_string)) { - value = enum_opt.value(); - } + static void read_value(attribute_reader &reader, const char *id, const size_t index, job::job_mode &value) { + std::string enum_string; + reader.read_value(id, index, enum_string, 64); + if (const auto enum_opt = job_mode_enum.to_enum(enum_string)) { + value = enum_opt.value(); } + } - static void bind_value(attribute_writer &binder, const size_t index, const job::job_mode &value) { - binder.write_value(index, job_mode_enum.to_string(value)); - } + static void bind_value(attribute_writer &binder, const size_t index, const job::job_mode &value) { + binder.write_value(index, job_mode_enum.to_string(value)); + } }; META_TABLE(authors, AUTHOR, id, first_name, last_name, date_of_birth, year_of_birth, distinguished) @@ -146,144 +148,161 @@ META_TABLE(books, BOOK, id, author_id, title, published_in) META_TABLE(job, JOB, id, payload, type, description, state, mode) -META_TABLE(payload, PAYLOAD, id ) +META_TABLE(payload, PAYLOAD, id) -META_TABLE(temporary_table, TEMPORARY_TABLE, id ); +META_TABLE(temporary_table, TEMPORARY_TABLE, id); META_TABLE(customer, CUSTOMER, id, name, email, address) + META_TABLE(product, PRODUCT, id, title, description, price, category) + META_TABLE(category, CATEGORY, id, title, description) + META_TABLE(cart, CART, id, items, owner) int main() { - using namespace matador::sql; - using namespace matador::object; - using namespace matador::utils; - using namespace matador::query::meta; + using namespace matador::sql; + using namespace matador::object; + using namespace matador::utils; + using namespace matador::query; + using namespace matador::query::meta; - const std::string env_var{"MATADOR_BACKENDS_PATH"}; + const std::string env_var{"MATADOR_BACKENDS_PATH"}; - std::string dns{"sqlite://demo.db"}; - repository s( "main" ); - auto result = s.attach( "authors" ).and_then( [&s] { - return s.attach( "books" ); - } ); - // s.attach( "books" ); + connection_pool pool("postgres://test:test123!@127.0.0.1:5432/matador", 4); - connection c( dns ); - result = c.open(); - // s.create( c ); - // - // auto create_authors_sql = c.query( s ) - // .create() - // .table( qh::authors ) - // .execute(); - // - // c.query( s ) - // .create() - // .table( qh::books ) - // .execute(); - // - // std::cout << "SQL: " << create_authors_sql << "\n"; - // - // author mc; - // 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(); - // - // std::cout << "SQL: " << insert_authors_sql << "\n"; - // - // auto result = c.query( s ) - // .select( qh::authors.columns ) - // .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(); - // - // std::cout << "SQL: " << update_authors_sql << "\n"; - // - // auto authors = c.query( s ) - // .select( qh::authors.columns ) - // .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 = matador::query::query::select( BOOK, {AUTHOR.last_name} ) - .from( BOOK ) - .join_left( AUTHOR ) - .on( BOOK.author_id == AUTHOR.id ) - .where( BOOK.published_in < 2008 && AUTHOR.last_name == "King" ) - .group_by( BOOK.published_in ) - .order_by( BOOK.title ).asc() - .limit( 5 ) - .offset( 2 ) - .fetch_all(c); - - for (const auto& r: *select_books_sql) { - std::cout << "R: " << r.at( BOOK.title ) << ", " << r.at( AUTHOR.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 - // // WHERE book.published_in < 2008 AND author.name = "Michael Crichton" - // // ORDER BY "book.title" ASC - // // OFFSET 2 LIMIT 5 - // - // c.query( s ).drop().table( qh::books ).execute(); - // - // auto drop_authors_sql = c.query( s ) - // .drop() - // .table( qh::authors ) - // .execute(); - // - // std::cout << "SQL: " << drop_authors_sql << "\n"; - // - // auto res = c.query( s ) - // .select( {qh::payload.id} ) - // .from( qh::payload ) - // .join_left( qh::job ) - // .on( qh::job.payload == qh::payload.id ) - // .where( - // in( qh::payload.id, c.query( s ) - // .select( {qh::job.state} ) - // .from( qh::job ) - // .where( qh::job.state == job::job_state::Running ) - // ) && - // in( qh::payload.id, c.query( s ) - // .select( {qh::temporary_table.id} ) - // .from( qh::temporary_table ) ) - // ) - // .build(); - // // .fetch_value(); - // std::cout << "SQL: " << res.sql << "\n"; + schema s(""); + auto result = s.attach("authors").and_then([&s] { + return s.attach("books"); + }); + const auto c = pool.acquire(); + result = s.create(*c); + if (!result) { + std::cout << "error: " << result.err() << std::endl; return 0; -} \ No newline at end of file + } + + author mc; + 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 = query::insert() + .into(AUTHOR) + .values(mc) + .execute(*c); + + if (!insert_authors_sql) { + std::cout << "error: " << insert_authors_sql.err() << std::endl; + std::ignore = s.drop(*c); + return 0; + } + + auto authors_result = query::select(AUTHOR) + .from(AUTHOR) + .fetch_all(*c); + + if (!authors_result) { + std::cout << "error: " << authors_result.err() << std::endl; + std::ignore = s.drop(*c); + return 0; + } + + for (const auto &row: *authors_result) { + std::cout << "Author " << row.at(AUTHOR.first_name.canonical_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(); + // + // std::cout << "SQL: " << update_authors_sql << "\n"; + // + // auto authors = c.query( s ) + // .select( qh::authors.columns ) + // .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 = query::select( BOOK, {AUTHOR.last_name} ) + auto select_books_sql = query::select({BOOK.id, BOOK.title, BOOK.author_id, BOOK.published_in, AUTHOR.last_name}) + .from(BOOK) + .join_left(AUTHOR) + .on(BOOK.author_id == AUTHOR.id) + .where(BOOK.published_in < 2008 && AUTHOR.last_name == "King") + .group_by({BOOK.id, AUTHOR.last_name}) + .order_by(BOOK.title).asc() + .limit(5) + .offset(2) + .fetch_all(*c); + + if (!select_books_sql) { + std::cout << "error: " << select_books_sql.err() << std::endl; + std::ignore = s.drop(*c); + return 0; + } + + for (const auto &r: *select_books_sql) { + std::cout << "R: " << r.at(BOOK.title.canonical_name()) << ", " << r.at(AUTHOR.last_name.canonical_name()) << "\n"; + } + + result = s.drop(*c); + if (!result) { + std::cout << "error: " << result.err() << std::endl; + return 0; + } + + + // // 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 + // // OFFSET 2 LIMIT 5 + // + // c.query( s ).drop().table( qh::books ).execute(); + // + // auto drop_authors_sql = c.query( s ) + // .drop() + // .table( qh::authors ) + // .execute(); + // + // std::cout << "SQL: " << drop_authors_sql << "\n"; + // + auto res = query::select({PAYLOAD.id}) + .from(PAYLOAD) + .join_left(JOB) + .on(JOB.payload == PAYLOAD.id) + .where( + in(PAYLOAD.id, query::select({JOB.state}) + .from(JOB) + .where(JOB.state == job::job_state::Running).compile(c->dialect()) + ) && + in(PAYLOAD.id, query::select({TEMPORARY_TABLE.id}) + .from(TEMPORARY_TABLE).compile(c->dialect()) + ) + ).compile(c->dialect()); + // // .fetch_value(); + std::cout << "SQL: " << res.sql << "\n"; + + return 0; +} diff --git a/include/matador/object/attribute.hpp b/include/matador/object/attribute.hpp index e504fca..27b778b 100644 --- a/include/matador/object/attribute.hpp +++ b/include/matador/object/attribute.hpp @@ -52,6 +52,7 @@ public: [[nodiscard]] bool is_varchar() const; [[nodiscard]] bool is_date() const; [[nodiscard]] bool is_time() const; + [[nodiscard]] bool is_timestamp() const; [[nodiscard]] bool is_blob() const; [[nodiscard]] bool is_null() const; diff --git a/include/matador/object/collection.hpp b/include/matador/object/collection.hpp index fa3171a..22253a0 100644 --- a/include/matador/object/collection.hpp +++ b/include/matador/object/collection.hpp @@ -8,11 +8,13 @@ namespace matador::object { template < class Type > class collection { public: - using value_type = Type; + using value_type = Type; + void push_back(const Type& value) { data_.push_back(value); } + + [[nodiscard]] size_t size() const { return data_.size(); } private: std::vector data_; - }; } diff --git a/include/matador/query/intermediates/query_create_intermediate.hpp b/include/matador/query/intermediates/query_create_intermediate.hpp index 7ecb866..ebb99d7 100644 --- a/include/matador/query/intermediates/query_create_intermediate.hpp +++ b/include/matador/query/intermediates/query_create_intermediate.hpp @@ -21,7 +21,7 @@ public: executable_query constraints(std::initializer_list constraints); executable_query constraints(const std::list &restrictions); executable_query constraints(std::initializer_list constraints); - executable_query constraints(const std::list &restrictions); + executable_query constraints(const std::list &constraints); }; class query_create_table_intermediate : public query_intermediate { @@ -32,6 +32,7 @@ public: query_create_table_columns_intermediate columns(const std::list &attributes); query_create_table_columns_intermediate columns(std::initializer_list columns); query_create_table_columns_intermediate columns(const std::list &columns); + query_create_table_columns_intermediate columns(const std::vector &columns); }; class query_create_intermediate : public query_intermediate { diff --git a/include/matador/query/intermediates/query_execute_where_intermediate.hpp b/include/matador/query/intermediates/query_execute_where_intermediate.hpp index c1c10a7..1029401 100644 --- a/include/matador/query/intermediates/query_execute_where_intermediate.hpp +++ b/include/matador/query/intermediates/query_execute_where_intermediate.hpp @@ -15,6 +15,7 @@ public: query_execute_limit_intermediate limit(size_t limit); query_execute_order_by_intermediate order_by(const table_column &col); + query_execute_order_by_intermediate order_by(std::initializer_list columns); }; } diff --git a/include/matador/query/intermediates/query_from_intermediate.hpp b/include/matador/query/intermediates/query_from_intermediate.hpp index 440831d..222457c 100644 --- a/include/matador/query/intermediates/query_from_intermediate.hpp +++ b/include/matador/query/intermediates/query_from_intermediate.hpp @@ -19,14 +19,11 @@ public: query_from_intermediate join_left(join_data &data); query_from_intermediate join_left(std::vector &data_vector); - // template - // query_where_intermediate where(const Condition &cond) - // { - // return where_clause(std::make_unique(std::move(cond))); - // } query_where_intermediate where(std::unique_ptr &&cond); - query_group_by_intermediate group_by(const table_column &col); + query_group_by_intermediate group_by(const table_column &column); + query_group_by_intermediate group_by(std::initializer_list columns); query_order_by_intermediate order_by(const table_column &col); + query_order_by_intermediate order_by(std::initializer_list columns); private: query_where_intermediate where_clause(std::unique_ptr &&cond); diff --git a/include/matador/query/intermediates/query_group_by_intermediate.hpp b/include/matador/query/intermediates/query_group_by_intermediate.hpp index 9986235..ea5d901 100644 --- a/include/matador/query/intermediates/query_group_by_intermediate.hpp +++ b/include/matador/query/intermediates/query_group_by_intermediate.hpp @@ -13,6 +13,7 @@ public: using fetchable_query::fetchable_query; query_order_by_intermediate order_by(const table_column &col); + query_order_by_intermediate order_by(std::initializer_list columns); }; } diff --git a/include/matador/query/intermediates/query_where_intermediate.hpp b/include/matador/query/intermediates/query_where_intermediate.hpp index be32629..d2720e7 100644 --- a/include/matador/query/intermediates/query_where_intermediate.hpp +++ b/include/matador/query/intermediates/query_where_intermediate.hpp @@ -13,8 +13,10 @@ class query_where_intermediate : public fetchable_query public: using fetchable_query::fetchable_query; - query_group_by_intermediate group_by(const table_column &col); + query_group_by_intermediate group_by(const table_column &column); + query_group_by_intermediate group_by(std::initializer_list columns); query_order_by_intermediate order_by(const table_column &col); + query_order_by_intermediate order_by(std::initializer_list columns); }; } diff --git a/include/matador/query/internal/query_parts.hpp b/include/matador/query/internal/query_parts.hpp index 1810c48..11bce9f 100644 --- a/include/matador/query/internal/query_parts.hpp +++ b/include/matador/query/internal/query_parts.hpp @@ -205,29 +205,29 @@ protected: class query_group_by_part final : public query_part { public: - explicit query_group_by_part(class table_column col); + explicit query_group_by_part(const std::vector& columns); - [[nodiscard]] const table_column& column() const; + [[nodiscard]] const std::vector& columns() const; private: void accept(query_part_visitor &visitor) override; private: - table_column column_; + std::vector columns_; }; class query_order_by_part final : public query_part { public: - explicit query_order_by_part(class table_column col); + explicit query_order_by_part(const std::vector& columns); - [[nodiscard]] const table_column& column() const; + [[nodiscard]] const std::vector& columns() const; private: void accept(query_part_visitor &visitor) override; private: - table_column column_; + std::vector columns_; }; class query_order_by_asc_part final : public query_part diff --git a/include/matador/query/meta_table_macro.hpp b/include/matador/query/meta_table_macro.hpp index 986753c..0b58c03 100644 --- a/include/matador/query/meta_table_macro.hpp +++ b/include/matador/query/meta_table_macro.hpp @@ -16,7 +16,7 @@ namespace internal { \ class TABLE_NAME##_table : public typed_table { \ public: \ TABLE_NAME##_table()\ -: TABLE_NAME##_table("") \ +: TABLE_NAME##_table(#TABLE_NAME) \ {} \ TABLE_NAME##_table(const std::string& alias) \ : typed_table(#TABLE_NAME, alias, {MAP(FIELD_STRING, __VA_ARGS__)}) \ diff --git a/include/matador/query/query.hpp b/include/matador/query/query.hpp index b40eeb6..25f1c14 100644 --- a/include/matador/query/query.hpp +++ b/include/matador/query/query.hpp @@ -25,7 +25,6 @@ public: [[nodiscard]] static query_select_intermediate select(std::initializer_list columns); [[nodiscard]] static query_select_intermediate select(const std::vector& columns); [[nodiscard]] static query_select_intermediate select(const std::vector &column_names); - [[nodiscard]] static query_select_intermediate select(std::vector columns, std::initializer_list additional_columns); template [[nodiscard]] static query_select_intermediate select(const schema &scm) { return select(generator::columns(scm)); diff --git a/include/matador/utils/access.hpp b/include/matador/utils/access.hpp index 85aa86e..ba910b6 100644 --- a/include/matador/utils/access.hpp +++ b/include/matador/utils/access.hpp @@ -2,16 +2,12 @@ #define OOS_ACCESS_HPP #include -#include #include namespace matador { enum class cascade_type; -template < class Type, template < class ... > class ContainerType > -class container; - namespace utils { class field_attributes; class foreign_attributes; diff --git a/include/matador/utils/identifier.hpp b/include/matador/utils/identifier.hpp index 86a2562..fa3c8d0 100644 --- a/include/matador/utils/identifier.hpp +++ b/include/matador/utils/identifier.hpp @@ -194,6 +194,7 @@ public: [[nodiscard]] bool is_varchar() const; [[nodiscard]] bool is_date() const; [[nodiscard]] bool is_time() const; + [[nodiscard]] bool is_timestamp() const; [[nodiscard]] bool is_blob() const; [[nodiscard]] bool is_null() const; diff --git a/include/matador/utils/value.hpp b/include/matador/utils/value.hpp index b21d6ee..b220abe 100644 --- a/include/matador/utils/value.hpp +++ b/include/matador/utils/value.hpp @@ -18,15 +18,19 @@ size_t determine_size(const blob_type_t &val); } -class value -{ +class value { public: value() = default; - template + template>* = nullptr> explicit value(Type value, size_t size = 0) : value_(value) , size_(size) , type_(data_type_traits::type(size)) {} + template>* = nullptr> + explicit value(Type value, size_t size = 0) + : value_(static_cast(value)) + , size_(size) + , type_(data_type_traits::type(size)) {} explicit value(basic_type data_type, size_t size = 0); value(const value &x) = default; value& operator=(const value &x) = default; @@ -74,11 +78,12 @@ public: [[nodiscard]] bool is_varchar() const; [[nodiscard]] bool is_date() const; [[nodiscard]] bool is_time() const; + [[nodiscard]] bool is_timestamp() const; [[nodiscard]] bool is_blob() const; [[nodiscard]] bool is_null() const; private: - utils::database_type value_; + database_type value_; size_t size_{}; basic_type type_{basic_type::Null}; diff --git a/source/core/object/attribute.cpp b/source/core/object/attribute.cpp index 8a5a5fe..99d54de 100644 --- a/source/core/object/attribute.cpp +++ b/source/core/object/attribute.cpp @@ -85,6 +85,10 @@ bool attribute::is_time() const { return type_ == utils::basic_type::Time; } +bool attribute::is_timestamp() const { + return type_ == utils::basic_type::DateTime; +} + bool attribute::is_blob() const { return type_ == utils::basic_type::Blob; } diff --git a/source/core/utils/identifier.cpp b/source/core/utils/identifier.cpp index 8a1521a..9d7bf6b 100644 --- a/source/core/utils/identifier.cpp +++ b/source/core/utils/identifier.cpp @@ -9,63 +9,58 @@ size_t detail::hash(const char *value) { return std::hash()(std::string_view(value, std::strlen(value))); } -bool identifier_type_traits::is_valid(const char *value) { +bool identifier_type_traits::is_valid(const char *value) { return value != nullptr && strlen(value) > 0; } -std::string identifier_type_traits::to_string(const char *value) { +std::string identifier_type_traits::to_string(const char *value) { return value; } identifier::base::base(const std::type_index &ti, const basic_type type) - : type_index_(ti) - , type_(type) -{} +: type_index_(ti) + , type_(type) { +} identifier::null_pk::null_pk() - : base(std::type_index(typeid(null_type_t)), basic_type::Null) -{} +: base(std::type_index(typeid(null_type_t)), basic_type::Null) { +} -identifier::base* identifier::null_pk::copy() const -{ +identifier::base *identifier::null_pk::copy() const { return new null_pk; } -bool identifier::null_pk::equal_to(const base &x) const -{ +bool identifier::null_pk::equal_to(const base &x) const { return type_index_ == x.type_index_; } -bool identifier::null_pk::less(const base &x) const -{ +bool identifier::null_pk::less(const base &x) const { return type_index_ == x.type_index_; } -bool identifier::null_pk::is_valid() const -{ +bool identifier::null_pk::is_valid() const { return identifier_type_traits::is_valid(); } -std::string identifier::null_pk::str() const -{ +std::string identifier::null_pk::str() const { return identifier_type_traits::to_string(); } -void identifier::null_pk::serialize(identifier_serializer &s) -{ +void identifier::null_pk::serialize(identifier_serializer &s) { s.serialize(null_, {}); } -size_t identifier::null_pk::hash() const -{ +size_t identifier::null_pk::hash() const { return std::hash()(nullptr); } identifier::identifier() -: id_(std::make_shared()) {} +: id_(std::make_shared()) { +} identifier::identifier(const identifier &x) -: id_(x.id_->copy()) {} +: id_(x.id_->copy()) { +} identifier &identifier::operator=(const identifier &x) { if (this == &x) { @@ -123,13 +118,11 @@ basic_type identifier::type() const { return id_->type_; } -identifier identifier::share() const -{ +identifier identifier::share() const { return identifier(id_); } -size_t identifier::use_count() const -{ +size_t identifier::use_count() const { return id_.use_count(); } @@ -157,22 +150,23 @@ bool identifier::is_time() const { return id_->type_ == basic_type::Time; } +bool identifier::is_timestamp() const { + return id_->type_ == basic_type::DateTime; +} + bool identifier::is_blob() const { return id_->type_ == basic_type::Blob; } -bool identifier::is_null() const -{ +bool identifier::is_null() const { return type_index() == null_identifier.type_index(); } -bool identifier::is_valid() const -{ +bool identifier::is_valid() const { return id_->is_valid(); } -void identifier::clear() -{ +void identifier::clear() { id_ = std::make_unique(); } @@ -180,24 +174,20 @@ void identifier::serialize(identifier_serializer &s) const { id_->serialize(s); } -size_t identifier::hash() const -{ +size_t identifier::hash() const { return id_->hash(); } identifier::identifier(const std::shared_ptr &id) - : id_(id) -{} +: id_(id) { +} -std::ostream &operator<<(std::ostream &out, const identifier &id) -{ +std::ostream &operator<<(std::ostream &out, const identifier &id) { out << id.str(); return out; } -size_t id_pk_hash::operator()(const identifier &id) const -{ +size_t id_pk_hash::operator()(const identifier &id) const { return id.hash(); } - -} \ No newline at end of file +} diff --git a/source/core/utils/value.cpp b/source/core/utils/value.cpp index 268c4a8..e2ba757 100644 --- a/source/core/utils/value.cpp +++ b/source/core/utils/value.cpp @@ -84,6 +84,10 @@ bool value::is_time() const { return type_ == basic_type::Time; } +bool value::is_timestamp() const { + return type_ == basic_type::DateTime; +} + bool value::is_blob() const { return type_ == basic_type::Blob; } diff --git a/source/orm/query/intermediates/query_create_intermediate.cpp b/source/orm/query/intermediates/query_create_intermediate.cpp index 8cab626..9a76c1c 100644 --- a/source/orm/query/intermediates/query_create_intermediate.cpp +++ b/source/orm/query/intermediates/query_create_intermediate.cpp @@ -79,4 +79,13 @@ query_create_table_columns_intermediate query_create_table_intermediate::columns return {context_}; } + +query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::vector &columns) { + std::list cols; + for (const auto &col : columns) { + cols.emplace_back(col); + } + + return this->columns(cols); +} } diff --git a/source/orm/query/intermediates/query_execute_where_intermediate.cpp b/source/orm/query/intermediates/query_execute_where_intermediate.cpp index d4acca7..6a138a1 100644 --- a/source/orm/query/intermediates/query_execute_where_intermediate.cpp +++ b/source/orm/query/intermediates/query_execute_where_intermediate.cpp @@ -13,8 +13,11 @@ query_execute_limit_intermediate query_execute_where_intermediate::limit(size_t } query_execute_order_by_intermediate query_execute_where_intermediate::order_by(const table_column &col) { - context_->parts.push_back(std::make_unique(col)); - return {context_}; + return order_by({col}); } +query_execute_order_by_intermediate query_execute_where_intermediate::order_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); + return {context_}; +} } diff --git a/source/orm/query/intermediates/query_from_intermediate.cpp b/source/orm/query/intermediates/query_from_intermediate.cpp index 2f8f783..916884a 100644 --- a/source/orm/query/intermediates/query_from_intermediate.cpp +++ b/source/orm/query/intermediates/query_from_intermediate.cpp @@ -38,13 +38,21 @@ query_where_intermediate query_from_intermediate::where_clause(std::unique_ptrparts.push_back(std::make_unique(col)); +query_group_by_intermediate query_from_intermediate::group_by(const table_column &column) { + return group_by({column}); +} + +query_group_by_intermediate query_from_intermediate::group_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); return {context_}; } query_order_by_intermediate query_from_intermediate::order_by(const table_column &col) { - context_->parts.push_back(std::make_unique(col)); + return order_by({col}); +} + +query_order_by_intermediate query_from_intermediate::order_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); return {context_}; } diff --git a/source/orm/query/intermediates/query_group_by_intermediate.cpp b/source/orm/query/intermediates/query_group_by_intermediate.cpp index 375565d..f0f2998 100644 --- a/source/orm/query/intermediates/query_group_by_intermediate.cpp +++ b/source/orm/query/intermediates/query_group_by_intermediate.cpp @@ -6,8 +6,11 @@ namespace matador::query { query_order_by_intermediate query_group_by_intermediate::order_by(const table_column &col) { - context_->parts.push_back(std::make_unique(col)); - return {context_}; + return order_by({col}); } -} \ No newline at end of file +query_order_by_intermediate query_group_by_intermediate::order_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); + return {context_}; +} +} diff --git a/source/orm/query/intermediates/query_where_intermediate.cpp b/source/orm/query/intermediates/query_where_intermediate.cpp index e2a60ae..c2686d4 100644 --- a/source/orm/query/intermediates/query_where_intermediate.cpp +++ b/source/orm/query/intermediates/query_where_intermediate.cpp @@ -5,15 +5,23 @@ #include "matador/query/internal/query_parts.hpp" namespace matador::query { +query_group_by_intermediate query_where_intermediate::group_by(const table_column &column) { + return group_by({column}); +} -query_group_by_intermediate query_where_intermediate::group_by(const table_column &col) { - context_->parts.push_back(std::make_unique(col)); +query_group_by_intermediate query_where_intermediate::group_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); return {context_}; } query_order_by_intermediate query_where_intermediate::order_by(const table_column &col) { - context_->parts.push_back(std::make_unique(col)); + return order_by({col}); +} + +query_order_by_intermediate query_where_intermediate::order_by(std::initializer_list columns) { + context_->parts.push_back(std::make_unique(columns)); return {context_}; } + } \ No newline at end of file diff --git a/source/orm/query/internal/query_parts.cpp b/source/orm/query/internal/query_parts.cpp index 3fb5948..09e62d0 100644 --- a/source/orm/query/internal/query_parts.cpp +++ b/source/orm/query/internal/query_parts.cpp @@ -4,444 +4,439 @@ namespace matador::query::internal { query_alter_part::query_alter_part() -: query_part(sql::dialect_token::Alter) {} +: query_part(sql::dialect_token::Alter) { +} -void query_alter_part::accept( query_part_visitor& visitor ) { +void query_alter_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_alter_table_part::query_alter_table_part(class table tab) : query_part(sql::dialect_token::Table) -, table_(std::move(tab)) {} +, table_(std::move(tab)) { +} -void query_alter_table_part::accept(query_part_visitor& visitor) { +void query_alter_table_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const table& query_alter_table_part::table() const { +const table &query_alter_table_part::table() const { return table_; } query_add_key_constraint_part::query_add_key_constraint_part(std::string name) : query_part(sql::dialect_token::AddConstraint) -, name_(std::move(name)){} +, name_(std::move(name)) { +} -void query_add_key_constraint_part::accept( query_part_visitor& visitor ) { +void query_add_key_constraint_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const std::string& query_add_key_constraint_part::name() const { - return name_; +const std::string &query_add_key_constraint_part::name() const { + return name_; } query_add_constraint_part_by_constraint::query_add_constraint_part_by_constraint(const query::table_constraint &co) : query_part(sql::dialect_token::AddConstraint) -, constraint_(co) {} +, constraint_(co) { +} void query_add_constraint_part_by_constraint::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const table_constraint & query_add_constraint_part_by_constraint::constraint() const { +const table_constraint &query_add_constraint_part_by_constraint::constraint() const { return constraint_; } query_drop_key_constraint_part_by_name::query_drop_key_constraint_part_by_name(std::string name) -: query_part( sql::dialect_token::DropConstraint ) -, name_(std::move( name )){} +: query_part(sql::dialect_token::DropConstraint) +, name_(std::move(name)) { +} -void query_drop_key_constraint_part_by_name::accept(query_part_visitor& visitor) { +void query_drop_key_constraint_part_by_name::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const std::string& query_drop_key_constraint_part_by_name::name() const { +const std::string &query_drop_key_constraint_part_by_name::name() const { return name_; } query_drop_key_constraint_part_by_constraint::query_drop_key_constraint_part_by_constraint(const table_constraint &co) -: query_part( sql::dialect_token::DropConstraint ) -, constraint_(co) {} - -void query_drop_key_constraint_part_by_constraint::accept(query_part_visitor& visitor) { - visitor.visit(*this); +: query_part(sql::dialect_token::DropConstraint) +, constraint_(co) { } -const table_constraint& query_drop_key_constraint_part_by_constraint::constraint() const { +void query_drop_key_constraint_part_by_constraint::accept(query_part_visitor &visitor) { + visitor.visit(*this); +} + +const table_constraint &query_drop_key_constraint_part_by_constraint::constraint() const { return constraint_; } -query_add_foreign_key_constraint_part::query_add_foreign_key_constraint_part(const std::vector& columns) +query_add_foreign_key_constraint_part::query_add_foreign_key_constraint_part(const std::vector &columns) : query_part(sql::dialect_token::ForeignKey) -, columns_(columns) {} +, columns_(columns) { +} -void query_add_foreign_key_constraint_part::accept( query_part_visitor& visitor ) { +void query_add_foreign_key_constraint_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const std::vector& query_add_foreign_key_constraint_part::columns() const { +const std::vector &query_add_foreign_key_constraint_part::columns() const { return columns_; } -query_add_foreign_key_reference_part::query_add_foreign_key_reference_part(class table tab, const std::vector& columns) +query_add_foreign_key_reference_part::query_add_foreign_key_reference_part( + class table tab, const std::vector &columns) : query_part(sql::dialect_token::References) , table_(std::move(tab)) -, columns_(columns) {} +, columns_(columns) { +} -void query_add_foreign_key_reference_part::accept( query_part_visitor& visitor ) { +void query_add_foreign_key_reference_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const table& query_add_foreign_key_reference_part::table() const { +const table &query_add_foreign_key_reference_part::table() const { return table_; } -const std::vector& query_add_foreign_key_reference_part::columns() const { +const std::vector &query_add_foreign_key_reference_part::columns() const { return columns_; } -query_add_primary_key_constraint_part::query_add_primary_key_constraint_part(const std::vector& columns) +query_add_primary_key_constraint_part::query_add_primary_key_constraint_part(const std::vector &columns) : query_part(sql::dialect_token::PrimaryKey) -, columns_(columns) {} +, columns_(columns) { +} -void query_add_primary_key_constraint_part::accept( query_part_visitor& visitor ) { +void query_add_primary_key_constraint_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const std::vector& query_add_primary_key_constraint_part::columns() const { +const std::vector &query_add_primary_key_constraint_part::columns() const { return columns_; } query_select_part::query_select_part(std::vector columns) - : query_part(sql::dialect_token::Select) - , columns_(std::move(columns)) {} +: query_part(sql::dialect_token::Select) +, columns_(std::move(columns)) { +} -void query_select_part::accept(query_part_visitor &visitor) -{ +void query_select_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const std::vector& query_select_part::columns() const -{ +const std::vector &query_select_part::columns() const { return columns_; } query_from_part::query_from_part(class table tab) - : query_part(sql::dialect_token::From) - , table_(std::move(tab)) {} +: query_part(sql::dialect_token::From) +, table_(std::move(tab)) { +} -const table &query_from_part::table() const -{ +const table &query_from_part::table() const { return table_; } -void query_from_part::accept(query_part_visitor &visitor) -{ +void query_from_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_join_part::query_join_part(class table tab) - : query_part(sql::dialect_token::Join) - , table_(std::move(tab)) {} +: query_part(sql::dialect_token::Join) +, table_(std::move(tab)) { +} -const table &query_join_part::table() const -{ +const table &query_join_part::table() const { return table_; } -void query_join_part::accept(query_part_visitor &visitor) -{ +void query_join_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_on_part::query_on_part(std::unique_ptr &&cond) : query_part(sql::dialect_token::On) -, condition_(std::move(cond)) {} +, condition_(std::move(cond)) { +} -const abstract_criteria &query_on_part::condition() const -{ +const abstract_criteria &query_on_part::condition() const { return *condition_; } -void query_on_part::accept(query_part_visitor &visitor) -{ +void query_on_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_where_part::query_where_part(std::unique_ptr &&cond) : query_part(sql::dialect_token::Where) -, condition_(std::move(cond)) {} +, condition_(std::move(cond)) { +} -void query_where_part::accept(query_part_visitor &visitor) -{ +void query_where_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -const abstract_criteria &query_where_part::condition() const -{ +const abstract_criteria &query_where_part::condition() const { return *condition_; } query_table_name_part::query_table_name_part(const sql::dialect_token token, std::string table_name) : query_part(token) -, table_name_(std::move(table_name)) {} - -query_group_by_part::query_group_by_part(class table_column col) -: query_part(sql::dialect_token::GroupBy) -, column_(std::move(col)) -{} - -const table_column &query_group_by_part::column() const -{ - return column_; +, table_name_(std::move(table_name)) { } -void query_group_by_part::accept(query_part_visitor &visitor) -{ +query_group_by_part::query_group_by_part(const std::vector &columns) +: query_part(sql::dialect_token::GroupBy) +, columns_(columns) { +} + +const std::vector &query_group_by_part::columns() const { + return columns_; +} + +void query_group_by_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -query_order_by_part::query_order_by_part(class table_column col) +query_order_by_part::query_order_by_part(const std::vector& columns) : query_part(sql::dialect_token::OrderBy) -, column_(std::move(col)) -{} - -const table_column &query_order_by_part::column() const -{ - return column_; +, columns_(columns) { } -void query_order_by_part::accept(query_part_visitor &visitor) -{ +const std::vector &query_order_by_part::columns() const { + return columns_; +} + +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(sql::dialect_token::Asc) -{} +: query_part(sql::dialect_token::Asc) { +} -void query_order_by_asc_part::accept(query_part_visitor &visitor) -{ +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(sql::dialect_token::Desc) -{} +: query_part(sql::dialect_token::Desc) { +} -void query_order_by_desc_part::accept(query_part_visitor &visitor) -{ +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(sql::dialect_token::Offset) -, offset_(offset) {} +, offset_(offset) { +} -size_t query_offset_part::offset() const -{ +size_t query_offset_part::offset() const { return offset_; } -void query_offset_part::accept(query_part_visitor &visitor) -{ +void query_offset_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_limit_part::query_limit_part(size_t limit) : query_part(sql::dialect_token::Limit) -, limit_(limit) {} +, limit_(limit) { +} -size_t query_limit_part::limit() const -{ +size_t query_limit_part::limit() const { return limit_; } -void query_limit_part::accept(query_part_visitor &visitor) -{ +void query_limit_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_insert_part::query_insert_part() -: query_part(sql::dialect_token::Insert) {} +: query_part(sql::dialect_token::Insert) { +} -void query_insert_part::accept(query_part_visitor &visitor) -{ +void query_insert_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_into_part::query_into_part(class table tab, std::vector columns) : query_part(sql::dialect_token::Insert) , table_(std::move(tab)) -, columns_(std::move(columns)) {} +, columns_(std::move(columns)) { +} -const table &query_into_part::table() const -{ +const table &query_into_part::table() const { return table_; } -const std::vector &query_into_part::columns() const -{ +const std::vector &query_into_part::columns() const { return columns_; } -void query_into_part::accept(query_part_visitor &visitor) -{ +void query_into_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -query_values_part::query_values_part(std::vector> &&values) +query_values_part::query_values_part(std::vector > &&values) : query_part(sql::dialect_token::Values) -, values_(std::move(values)) {} +, values_(std::move(values)) { +} -const std::vector>& query_values_part::values() const -{ +const std::vector > &query_values_part::values() const { return values_; } -void query_values_part::accept(query_part_visitor &visitor) -{ +void query_values_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_update_part::query_update_part(class table tab) : query_part(sql::dialect_token::Update) -, table_(std::move(tab)) {} +, table_(std::move(tab)) { +} -const table& query_update_part::table() const -{ +const table &query_update_part::table() const { return table_; } -void query_update_part::accept(query_part_visitor &visitor) -{ +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_set_part::query_set_part(const std::vector &key_value_pairs) : query_part(sql::dialect_token::Set) -, key_value_pairs_(key_value_pairs) {} +, key_value_pairs_(key_value_pairs) { +} -const std::vector &query_set_part::column_values() const -{ +const std::vector &query_set_part::column_values() const { return key_value_pairs_; } -void query_set_part::accept(query_part_visitor &visitor) -{ +void query_set_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_delete_part::query_delete_part() -: query_part(sql::dialect_token::Remove) {} +: query_part(sql::dialect_token::Remove) { +} -void query_delete_part::accept(query_part_visitor &visitor) -{ +void query_delete_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_delete_from_part::query_delete_from_part(class table tab) : query_part(sql::dialect_token::From) -, table_(std::move(tab)) {} +, table_(std::move(tab)) { +} -const table &query_delete_from_part::table() const -{ +const table &query_delete_from_part::table() const { return table_; } -void query_delete_from_part::accept(query_part_visitor &visitor) -{ +void query_delete_from_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_create_part::query_create_part() -: query_part(sql::dialect_token::Create) {} +: query_part(sql::dialect_token::Create) { +} -void query_create_part::accept(query_part_visitor &visitor) -{ +void query_create_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_create_table_part::query_create_table_part(class table tab) : query_part(sql::dialect_token::Table) -, table_(std::move(tab)) {} +, table_(std::move(tab)) { +} -const table &query_create_table_part::table() const -{ +const table &query_create_table_part::table() const { return table_; } -void query_create_table_part::accept(query_part_visitor &visitor) -{ +void query_create_table_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -query_create_table_columns_part::query_create_table_columns_part(const std::list& columns) -: query_part( sql::dialect_token::Columns ) -, columns_(columns){} +query_create_table_columns_part::query_create_table_columns_part(const std::list &columns) +: query_part(sql::dialect_token::Columns) +, columns_(columns) { +} -const std::list& query_create_table_columns_part::columns() const { +const std::list &query_create_table_columns_part::columns() const { return columns_; } -void query_create_table_columns_part::accept(query_part_visitor& visitor) { +void query_create_table_columns_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -query_create_table_constraints_part::query_create_table_constraints_part(const std::list& constraints) -: query_part( sql::dialect_token::Constraint ) -, constraints_(constraints) {} +query_create_table_constraints_part::query_create_table_constraints_part( + const std::list &constraints) +: query_part(sql::dialect_token::Constraint) +, constraints_(constraints) { +} -const std::list& query_create_table_constraints_part::constraints() const { +const std::list &query_create_table_constraints_part::constraints() const { return constraints_; } -void query_create_table_constraints_part::accept( query_part_visitor& visitor ) { +void query_create_table_constraints_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_create_schema_part::query_create_schema_part(std::string schema) -: query_part( sql::dialect_token::Schema ) -, schema_( std::move( schema ) ){} - -const std::string& query_create_schema_part::schema() const { - return schema_; +: query_part(sql::dialect_token::Schema) +, schema_(std::move(schema)) { } -void query_create_schema_part::accept( query_part_visitor& visitor ) { - visitor.visit(*this); +const std::string &query_create_schema_part::schema() const { + return schema_; +} + +void query_create_schema_part::accept(query_part_visitor &visitor) { + visitor.visit(*this); } query_drop_part::query_drop_part() -: query_part(sql::dialect_token::Drop) {} +: query_part(sql::dialect_token::Drop) { +} -void query_drop_part::accept(query_part_visitor &visitor) -{ +void query_drop_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_drop_table_part::query_drop_table_part(class table tab) : query_part(sql::dialect_token::Table) -, table_(std::move(tab)) {} +, table_(std::move(tab)) { +} -const table &query_drop_table_part::table() const -{ +const table &query_drop_table_part::table() const { return table_; } -void query_drop_table_part::accept(query_part_visitor &visitor) -{ +void query_drop_table_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } query_drop_schema_part::query_drop_schema_part(std::string schema_) -: query_part( sql::dialect_token::Schema ) -, schema_( std::move( schema_ ) ) {} +: query_part(sql::dialect_token::Schema) +, schema_(std::move(schema_)) { +} -const std::string& query_drop_schema_part::schema() const { +const std::string &query_drop_schema_part::schema() const { return schema_; } -void query_drop_schema_part::accept( query_part_visitor& visitor ) { +void query_drop_schema_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -} \ No newline at end of file +} diff --git a/source/orm/query/query.cpp b/source/orm/query/query.cpp index 65ee7eb..ae77362 100644 --- a/source/orm/query/query.cpp +++ b/source/orm/query/query.cpp @@ -49,13 +49,6 @@ query_select_intermediate query::select(const std::vector &column_n return select(columns); } -query_select_intermediate query::select(std::vector columns, const std::initializer_list additional_columns) { - for (const auto &col : additional_columns) { - columns.push_back(col); - } - return query_select_intermediate{columns}; -} - query_insert_intermediate query::insert() { return {}; } diff --git a/source/orm/query/query_compiler.cpp b/source/orm/query/query_compiler.cpp index 064cef7..8ed6cec 100644 --- a/source/orm/query/query_compiler.cpp +++ b/source/orm/query/query_compiler.cpp @@ -179,12 +179,35 @@ void query_compiler::visit(internal::query_where_part &part) { } void query_compiler::visit(internal::query_group_by_part &part) { - query_.sql += " " + dialect_->group_by() + " " + prepare_identifier(*dialect_, part.column()); + query_.sql += " " + dialect_->group_by() + " "; + if (part.columns().size() < 2) { + for (const auto &col: part.columns()) { + query_.sql.append(dialect_->prepare_identifier_string(col.canonical_name())); + } + } else { + auto it = part.columns().begin(); + query_.sql.append(dialect_->prepare_identifier_string((it++)->canonical_name())); + for (; it != part.columns().end(); ++it) { + query_.sql.append(", "); + query_.sql.append(dialect_->prepare_identifier_string(it->canonical_name())); + } + } } void query_compiler::visit(internal::query_order_by_part &part) { - query_.sql += " " + dialect_->order_by() + - " " + prepare_criteria(*dialect_, part.column()); + query_.sql += " " + dialect_->order_by() + " "; + if (part.columns().size() < 2) { + for (const auto &col: part.columns()) { + query_.sql.append(dialect_->prepare_identifier_string(col.canonical_name())); + } + } else { + auto it = part.columns().begin(); + query_.sql.append(dialect_->prepare_identifier_string((it++)->canonical_name())); + for (; it != part.columns().end(); ++it) { + query_.sql.append(", "); + query_.sql.append(dialect_->prepare_identifier_string(it->canonical_name())); + } + } } void query_compiler::visit(internal::query_order_by_asc_part &/*order_by_asc_part*/) { diff --git a/test/backends/QueryRecordTest.cpp b/test/backends/QueryRecordTest.cpp index 6c4e5b9..357ed3b 100644 --- a/test/backends/QueryRecordTest.cpp +++ b/test/backends/QueryRecordTest.cpp @@ -120,7 +120,6 @@ TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record REQUIRE(str == row.at("val_string")); REQUIRE(varchar == row.at("val_varchar")); REQUIRE(md == row.at("val_date")); - const auto mtres = row.at("val_time"); REQUIRE(mt == row.at("val_time")); REQUIRE(bin == row.at("val_blob")); } @@ -510,7 +509,7 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with group by and order auto result = query::select({count("age").as("age_count"), "age"}) .from("person") - .group_by("age") + .group_by({"age"}) .order_by("age_count").desc() .fetch_all(db); REQUIRE(result.is_ok()); diff --git a/test/backends/QueryTest.cpp b/test/backends/QueryTest.cpp index b1b2297..4e4cea5 100644 --- a/test/backends/QueryTest.cpp +++ b/test/backends/QueryTest.cpp @@ -12,6 +12,9 @@ #include "models/flight.hpp" #include "models/person.hpp" #include "models/recipe.hpp" +#include "models/shipment.hpp" + +#include "../test/utils/record_printer.hpp" using namespace matador::object; using namespace matador::query; @@ -23,6 +26,8 @@ META_TABLE(ingredients, INGREDIENT, id, name); META_TABLE(recipe_ingredients, RECIPE_INGREDIENT, recipe_id, ingredient_id); META_TABLE(airplanes, AIRPLANE, id, brand, model); META_TABLE(flights, FLIGHT, id, airplane_id, pilot_name); +META_TABLE(shipments, SHIPMENT, id, tracking_number) +META_TABLE(packages, PACKAGE, id, weight, shipment) TEST_CASE_METHOD(QueryFixture, "Create table with foreign key relation", "[query][foreign][relation]") { auto result = repo.attach("airplane") @@ -605,4 +610,107 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship" REQUIRE(row.at(3).as().value() == std::get<3>(expected_result_two_joins[index])); ++index; } +} + +void print(std::ostream& out, const record& row) { + for (const auto& f : row) { + out << f << " "; + } +} + +TEST_CASE_METHOD(QueryFixture, "Test load entity with eager has many relation", "[query][has_many][eager]") { + auto result = repo.attach("packages") + .and_then( [this] { return repo.attach("shipments"); } ); + // auto result = repo.attach("shipments") + // .and_then( [this] { return repo.attach("packages"); } ); + REQUIRE(result.is_ok()); + tables_to_drop.emplace("shipments"); + tables_to_drop.emplace("packages"); + + result = repo.create(db); + REQUIRE(result.is_ok()); + + const std::vector shipments { + object_ptr{new shipment{1, "4711"}}, + object_ptr{new shipment{2, "0815"}} + }; + + using namespace matador::query::meta; + + for (const auto &sh: shipments) { + auto res = query::insert() + .into(SHIPMENT, SHIPMENT) + .values(*sh) + .execute(db); + REQUIRE(res.is_ok()); + REQUIRE(*res == 1); + } + + auto count = query::select({count_all()}) + .from(SHIPMENT) + .fetch_value(db); + REQUIRE(count.is_ok()); + REQUIRE(*count == 2); + + std::vector packages { + object_ptr{new package{3, 15.4, shipments.at(0)}}, + object_ptr{new package{4, 1.3, shipments.at(0)}}, + object_ptr{new package{5, 30.9, shipments.at(1)}}, + object_ptr{new package{6, 22.8, shipments.at(1)}}, + object_ptr{new package{7, 17.2, shipments.at(1)}} + }; + + for (const auto &pkg: packages) { + auto res = query::insert() + .into(PACKAGE, PACKAGE) + .values(*pkg) + .execute(db); + REQUIRE(res.is_ok()); + REQUIRE(*res == 1); + } + + count = query::select({count_all()}) + .from(PACKAGE) + .fetch_value(db); + REQUIRE(count.is_ok()); + REQUIRE(*count == 5); + + auto pkgs = query::select({PACKAGE.id, PACKAGE.weight, PACKAGE.shipment, SHIPMENT.tracking_number}) + .from(PACKAGE) + .join_left(SHIPMENT) + .on( PACKAGE.shipment == SHIPMENT.id ) + .where( PACKAGE.weight > 20.0 && SHIPMENT.tracking_number == "0815" ) + .group_by({PACKAGE.id, SHIPMENT.tracking_number}) + .order_by(PACKAGE.weight).asc() + .limit( 5 ) + .offset( 0 ) + .fetch_all(db); + + REQUIRE(pkgs.is_ok()); + + record_printer printer(std::cout); + printer.print(*pkgs); + + auto shipment_records = query::select({SHIPMENT.tracking_number, SHIPMENT.id, PACKAGE.weight, PACKAGE.weight}) + .from(SHIPMENT) + .join_left(PACKAGE) + .on( SHIPMENT.id == PACKAGE.shipment ) + .fetch_all(db); + + REQUIRE(shipment_records.is_ok()); + + printer.print(*shipment_records); + + auto shipment_result = query::select({SHIPMENT.id, SHIPMENT.tracking_number, PACKAGE.id, PACKAGE.weight, PACKAGE.shipment}) + .from(SHIPMENT) + .join_left(PACKAGE) + .on( SHIPMENT.id == PACKAGE.shipment ) + .fetch_all(db); + + REQUIRE(shipment_result.is_ok()); + + std::cout << "\n"; + for (const auto &s : *shipment_result) { + std::cout << s.id << " " << s.tracking_number << " packages: " << s.packages.size() << std::endl; + } } \ No newline at end of file diff --git a/test/models/shipment.hpp b/test/models/shipment.hpp new file mode 100644 index 0000000..11f0f59 --- /dev/null +++ b/test/models/shipment.hpp @@ -0,0 +1,43 @@ +#ifndef MATADOR_SHIPMENT_HPP +#define MATADOR_SHIPMENT_HPP + +#include "matador/utils/access.hpp" +#include "matador/utils/foreign_attributes.hpp" + +#include "matador/object/collection.hpp" +#include "matador/object/object_ptr.hpp" + +#include + +namespace matador::test { +struct package; +struct shipment { + long id{}; + std::string tracking_number; + object::collection> packages{}; + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::attribute(op, "tracking_number", tracking_number, 255); + field::has_many(op, "packages", packages, "shipment_id", utils::CascadeAllFetchEager); + } +}; + +struct package { + long id{}; + double weight{}; + object::object_ptr delivery; + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::attribute(op, "weight", weight); + field::belongs_to(op, "shipment", delivery, utils::CascadeAllFetchLazy); + } +}; +} + +#endif //MATADOR_SHIPMENT_HPP diff --git a/test/orm/backend/test_result_reader.cpp b/test/orm/backend/test_result_reader.cpp index 7b2b792..eec7bc3 100644 --- a/test/orm/backend/test_result_reader.cpp +++ b/test/orm/backend/test_result_reader.cpp @@ -72,7 +72,7 @@ void test_result_reader::read_value(const char * /*id*/, const size_t /*index*/, value = {12, 34, 56, 123456}; } -void test_result_reader::read_value(const char *id, size_t index, utils::timestamp_type_t &value) { +void test_result_reader::read_value(const char * /*id*/, size_t /*index*/, utils::timestamp_type_t &value) { value = utils::timestamp_type_t(); } diff --git a/test/utils/record_printer.cpp b/test/utils/record_printer.cpp new file mode 100644 index 0000000..85cef80 --- /dev/null +++ b/test/utils/record_printer.cpp @@ -0,0 +1,72 @@ +#include "record_printer.hpp" + +#include "matador/utils/basic_types.hpp" + +#include "matador/sql/record.hpp" + +#include +#include + +namespace matador::test { +record_printer::record_printer(std::ostream &os) +: os_(os) { + type_widths_ = { + {utils::basic_type::Int8, 4}, + {utils::basic_type::Int16, 6}, + {utils::basic_type::Int32, 11}, + {utils::basic_type::Int64, 20}, + {utils::basic_type::UInt8, 4}, + {utils::basic_type::UInt16, 6}, + {utils::basic_type::UInt32, 11}, + {utils::basic_type::UInt64, 20}, + {utils::basic_type::Float, 12}, + {utils::basic_type::Double, 15}, + {utils::basic_type::Boolean, 6}, + {utils::basic_type::Varchar, 20}, + {utils::basic_type::Text, 30}, + {utils::basic_type::Date, 12}, + {utils::basic_type::DateTime, 20}, + {utils::basic_type::Time, 10}, + {utils::basic_type::Blob, 10}, + {utils::basic_type::Null, 6} + }; +} + +void record_printer::print_header(const sql::record &rec) const { + for (const auto &f_ref: rec.columns()) { + const auto &f = f_ref.get(); + os_ << std::left << std::setw(width(f)) << f.name() << " "; + } + os_ << "\n"; + + for (const auto &f_ref: rec.columns()) { + const auto &f = f_ref.get(); + os_ << std::string(width(f), '-') << " "; + } + os_ << "\n"; +} + +void record_printer::print(const sql::record &rec) const { + for (const auto &f_ref: rec.columns()) { + const auto &f = f_ref.get(); + os_ << std::left << std::setw(width(f)) << f.str() << " "; + } + os_ << "\n"; +} + +int record_printer::width(const sql::field &f) { + // If it's a varchar/string and has a defined size, use it if it's reasonable, + // otherwise fall back to type defaults. + if ((f.is_varchar() || f.is_string()) && f.size() > 0 && f.size() < 100) { + return std::max(f.name().length(), f.size()); + } + + // Find the default width for type + // Note: field class doesn't expose basic_type directly but we can use value().type() + // if we had access. For now we use name length as minimum. + constexpr size_t w = 15; + // In a real implementation we would probe the field's underlying type. + + return std::max(f.name().length(), w); +} +} diff --git a/test/utils/record_printer.hpp b/test/utils/record_printer.hpp new file mode 100644 index 0000000..e386973 --- /dev/null +++ b/test/utils/record_printer.hpp @@ -0,0 +1,43 @@ +#ifndef MATADOR_RECORD_PRINTER_HPP +#define MATADOR_RECORD_PRINTER_HPP + +#include "matador/sql/record.hpp" + +#include +#include + +namespace matador::sql { +class field; +class record; +} + +namespace matador::test { +class record_printer final { +public: + explicit record_printer(std::ostream &os); + + void print_header(const sql::record &rec) const; + void print(const sql::record &rec) const; + + template < class Type, template class ContainerType > + void print(ContainerType &records) const { + bool first = true; + for (const auto &rec: records) { + if (first) { + print_header(rec); + first = false; + } + print(rec); + } + } + +private: + [[nodiscard]] static int width(const sql::field &f) ; + +private: + std::ostream &os_; + std::map type_widths_; +}; +} + +#endif //MATADOR_RECORD_PRINTER_HPP diff --git a/todo.md b/todo.md index 116c055..7fbc34d 100644 --- a/todo.md +++ b/todo.md @@ -1,369 +1,36 @@ # Todo -- move `object_definition` and `attribute_definition` to `table` and `column` in query - and add `contraint` class -- replace mk_column with builder style (see `query/builder.hpp`) -- fix corresponding tests -- enhance query helper macro to look like the `book` class below -- add `aliasable_table`(see class below) -- add `as()` methode to table class -- move `sql_function_t` to own header in namespace `matador::sql` - move `prepare_*` methods from `dialect` to `query_compiler` - add `session_insert_builder` and `session_update_builder` (returning multiple statements) -- finish `attribued_definition` (also in `repository` class -> dependencies) -- fix compile errors - finish fetch eager has-many/belongs-to relations - implement lazy loading - implement polymorphic class hierarchies -- finish `schema` and `schema_repository` classes (move add/drop from `session` to `schema`) +- finish `schema_repository` classes (move add/drop from `session` to `schema`) - implement a flag class for enumerations -## book class + +__Proposal for polymorphic classes:__ + +object_ptr::as does the following checks; + +1. The requested type has a super class +2. Super class has a discriminator column defined +3. Super class has a discriminator value defined +4. Discriminator value is mapped to the requested type + +If all checks succeed, the requested is fetched from the database. + ```cpp -class Book : public matador::object::typed_object { -public: - using typed_object::as; - - Book() : typed_object("book") {} - explicit Book(std::string alias) - : typed_object("book", std::move(alias)) {} - - const matador::object::attribute id = create_attribute("id", *this); - const matador::object::attribute title = create_attribute("title", *this); - const matador::object::attribute year = create_attribute("year", *this); -}; +schema.attach("payloads", make_polymorph("type")); +schema.attach("id_list_payloads", make_polymorph_type("IdPayload")); +schema.attach("id_payloads", make_polymorph_type("IdListPayload")); +object::object_ptr payload; +auto result = payload.as(); +if (result.is_ok()) { + const auto& is_payload = result.value(); + // Use requested type + id_payload->id = 1; +} +payload.is_polymorphic(); +payload.is_polymorphic_type(); ``` - -## aliasable_table -```cpp -class object; - -class attribute { -public: - explicit attribute(std::string name); // NOLINT(*-explicit-constructor) - - attribute(const attribute&) = default; - attribute& operator=(const attribute&) = default; - attribute(attribute&&) noexcept = default; - attribute& operator=(attribute&&) noexcept = default; - - attribute() = default; - attribute(std::string name, - utils::basic_type type, - const utils::field_attributes& attr = utils::null_attributes, - utils::null_option_type null_opt = utils::null_option_type::NotNull); - - [[nodiscard]] const std::string& name() const { return name_; } - void name(const std::string& n); - [[nodiscard]] const utils::field_attributes& attributes() const; - [[nodiscard]] utils::field_attributes& attributes(); - - [[nodiscard]] bool is_nullable() const; - [[nodiscard]] utils::basic_type type() const; - - [[nodiscard]] bool is_integer() const; - [[nodiscard]] bool is_floating_point() const; - [[nodiscard]] bool is_bool() const; - [[nodiscard]] bool is_string() const; - [[nodiscard]] bool is_varchar() const; - [[nodiscard]] bool is_date() const; - [[nodiscard]] bool is_time() const; - [[nodiscard]] bool is_blob() const; - [[nodiscard]] bool is_null() const; - -private: - friend class object; - - std::string name_; - std::string alias_; - utils::basic_type type_{utils::basic_type::type_null}; - utils::field_attributes attributes_; - utils::null_option_type null_option_type_{utils::null_option_type::NotNull}; - - object* parent_{nullptr}; -}; - -class constraint { -public: - constraint() = default; - - explicit constraint(std::string name) : name_(std::move(name)) {} - [[nodiscard]] const std::string& name() const { return name_; } - -private: - friend class object; - - std::string name_; - std::string attribute_name_; - utils::constraints options_{utils::constraints::None}; - - object* parent_{nullptr}; -}; - -class object { -public: - using iterator = std::vector::iterator; - using const_iterator = std::vector::const_iterator; - - explicit object(std::string name, std::string alias = ""); - - void add_attribute(attribute attr) { - auto &ref = attributes_.emplace_back(std::move(attr)); - ref.parent_ = this; - } - - static const attribute& create_attribute(std::string name, object& obj) { - attribute attr{std::move(name)}; - attr.parent_ = &obj; - return obj.attributes_.emplace_back(std::move(attr)); - } - - iterator begin() { return attributes_.begin(); } - iterator end() { return attributes_.end(); } - - [[nodiscard]] bool empty() const { return attributes_.empty(); } - [[nodiscard]] size_t size() const { return attributes_.size(); } - - [[nodiscard]] const std::string& name() const { return name_; } - [[nodiscard]] const std::string& alias() const { return alias_; } - [[nodiscard]] const std::vector& columns() const { return attributes_; } - -private: - std::string name_; - std::string alias_; - - std::vector attributes_; -}; - -template -class typed_object : public object { -public: - using object::object; - - Type as(std::string alias) { return Type{std::move(alias)}; } -}; -``` - -```cpp -struct column_builder { - explicit column_builder(std::string column_name) - : column_name( std::move(column_name) ) { - } - - column_builder& not_null() { - return *this; - } - - column_builder& primary_key() { - return *this; - } - - operator matador::sql::column() const { - return matador::sql::column{column_name}; - } - - std::string column_name; -}; - -column_builder column(std::string name) { - return column_builder(std::move(name)); -} - -namespace matador::sql { -struct constraint { - std::string name; -}; -} - -struct constraint_builder { - constraint_builder& constraint(std::string name) { - constraint_name = std::move(name); - return *this; - } - - constraint_builder& primary_key(std::string name) { - pk_column_name = std::move(name); - return *this; - } - constraint_builder& foreign_key(std::string name) { - fk_column_name = std::move(name); - return *this; - } - - constraint_builder& references(std::string table, std::string column) { - this->table_name = std::move(table); - this->column_name = std::move(column); - return *this; - } - - operator matador::sql::constraint() const { - return matador::sql::constraint{constraint_name}; - } - - std::string constraint_name; - std::string pk_column_name; - std::string fk_column_name; - std::string table_name; - std::string column_name; -}; - -constraint_builder constraint(std::string name) { - constraint_builder builder; - return builder.constraint(std::move(name)); -} -void foo(const std::initializer_list columns) { - for (const auto& column : columns) { - std::cout << column.name() << std::endl; - } -} - -void foo(const std::vector& columns) { - for (const auto& column : columns) { - std::cout << column.name() << std::endl; - } -} - -template -std::string column_prefix(matador::sql::aliasable_table *tab) { - if (!tab || tab->empty()) { - return ""; - } - if (!tab->alias().empty()) { - return tab->alias(); - } - return tab->name(); -} -struct table_builder { - explicit table_builder(std::string name) - : table_name( std::move(name) ) {} - - table_builder& as(std::string table_alias) { - this->alias = std::move(table_alias); - return *this; - } - - operator matador::query::query_table() const { - return {matador::sql::table{table_name}, alias}; - } - std::string table_name; - std::string alias; -}; - -table_builder table(std::string name) { - return table_builder(std::move(name)); -} - -class Book : public matador::sql::aliasable_table { -public: - using aliasable_table::as; - - Book() : aliasable_table("book", "") {} - -private: - friend class aliasable_table; - - explicit Book(std::string alias) - : aliasable_table("book", std::move(alias)) {} - -public: - matador::sql::column id = create_column("id", *this); - matador::sql::column title = create_column("title", *this); - matador::sql::column year = create_column("year", *this); -}; - -struct base_node { - base_node() = delete; - base_node(std::string name) - : name(std::move(name)) {} - virtual ~base_node() = default; - - std::string name; -}; -template < typename Type> -struct node final { - virtual ~node() = default; - - Type type; -}; - -template < template typename NodeType = node, typename BaseType = base_node > -struct repository { - template - NodeType find(std::string name); - - std::unordered_map nodes; -}; - -struct base_schema_node : base_node { - base_schema_node() = delete; - base_schema_node(std::string name, std::string table) - : base_node(std::move(name)), table_name(std::move(table)) {} - - std::string table_name; -}; - -template < typename Type > -struct schema_node final : base_schema_node { - schema_node() = default; - schema_node(std::string name, std::string table) - : base_schema_node(std::move(name), std::move(table)) {} - - Type type; -}; - -int main() { - repository repo1; - repository repo; - - Book BOOK; - - const auto b = BOOK.as("b"); - - foo(b); - foo(BOOK); - foo({ - BOOK.id, - b.title, - column("col1").primary_key(), - column("col2").not_null() - }); - matador::sql::schema schema("test"); - - schema.add_table(BOOK.as_table()); - // query::create() - // .table(BOOK) - // .columns({ - // BOOK.id, - // BOOK.title, - // column("year"), - // column("author_id") - // }) - // .constraints({ - // constraint( "PK" ).primary_key("id"), - // constraint( "FK" ).foreign_key("author_id").references("author", "id") - // }); - // - // query::create() - // .table("book", { - // column("id"), - // column("title"), - // column("year"), - // column("author_id") - // }, { - // constraint( "PK" ).primary_key("id"), - // constraint( "FK" ).foreign_key("author_id").references("author", "id") - // }); - // - // matador::query::query_table book = table("book").as("b"); - // - // query::select({ - // column(book.column("id")), - // column(book.column("title")) - // }) - // .from(book); - // - // query::insert() - // .into(b, {b.title, b.year}) - // .values({"title", 2021}); -} -``` \ No newline at end of file