# 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`) - implement a flag class for enumerations ## book class ```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); }; ``` ## 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}); } ```