From 4ed01a617d22889b7730317ade1e9631ae0206d3 Mon Sep 17 00:00:00 2001 From: Sascha Kuehl Date: Sun, 12 Nov 2023 22:27:19 +0100 Subject: [PATCH] added column names and values generator and tests --- CMakeLists.txt | 3 +- include/matador/sql/any_type.hpp | 18 +++++ include/matador/sql/column_generator.hpp | 52 ++++++++++++-- include/matador/sql/column_name_generator.hpp | 59 ++++++++++++++++ include/matador/sql/key_value_pair.hpp | 12 +--- include/matador/sql/query_intermediates.hpp | 6 ++ include/matador/sql/value_generator.hpp | 70 +++++++++++++++++++ src/CMakeLists.txt | 11 ++- src/sql/column_generator.cpp | 63 ++++++++++++++++- src/sql/column_name_generator.cpp | 29 ++++++++ src/sql/value_generator.cpp | 36 ++++++++++ test/CMakeLists.txt | 3 +- test/column_name_generator.cpp | 30 ++++++++ test/session.cpp | 5 +- 14 files changed, 374 insertions(+), 23 deletions(-) create mode 100644 include/matador/sql/any_type.hpp create mode 100644 include/matador/sql/column_name_generator.hpp create mode 100644 include/matador/sql/value_generator.hpp create mode 100644 src/sql/column_name_generator.cpp create mode 100644 src/sql/value_generator.cpp create mode 100644 test/column_name_generator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e65498..bfcc8ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,5 +28,6 @@ add_subdirectory(src) add_subdirectory(test) add_subdirectory(backends) -add_executable(query main.cpp) +add_executable(query main.cpp + include/matador/sql/column_name_generator.hpp) target_link_libraries(query matador) diff --git a/include/matador/sql/any_type.hpp b/include/matador/sql/any_type.hpp new file mode 100644 index 0000000..b8870fc --- /dev/null +++ b/include/matador/sql/any_type.hpp @@ -0,0 +1,18 @@ +#ifndef QUERY_ANY_TYPE_HPP +#define QUERY_ANY_TYPE_HPP + +#include +#include + +namespace matador::sql { + +using any_type = std::variant< + char, short, int, long, long long, + unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, + bool, + float, double, + const char*, + std::string>; + +} +#endif //QUERY_ANY_TYPE_HPP diff --git a/include/matador/sql/column_generator.hpp b/include/matador/sql/column_generator.hpp index 4361d60..95f8b2b 100644 --- a/include/matador/sql/column_generator.hpp +++ b/include/matador/sql/column_generator.hpp @@ -6,16 +6,56 @@ #include "matador/utils/access.hpp" #include "matador/utils/field_attributes.hpp" +#include "matador/utils/identifiable.hpp" +#include "matador/utils/identifier.hpp" #include namespace matador::utils { -class identifiable; enum class cascade_type; } namespace matador::sql { +namespace detail { +class null_identifiable : public utils::identifiable +{ +public: + void reset(const utils::identifier &) override {}; + [[nodiscard]] bool has_primary_key() const override { return false; } + [[nodiscard]] const utils::identifier& primary_key() const override { return id_; } + utils::identifier& primary_key() override { return id_; } + [[nodiscard]] utils::identifier create_identifier() const override { return utils::identifier(id_); } + +private: + utils::identifier id_; +}; + +static null_identifiable null_id; + +} + +class fk_column_generator : public utils::identifier_serializer +{ +public: + column generate(const char *id, utils::identifiable &x); + void serialize(short &i, const utils::field_attributes &attributes) override; + void serialize(int &i, const utils::field_attributes &attributes) override; + void serialize(long &i, const utils::field_attributes &attributes) override; + void serialize(long long int &i, const utils::field_attributes &attributes) override; + void serialize(unsigned short &i, const utils::field_attributes &attributes) override; + void serialize(unsigned int &i, const utils::field_attributes &attributes) override; + void serialize(unsigned long &i, const utils::field_attributes &attributes) override; + void serialize(unsigned long long int &i, const utils::field_attributes &attributes) override; + void serialize(std::string &string, const utils::field_attributes &attributes) override; + void serialize(utils::null_type_t &type, const utils::field_attributes &attributes) override; + +private: + utils::identifiable &identifiable_{detail::null_id}; + const char *id_{}; + column column_; +}; + class column_generator { private: @@ -37,21 +77,23 @@ public: template < class V > void on_primary_key(const char *, V &x, typename std::enable_if::value && !std::is_same::value>::type* = 0); void on_primary_key(const char *id, std::string &pk, size_t size); - void on_revision(const char *id, unsigned long long &/*rev*/); + void on_revision(const char *id, unsigned long long &rev); template void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes); void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type); void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type); -// void on_has_many(const char *, abstract_container &, const char *, const char *, cascade_type) {} -// void on_has_many(const char *, abstract_container &, cascade_type) {} + template + void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {} + template + void on_has_many(const char *, ContainerType &, utils::cascade_type) {} private: size_t index_ = 0; std::vector &columns_; -// typed_column_identifier_serializer column_identifier_serializer_; + fk_column_generator fk_column_generator_; }; template diff --git a/include/matador/sql/column_name_generator.hpp b/include/matador/sql/column_name_generator.hpp new file mode 100644 index 0000000..d8ddb1d --- /dev/null +++ b/include/matador/sql/column_name_generator.hpp @@ -0,0 +1,59 @@ +#ifndef QUERY_COLUMN_NAME_GENERATOR_HPP +#define QUERY_COLUMN_NAME_GENERATOR_HPP + +#include "matador/utils/access.hpp" +#include "matador/utils/field_attributes.hpp" + +#include +#include + +namespace matador::utils { +class identifiable; +} + +namespace matador::sql { + +class column_name_generator +{ +private: + explicit column_name_generator(std::vector &column_names); + +public: + ~column_name_generator() = default; + + template < class Type > + static std::vector generate() + { + std::vector columns; + column_name_generator gen(columns); + Type obj; + matador::utils::access::process(gen, obj); + return std::move(columns); + } + + template < class V > + void on_primary_key(const char *id, V &, typename std::enable_if::value && !std::is_same::value>::type* = 0) + { + column_names_.emplace_back(id); + } + void on_primary_key(const char *id, std::string &, size_t); + void on_revision(const char *id, unsigned long long &/*rev*/); + + template + void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) + { + column_names_.emplace_back(id); + } + + void on_belongs_to(const char *id, utils::identifiable &, utils::cascade_type); + void on_has_one(const char *id, utils::identifiable &, utils::cascade_type); +// void on_has_many(const char *, abstract_container &, const char *, const char *, cascade_type) {} +// void on_has_many(const char *, abstract_container &, cascade_type) {} + +private: + std::vector &column_names_; +}; + +} + +#endif //QUERY_COLUMN_NAME_GENERATOR_HPP diff --git a/include/matador/sql/key_value_pair.hpp b/include/matador/sql/key_value_pair.hpp index d5222b4..fe543a3 100644 --- a/include/matador/sql/key_value_pair.hpp +++ b/include/matador/sql/key_value_pair.hpp @@ -1,20 +1,10 @@ #ifndef QUERY_KEY_VALUE_PAIR_HPP #define QUERY_KEY_VALUE_PAIR_HPP -#include -#include -#include +#include "matador/sql/any_type.hpp" namespace matador::sql { -using any_type = std::variant< - char, short, int, long, long long, - unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, - bool, - float, double, - const char*, - std::string>; - class key_value_pair { public: diff --git a/include/matador/sql/query_intermediates.hpp b/include/matador/sql/query_intermediates.hpp index c06ba03..7fe0240 100644 --- a/include/matador/sql/query_intermediates.hpp +++ b/include/matador/sql/query_intermediates.hpp @@ -3,6 +3,7 @@ #include "matador/sql/column.hpp" #include "matador/sql/column_generator.hpp" +#include "matador/sql/column_name_generator.hpp" #include "matador/sql/key_value_pair.hpp" #include "matador/sql/query_result.hpp" #include "matador/sql/record.hpp" @@ -158,6 +159,11 @@ public: using query_intermediate::query_intermediate; query_into_intermediate into(const std::string &table, std::initializer_list column_names); + template + query_into_intermediate into(const std::string &table) + { + return into(table, column_name_generator::generate()); + } }; class query_execute_where_intermediate : public query_execute_finish diff --git a/include/matador/sql/value_generator.hpp b/include/matador/sql/value_generator.hpp new file mode 100644 index 0000000..f9b315e --- /dev/null +++ b/include/matador/sql/value_generator.hpp @@ -0,0 +1,70 @@ +#ifndef QUERY_VALUE_GENERATOR_HPP +#define QUERY_VALUE_GENERATOR_HPP + +#include "matador/sql/any_type.hpp" + +#include "matador/utils/access.hpp" +#include "matador/utils/field_attributes.hpp" +#include "matador/utils/identifiable.hpp" + +#include + +namespace matador::utils { +enum class cascade_type; +} +namespace matador::sql { + +class value_generator +{ +private: + explicit value_generator(std::vector &values); + +public: + ~value_generator() = default; + + template < class Type > + static std::vector generate() + { + std::vector values; + value_generator gen(values); + Type obj; + matador::utils::access::process(gen, obj); + return std::move(values); + } + + template + void on_primary_key(const char *, ValueType &x, typename std::enable_if::value && !std::is_same::value>::type* = 0) + { + append(x); + } + void on_primary_key(const char *id, std::string &pk, size_t size); + void on_revision(const char *id, unsigned long long &rev); + template < class Type > + void on_attribute(const char *, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) + { + append(x); + } + void on_attribute(const char *id, char *x, const utils::field_attributes &/*attr*/ = utils::null_attributes); + void on_attribute(const char *id, std::string &x, const utils::field_attributes &/*attr*/ = utils::null_attributes); + void on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type); + void on_has_one(const char *id, utils::identifiable &x, utils::cascade_type); + + template + void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {} + template + void on_has_many(const char *, ContainerType &, utils::cascade_type) {} + +private: + template + void append(Type &value) + { + values_.emplace_back(value); + } + +private: + std::vector &values_; +}; + +} + +#endif //QUERY_VALUE_GENERATOR_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c485b2..3f28e16 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,8 @@ set(SQL_SOURCES sql/session.cpp sql/backend_provider.cpp sql/query_result_impl.cpp - sql/column_generator.cpp) + sql/column_generator.cpp + sql/column_name_generator.cpp) set(SQL_HEADER ../include/matador/sql/dialect.hpp @@ -33,7 +34,10 @@ set(SQL_HEADER ../include/matador/sql/session.hpp ../include/matador/sql/backend_provider.hpp ../include/matador/sql/query_result_impl.hpp - ../include/matador/sql/column_generator.hpp) + ../include/matador/sql/column_generator.hpp + ../include/matador/sql/column_name_generator.hpp + ../include/matador/sql/value_generator.hpp + ../include/matador/sql/any_type.hpp) set(UTILS_HEADER ../include/matador/utils/field_attributes.hpp @@ -52,7 +56,8 @@ set(UTILS_SOURCES sql/condition.cpp utils/library.cpp utils/os.cpp - utils/identifier.cpp) + utils/identifier.cpp + sql/value_generator.cpp) add_library(matador STATIC ${SQL_SOURCES} ${SQL_HEADER} ${UTILS_SOURCES} ${UTILS_HEADER}) target_include_directories(matador PUBLIC ${PROJECT_SOURCE_DIR}/include) diff --git a/src/sql/column_generator.cpp b/src/sql/column_generator.cpp index 7599f7d..bbb22bc 100644 --- a/src/sql/column_generator.cpp +++ b/src/sql/column_generator.cpp @@ -1,5 +1,7 @@ #include "matador/sql/column_generator.hpp" +#include "matador/utils/identifiable.hpp" + namespace matador::sql { column_generator::column_generator(std::vector &columns) @@ -17,7 +19,8 @@ void column_generator::on_revision(const char *id, unsigned long long int &x) void column_generator::on_belongs_to(const char *id, utils::identifiable &x, utils::cascade_type) { - + columns_.push_back(fk_column_generator_.generate(id, x)); +// x.primary_key().serialize(fk_column_generator) } void column_generator::on_has_one(const char *id, utils::identifiable &x, utils::cascade_type) @@ -25,4 +28,62 @@ void column_generator::on_has_one(const char *id, utils::identifiable &x, utils: } +column fk_column_generator::generate(const char *id, utils::identifiable &x) +{ + identifiable_ = x; + id_ = id; + x.primary_key().serialize(*this); + return column_; +} + +void fk_column_generator::serialize(short &i, const utils::field_attributes &attributes) +{ + column_. + +} + +void fk_column_generator::serialize(int &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(long &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(long long int &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(unsigned short &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(unsigned int &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(unsigned long &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(unsigned long long int &i, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(std::string &string, const utils::field_attributes &attributes) +{ + +} + +void fk_column_generator::serialize(utils::null_type_t &type, const utils::field_attributes &attributes) +{ + +} } \ No newline at end of file diff --git a/src/sql/column_name_generator.cpp b/src/sql/column_name_generator.cpp new file mode 100644 index 0000000..920e074 --- /dev/null +++ b/src/sql/column_name_generator.cpp @@ -0,0 +1,29 @@ +#include "matador/sql/column_name_generator.hpp" + +namespace matador::sql { + +column_name_generator::column_name_generator(std::vector &column_names) +: column_names_(column_names) +{} + +void column_name_generator::on_primary_key(const char *id, std::string &, size_t) +{ + column_names_.emplace_back(id); +} + +void column_name_generator::on_revision(const char *id, unsigned long long int &) +{ + column_names_.emplace_back(id); +} + +void column_name_generator::on_belongs_to(const char *id, utils::identifiable &, utils::cascade_type) +{ + column_names_.emplace_back(id); +} + +void column_name_generator::on_has_one(const char *id, utils::identifiable &, utils::cascade_type) +{ + column_names_.emplace_back(id); +} + +} \ No newline at end of file diff --git a/src/sql/value_generator.cpp b/src/sql/value_generator.cpp new file mode 100644 index 0000000..0d5d253 --- /dev/null +++ b/src/sql/value_generator.cpp @@ -0,0 +1,36 @@ +#include "matador/sql/value_generator.hpp" + +namespace matador::sql { + +value_generator::value_generator(std::vector &values) +: values_(values) +{} + +void value_generator::on_primary_key(const char *, std::string &pk, size_t) +{ + append(pk); +} + +void value_generator::on_revision(const char *, unsigned long long int &rev) +{ + append(rev); +} + +void value_generator::on_attribute(const char *, char *x, const utils::field_attributes &) +{ + append(x); +} + +void value_generator::on_attribute(const char *, std::string &x, const utils::field_attributes &) +{ + append(x); +} + +void value_generator::on_belongs_to(const char *, utils::identifiable &x, utils::cascade_type) { + +} + +void value_generator::on_has_one(const char *, utils::identifiable &x, utils::cascade_type) { + +} +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d6a7734..57ef395 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,8 @@ add_executable(tests builder.cpp backend_provider.cpp connection.cpp product.hpp - column_generator.cpp) + column_generator.cpp + column_name_generator.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain matador diff --git a/test/column_name_generator.cpp b/test/column_name_generator.cpp new file mode 100644 index 0000000..2e03605 --- /dev/null +++ b/test/column_name_generator.cpp @@ -0,0 +1,30 @@ +#include + +#include "matador/sql/column_name_generator.hpp" + +#include "product.hpp" + +using namespace matador::sql; + +TEST_CASE("Generate column names from object", "[column name generator]") { + + auto columns = column_name_generator::generate(); + + const std::vector expected_columns = { + "product_name", + "supplier_id", + "category_id", + "quantity_per_unit", + "unit_price", + "units_in_stock", + "units_in_order", + "reorder_level", + "discontinued" + }; + REQUIRE(!columns.empty()); + REQUIRE(columns.size() == expected_columns.size()); + + for (size_t i = 0; i != expected_columns.size(); ++i) { + REQUIRE(expected_columns[i] == columns[i]); + } +} diff --git a/test/session.cpp b/test/session.cpp index 37bc385..a6775dc 100644 --- a/test/session.cpp +++ b/test/session.cpp @@ -7,6 +7,7 @@ #include "product.hpp" using namespace matador::sql; +using namespace matador::test; TEST_CASE("Execute create table statement", "[connection]") { connection_pool pool("sqlite://sqlite.db", 4); @@ -21,7 +22,9 @@ TEST_CASE("Execute create table statement", "[connection]") { REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL PRIMARY KEY, "name" VARCHAR(255), "age" INTEGER))"); - res = s.create().table("product").execute(); + res = s.create().table("product").execute(); + + REQUIRE(res.second == R"(CREATE TABLE "person" ("id" BIGINT NOT NULL PRIMARY KEY, "name" VARCHAR(255), "age" INTEGER))"); } TEST_CASE("Execute drop table statement", "[connection]") {