query/todo.md

9.9 KiB

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

class Book : public matador::object::typed_object<Book> {
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

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<attribute>::iterator;
    using const_iterator = std::vector<attribute>::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<attribute>& columns() const { return attributes_; }

private:
  std::string name_;
  std::string alias_;

  std::vector<attribute> attributes_;
};

template<typename Type>
class typed_object : public object {
public:
    using object::object;

    Type as(std::string alias) { return Type{std::move(alias)}; }
};
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<matador::sql::column> columns) {
    for (const auto& column : columns) {
        std::cout << column.name() << std::endl;
    }
}

void foo(const std::vector<matador::sql::column>& columns) {
    for (const auto& column : columns) {
        std::cout << column.name() << std::endl;
    }
}

template<typename Type>
std::string column_prefix(matador::sql::aliasable_table<Type> *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<Book> {
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> typename NodeType = node, typename BaseType = base_node >
struct repository {
    template<typename Type>
    NodeType<Type> find(std::string name);

    std::unordered_map<std::string, BaseType> 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<schema_node, base_schema_node> 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});
}