query builder progress

This commit is contained in:
Sascha Kühl 2025-12-02 16:19:13 +01:00
parent c156ab5e74
commit bfbbd4c589
31 changed files with 348 additions and 164 deletions

View File

@ -240,9 +240,9 @@ utils::result<std::vector<object::attribute>, utils::error> postgres_connection:
// Todo: extract size // Todo: extract size
auto type = (string2type(reader.column(2))); auto type = (string2type(reader.column(2)));
end = nullptr; end = nullptr;
object::null_option_type null_opt{object::null_option_type::NULLABLE}; object::null_option_type null_opt{object::null_option_type::Nullable};
if (strtoul(reader.column(4), &end, 10) == 0) { if (strtoul(reader.column(4), &end, 10) == 0) {
null_opt = object::null_option_type::NOT_NULL; null_opt = object::null_option_type::NotNull;
} }
// f.default_value(res->column(4)); // f.default_value(res->column(4));
prototype.emplace_back(name, type, utils::null_attributes, null_opt, index); prototype.emplace_back(name, type, utils::null_attributes, null_opt, index);

View File

@ -10,14 +10,9 @@
namespace matador::object { namespace matador::object {
enum class null_option_type : uint8_t { enum class null_option_type : uint8_t {
NULLABLE, NOT_NULL Nullable, NotNull
}; };
struct attribute_options {
utils::field_attributes attributes;
null_option_type null_option{null_option_type::NOT_NULL};
int index{-1};
};
class object; class object;
class attribute_generator; class attribute_generator;
@ -33,20 +28,17 @@ public:
attribute() = default; attribute() = default;
attribute(std::string name, attribute(std::string name,
utils::basic_type type, utils::basic_type type,
const utils::field_attributes&, const utils::field_attributes &attr = utils::null_attributes,
null_option_type null_opt); null_option_type null_opt = null_option_type::NotNull);
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
void name(const std::string& n); void name(const std::string& n);
[[nodiscard]] std::string full_name() const; [[nodiscard]] std::string full_name() const;
[[nodiscard]] int index() const;
[[nodiscard]] const utils::field_attributes& attributes() const; [[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] utils::field_attributes& attributes(); [[nodiscard]] utils::field_attributes& attributes();
[[nodiscard]] bool is_nullable() const; [[nodiscard]] bool is_nullable() const;
[[nodiscard]] utils::basic_type type() const; [[nodiscard]] utils::basic_type type() const;
[[nodiscard]] object* owner() const; [[nodiscard]] object* owner() const;
// [[nodiscard]] const std::string& table_name() const;
// void table_name(const std::string& name);
void change_type(utils::basic_type type, const utils::field_attributes &attr = utils::null_attributes); void change_type(utils::basic_type type, const utils::field_attributes &attr = utils::null_attributes);
template < typename Type > template < typename Type >
void change_type(const utils::field_attributes &attr = utils::null_attributes) { void change_type(const utils::field_attributes &attr = utils::null_attributes) {
@ -75,8 +67,9 @@ private:
std::string name_; std::string name_;
object *owner_{nullptr}; object *owner_{nullptr};
attribute_options options_;
utils::basic_type type_{utils::basic_type::type_null}; utils::basic_type type_{utils::basic_type::type_null};
utils::field_attributes options_{};
null_option_type null_option_{null_option_type::NotNull};
}; };

View File

@ -27,7 +27,7 @@ public:
template<class Type> template<class Type>
attribute generate(const char *id, Type &x) { attribute generate(const char *id, Type &x) {
access::process(*this, x); access::process(*this, x);
return attribute{id, type_, {utils::constraints::ForeignKey }, null_option_type::NOT_NULL}; return attribute{id, type_, {utils::constraints::ForeignKey }, null_option_type::NotNull};
} }
template<typename ValueType> template<typename ValueType>
@ -139,18 +139,18 @@ private:
template<typename ValueType> template<typename ValueType>
void attribute_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { void attribute_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NOT_NULL); auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NotNull);
prepare_primary_key(ref, utils::identifier(x)); prepare_primary_key(ref, utils::identifier(x));
} }
template<typename Type> template<typename Type>
void attribute_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) { void attribute_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) {
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NOT_NULL); std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NotNull);
} }
template<typename Type> template<typename Type>
void attribute_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) { void attribute_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) {
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NULLABLE); std::ignore = emplace_attribute<Type>(id, attr, null_option_type::Nullable);
} }
} }

View File

@ -2,6 +2,7 @@
#define BASIC_PROTOTYPE_INFO_HPP #define BASIC_PROTOTYPE_INFO_HPP
#include "matador/object/attribute.hpp" #include "matador/object/attribute.hpp"
#include "matador/object/constraint.hpp"
#include "matador/object/relation_endpoint.hpp" #include "matador/object/relation_endpoint.hpp"
#include "matador/utils/identifier.hpp" #include "matador/utils/identifier.hpp"
@ -26,6 +27,7 @@ public:
[[nodiscard]] std::type_index type_index() const; [[nodiscard]] std::type_index type_index() const;
[[nodiscard]] std::string name() const; [[nodiscard]] std::string name() const;
[[nodiscard]] const std::list<attribute>& attributes() const; [[nodiscard]] const std::list<attribute>& attributes() const;
[[nodiscard]] const std::list<class constraint>& constraints() const;
[[nodiscard]] bool has_primary_key() const; [[nodiscard]] bool has_primary_key() const;
[[nodiscard]] const utils::identifier& primary_key() const; [[nodiscard]] const utils::identifier& primary_key() const;

View File

@ -4,6 +4,7 @@
#include "matador/utils/constraints.hpp" #include "matador/utils/constraints.hpp"
#include <string> #include <string>
#include <variant>
namespace matador::object { namespace matador::object {
@ -18,6 +19,14 @@ public:
explicit constraint(std::string name); explicit constraint(std::string name);
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
[[nodiscard]] const class attribute* attribute() const;
[[nodiscard]] std::string column_name() const;
[[nodiscard]] const object* owner() const;
[[nodiscard]] bool is_primary_key_constraint() const;
[[nodiscard]] bool is_foreign_key_constraint() const;
[[nodiscard]] bool is_unique_constraint() const;
[[nodiscard]] const std::string& ref_table_name() const;
[[nodiscard]] const std::string& ref_column_name() const;
private: private:
friend class constraint_builder; friend class constraint_builder;
@ -26,7 +35,8 @@ private:
friend class object; friend class object;
std::string name_; std::string name_;
attribute* attr_{nullptr}; std::variant<class attribute*, std::string> attr_;
// class attribute* attr_{nullptr};
object *owner_{nullptr}; object *owner_{nullptr};
utils::constraints options_{utils::constraints::None}; utils::constraints options_{utils::constraints::None};
std::string ref_table_name_{}; std::string ref_table_name_{};

View File

@ -88,7 +88,7 @@ public:
template <class Pointer> template <class Pointer>
void on_foreign_key(const char *id, Pointer &/*x*/) { void on_foreign_key(const char *id, Pointer &/*x*/) {
const auto type = pk_type_determinator::determine<typename Pointer::value_type>(); const auto type = pk_type_determinator::determine<typename Pointer::value_type>();
auto &ref = object_->attributes_.emplace_back(id, type, utils::constraints::ForeignKey, null_option_type::NOT_NULL); auto &ref = object_->attributes_.emplace_back(id, type, utils::constraints::ForeignKey, null_option_type::NotNull);
ref.owner_ = object_.get(); ref.owner_ = object_.get();
} }
template<class ContainerType> template<class ContainerType>
@ -121,19 +121,19 @@ private:
template<typename ValueType> template<typename ValueType>
void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NOT_NULL); auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NotNull);
prepare_primary_key(ref, utils::identifier(x)); prepare_primary_key(ref, utils::identifier(x));
create_pk_constraint(id); create_pk_constraint(id);
} }
template<typename Type> template<typename Type>
void object_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) { void object_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) {
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NOT_NULL); std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NotNull);
} }
template<typename Type> template<typename Type>
void object_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) { void object_generator::on_attribute(const char *id, std::optional<Type> & /*x*/, const utils::field_attributes &attr) {
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::NULLABLE); std::ignore = emplace_attribute<Type>(id, attr, null_option_type::Nullable);
} }
} }

View File

@ -272,7 +272,7 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u
append_join( append_join(
query::column{table_info_stack_.top().table, id}, query::column{table_info_stack_.top().table, id},
query::column{next->second, info->get().reference_column()->name()} query::column{next->second, info->get().primary_key_attribute()->name()}
); );
} else { } else {
push(id); push(id);
@ -281,7 +281,7 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u
// create select query // create select query
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy)) auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy))
.from(*foreign_table) .from(*foreign_table)
.where(column(foreign_table, info->get().reference_column()->name(), "") == _) .where(column(foreign_table, info->get().primary_key_attribute()->name(), "") == _)
.prepare(executor_); .prepare(executor_);
if (!result) { if (!result) {
throw query_builder_exception(query_build_error::QueryError, result.release_error()); throw query_builder_exception(query_build_error::QueryError, result.release_error());

View File

@ -26,10 +26,8 @@ private:
class data_type { class data_type {
public: public:
template<typename Type> explicit data_type(const utils::basic_type type, const size_t size = 0)
data_type() : type_(utils::data_type_traits<Type>()) {} : type_(type), size_(size) {}
template<typename Type>
explicit data_type(const size_t size) : type_(utils::data_type_traits<Type>()), size_(size) {}
[[nodiscard]] const utils::basic_type& type() const { return type_; } [[nodiscard]] const utils::basic_type& type() const { return type_; }
[[nodiscard]] size_t size() const { return size_; } [[nodiscard]] size_t size() const { return size_; }
@ -39,10 +37,28 @@ private:
size_t size_{0}; size_t size_{0};
}; };
// using BigInt = data_type<int64_t>(); template<typename Type>
// using Real = data_type<float>; class typed_data_type final : public data_type {
// using double_ = data_type<double>; public:
// using string = data_type<std::string>; typed_data_type()
: data_type(utils::data_type_traits<Type>::type()) {}
};
template<typename Type>
class sized_typed_data_type final : public data_type {
public:
explicit sized_typed_data_type(size_t size)
: data_type(utils::data_type_traits<Type>::type(size), size) {}
};
using BigInt = typed_data_type<int64_t>;
using Integer = typed_data_type<int64_t>;
using Real = typed_data_type<float>;
using Double_ = typed_data_type<double>;
using String = typed_data_type<std::string>;
using Boolean = typed_data_type<bool>;
using Varchar = sized_typed_data_type<std::string>;
class constraint { class constraint {
public: public:
@ -50,7 +66,7 @@ public:
: name_(std::move(name)) {} : name_(std::move(name)) {}
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
[[nodiscard]] const std::string& column_name() const; [[nodiscard]] std::string column_name() const;
[[nodiscard]] const utils::constraints& type() const; [[nodiscard]] const utils::constraints& type() const;
[[nodiscard]] bool is_primary_key_constraint() const; [[nodiscard]] bool is_primary_key_constraint() const;
[[nodiscard]] bool is_foreign_key_constraint() const; [[nodiscard]] bool is_foreign_key_constraint() const;
@ -64,6 +80,7 @@ private:
utils::constraints type_{}; utils::constraints type_{};
std::string referenced_table_; std::string referenced_table_;
std::string referenced_column_; std::string referenced_column_;
data_type dt = Varchar{255};
}; };
} }
namespace matador::query { namespace matador::query {

View File

@ -5,16 +5,32 @@
#include "matador/query/intermediates/executable_query.hpp" #include "matador/query/intermediates/executable_query.hpp"
#include "matador/object/attribute_generator.hpp" #include "matador/object/attribute.hpp"
#include "matador/object/constraint.hpp"
namespace matador::query { namespace matador::query {
class query_create_table_columns_intermediate : public executable_query {
public:
using executable_query::executable_query;
executable_query constraints(std::initializer_list<class object::constraint> constraints);
executable_query constraints(const std::list<class object::constraint> &constraints);
};
class query_create_table_intermediate : public query_intermediate {
public:
using query_intermediate::query_intermediate;
query_create_table_columns_intermediate columns(std::initializer_list<object::attribute> columns);
query_create_table_columns_intermediate columns(const std::list<object::attribute> &columns);
};
class query_create_intermediate : public query_intermediate { class query_create_intermediate : public query_intermediate {
public: public:
query_create_intermediate(); query_create_intermediate();
executable_query table(const table &tab, std::initializer_list<object::attribute> columns); query_create_table_intermediate table(const table &tab);
executable_query table(const query::table &tab, const std::vector<object::attribute> &columns);
executable_query schema(const std::string &schema_name); executable_query schema(const std::string &schema_name);
}; };

View File

@ -10,6 +10,7 @@
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
#include "matador/object/attribute.hpp" #include "matador/object/attribute.hpp"
#include "matador/object/constraint.hpp"
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
@ -364,17 +365,41 @@ private:
class query_create_table_part final : public query_part class query_create_table_part final : public query_part
{ {
public: public:
query_create_table_part(class table tab, std::vector<object::attribute> columns); explicit query_create_table_part(class table tab);
[[nodiscard]] const class table& table() const; [[nodiscard]] const class table& table() const;
[[nodiscard]] const std::vector<object::attribute>& columns() const;
private: private:
void accept(query_part_visitor &visitor) override; void accept(query_part_visitor &visitor) override;
private: private:
class table table_; class table table_;
std::vector<object::attribute> columns_; };
class query_create_table_columns_part final : public query_part {
public:
explicit query_create_table_columns_part(const std::list<object::attribute> &columns);
[[nodiscard]] const std::list<object::attribute>& columns() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::list<object::attribute> columns_;
};
class query_create_table_constraints_part final : public query_part {
public:
explicit query_create_table_constraints_part(const std::list<class object::constraint> &constraints);
[[nodiscard]] const std::list<class object::constraint>& constraints() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::list<class object::constraint> constraints_;
}; };
class query_create_schema_part final : public query_part { class query_create_schema_part final : public query_part {

View File

@ -8,6 +8,7 @@
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
#include <functional>
#include <optional> #include <optional>
namespace matador::sql { namespace matador::sql {
@ -64,6 +65,8 @@ protected:
void visit(internal::query_create_part &part) override; void visit(internal::query_create_part &part) override;
void visit(internal::query_create_table_part &part) override; void visit(internal::query_create_table_part &part) override;
void visit(internal::query_create_table_columns_part& part) override;
void visit(internal::query_create_table_constraints_part& part) override;
void visit(internal::query_create_schema_part& part) override; void visit(internal::query_create_schema_part& part) override;
void visit(internal::query_drop_part &part) override; void visit(internal::query_drop_part &part) override;
@ -79,6 +82,8 @@ protected:
size_t table_index{0}; size_t table_index{0};
const sql::dialect *dialect_{nullptr}; const sql::dialect *dialect_{nullptr};
std::optional<std::reference_wrapper<const sql::connection_impl>> connection_{}; std::optional<std::reference_wrapper<const sql::connection_impl>> connection_{};
std::function<void(sql::query_context&)> finisher_ = [](sql::query_context&) {};
}; };
} }

View File

@ -32,6 +32,8 @@ class query_delete_part;
class query_delete_from_part; class query_delete_from_part;
class query_create_part; class query_create_part;
class query_create_table_part; class query_create_table_part;
class query_create_table_columns_part;
class query_create_table_constraints_part;
class query_create_schema_part; class query_create_schema_part;
class query_drop_part; class query_drop_part;
class query_drop_table_part; class query_drop_table_part;
@ -75,6 +77,8 @@ public:
virtual void visit(internal::query_create_part &part) = 0; virtual void visit(internal::query_create_part &part) = 0;
virtual void visit(internal::query_create_table_part &part) = 0; virtual void visit(internal::query_create_table_part &part) = 0;
virtual void visit(internal::query_create_table_columns_part &part) = 0;
virtual void visit(internal::query_create_table_constraints_part &part) = 0;
virtual void visit(internal::query_create_schema_part &part) = 0; virtual void visit(internal::query_create_schema_part &part) = 0;
virtual void visit(internal::query_drop_part &part) = 0; virtual void visit(internal::query_drop_part &part) = 0;

View File

@ -137,6 +137,7 @@ public:
[[nodiscard]] const std::string& column() const; [[nodiscard]] const std::string& column() const;
[[nodiscard]] const std::string& columns() const; [[nodiscard]] const std::string& columns() const;
[[nodiscard]] const std::string& commit() const; [[nodiscard]] const std::string& commit() const;
[[nodiscard]] const std::string& constraint() const;
[[nodiscard]] const std::string& create() const; [[nodiscard]] const std::string& create() const;
[[nodiscard]] const std::string& desc() const; [[nodiscard]] const std::string& desc() const;
[[nodiscard]] const std::string& distinct() const; [[nodiscard]] const std::string& distinct() const;
@ -201,6 +202,7 @@ private:
{dialect_token::Column, "COLUMN"}, {dialect_token::Column, "COLUMN"},
{dialect_token::Columns, "COLUMNS"}, {dialect_token::Columns, "COLUMNS"},
{dialect_token::Commit, "COMMIT TRANSACTION"}, {dialect_token::Commit, "COMMIT TRANSACTION"},
{dialect_token::Constraint, "CONSTRAINT"},
{dialect_token::Create, "CREATE"}, {dialect_token::Create, "CREATE"},
{dialect_token::Desc, "DESC"}, {dialect_token::Desc, "DESC"},
{dialect_token::Distinct, "DISTINCT"}, {dialect_token::Distinct, "DISTINCT"},

View File

@ -19,6 +19,7 @@ enum class dialect_token : uint8_t {
Column, Column,
Columns, Columns,
Commit, Commit,
Constraint,
Create, Create,
Database, Database,
Desc, Desc,

View File

@ -25,7 +25,8 @@ enum class basic_type : uint8_t {
type_date, /*!< Data type date */ type_date, /*!< Data type date */
type_time, /*!< Data type time */ type_time, /*!< Data type time */
type_blob, /*!< Data type blob */ type_blob, /*!< Data type blob */
type_null /*!< Data type null */ type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */
}; };
} }

View File

@ -19,7 +19,11 @@ class attribute_writer;
* for a data type * for a data type
*/ */
template < class Type, class Enable = void > template < class Type, class Enable = void >
struct data_type_traits; struct data_type_traits {
static basic_type type(std::size_t /*size*/) { return basic_type::type_unknown; }
static void read_value(attribute_reader &/*reader*/, const char *id, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0) {}
static void bind_value(attribute_writer &/*binder*/, size_t index, nullptr_t &/*value*/, size_t /*size*/ = 0) {}
};
} }
#endif //BASIC_TYPE_TRAITS_HPP #endif //BASIC_TYPE_TRAITS_HPP

View File

@ -6,7 +6,7 @@
namespace matador::object { namespace matador::object {
attribute::attribute(std::string name) attribute::attribute(std::string name)
: attribute(std::move(name), utils::basic_type::type_null, {}, null_option_type::NOT_NULL) { : attribute(std::move(name), utils::basic_type::type_null, {}, null_option_type::NotNull) {
} }
attribute::attribute(std::string name, attribute::attribute(std::string name,
@ -14,8 +14,9 @@ attribute::attribute(std::string name,
const utils::field_attributes &attr, const utils::field_attributes &attr,
const null_option_type null_opt) const null_option_type null_opt)
: name_(std::move(name)) : name_(std::move(name))
, options_{attr, null_opt}
, type_(type) , type_(type)
, options_(attr)
, null_option_(null_opt)
{} {}
const std::string &attribute::name() const { const std::string &attribute::name() const {
@ -30,20 +31,16 @@ std::string attribute::full_name() const {
return owner_ ? owner_->name() + "." + name_ : name_; return owner_ ? owner_->name() + "." + name_ : name_;
} }
int attribute::index() const {
return options_.index;
}
const utils::field_attributes &attribute::attributes() const { const utils::field_attributes &attribute::attributes() const {
return options_.attributes; return options_;
} }
utils::field_attributes& attribute::attributes() { utils::field_attributes& attribute::attributes() {
return options_.attributes; return options_;
} }
bool attribute::is_nullable() const { bool attribute::is_nullable() const {
return options_.null_option == null_option_type::NULLABLE; return null_option_ == null_option_type::Nullable;
} }
utils::basic_type attribute::type() const { utils::basic_type attribute::type() const {
@ -54,16 +51,8 @@ object* attribute::owner() const {
return owner_; return owner_;
} }
// const std::string& attribute::table_name() const {
// return owner_ ? owner_->name() : "";
// }
//
// void attribute::table_name( const std::string& name ) {
// table_name_ = name;
// }
void attribute::change_type(const utils::basic_type type, const utils::field_attributes& attr) { void attribute::change_type(const utils::basic_type type, const utils::field_attributes& attr) {
options_.attributes = attr; options_ = attr;
type_ = type; type_ = type;
} }

View File

@ -36,6 +36,10 @@ const std::list<attribute>& basic_object_info::attributes() const {
return object_->attributes(); return object_->attributes();
} }
const std::list<class constraint>& basic_object_info::constraints() const {
return object_->constraints();
}
bool basic_object_info::has_primary_key() const { bool basic_object_info::has_primary_key() const {
return object_->has_primary_key(); return object_->has_primary_key();
} }

View File

@ -1,4 +1,5 @@
#include "matador/object/constraint.hpp" #include "matador/object/constraint.hpp"
#include "matador/object/attribute.hpp"
namespace matador::object { namespace matador::object {
constraint::constraint(std::string name) constraint::constraint(std::string name)
@ -8,6 +9,49 @@ const std::string & constraint::name() const {
return name_; return name_;
} }
const class attribute* constraint::attribute() const {
if (std::holds_alternative<class attribute*>(attr_)) {
return std::get<class attribute*>(attr_);
}
return nullptr;
}
std::string constraint::column_name() const {
if (std::holds_alternative<class attribute*>(attr_)) {
return std::get<class attribute*>(attr_)->name();
}
if (std::holds_alternative<std::string>(attr_)) {
return std::get<std::string>(attr_);
}
return "";
}
const object* constraint::owner() const {
return owner_;
}
bool constraint::is_primary_key_constraint() const {
return utils::is_constraint_set(options_, utils::constraints::PrimaryKey);
}
bool constraint::is_foreign_key_constraint() const {
return utils::is_constraint_set(options_, utils::constraints::ForeignKey);
}
bool constraint::is_unique_constraint() const {
return utils::is_constraint_set(options_, utils::constraints::Unique);
}
const std::string& constraint::ref_table_name() const {
return ref_table_name_;
}
const std::string& constraint::ref_column_name() const {
return ref_column_name_;
}
constraint_builder & constraint_builder::constraint(std::string name) { constraint_builder & constraint_builder::constraint(std::string name) {
constraint_name = std::move(name); constraint_name = std::move(name);
return *this; return *this;
@ -35,10 +79,11 @@ constraint_builder & constraint_builder::references(std::string table, std::stri
constraint_builder::operator class constraint() const { constraint_builder::operator class constraint() const {
class constraint c; class constraint c;
c.name_ = constraint_name; c.name_ = constraint_name;
c.attr_ = column_name;
c.options_ = options_; c.options_ = options_;
c.ref_column_name_ = ref_column_name; c.ref_column_name_ = ref_column_name;
c.ref_table_name_ = ref_table_name; c.ref_table_name_ = ref_table_name;
return {}; return c;
} }
constraint_builder constraint(std::string name) { constraint_builder constraint(std::string name) {

View File

@ -110,7 +110,7 @@ attribute* repository_node::determine_reference_column(const std::type_index& ti
repository& repo) { repository& repo) {
const auto it = repo.missing_references_.find(ti); const auto it = repo.missing_references_.find(ti);
if (it == repo.missing_references_.end()) { if (it == repo.missing_references_.end()) {
return new attribute(pk_info.pk_column_name, pk_info.type, {utils::constraints::ForeignKey}, null_option_type::NOT_NULL); return new attribute(pk_info.pk_column_name, pk_info.type, {utils::constraints::ForeignKey}, null_option_type::NotNull);
} }
auto ref_column = it->second; auto ref_column = it->second;

View File

@ -57,7 +57,9 @@ matador::utils::result<void, matador::utils::error> matador::orm::schema::create
// std::cout << result.sql << std::endl; // std::cout << result.sql << std::endl;
for (const auto &node: repo_) { for (const auto &node: repo_) {
auto ctx = query::query::create() auto ctx = query::query::create()
.table(node->name(), node->info().attributes()) .table(node->name())
.columns(node->info().attributes())
.constraints(node->info().constraints())
.compile(*c); .compile(*c);
for ( const auto& [sql, command] : ctx.additional_commands ) { for ( const auto& [sql, command] : ctx.additional_commands ) {

View File

@ -52,7 +52,9 @@ utils::result<void, utils::error> session::create_schema() const {
auto c = cache_.pool().acquire(); auto c = cache_.pool().acquire();
for (const auto &node: *schema_) { for (const auto &node: *schema_) {
auto ctx = query::query::create() auto ctx = query::query::create()
.table(node->name(), node->info().attributes()) .table(node->name())
.columns(node->info().attributes())
.constraints(node->info().constraints())
.compile(*c); .compile(*c);
for ( const auto& [sql, command] : ctx.additional_commands ) { for ( const auto& [sql, command] : ctx.additional_commands ) {

View File

@ -9,13 +9,14 @@ namespace matador::query {
namespace detail { namespace detail {
sql::record *create_prototype(const std::vector<object::attribute> &prototype) { sql::record *create_prototype(const std::vector<object::attribute> &prototype) {
auto result = std::make_unique<sql::record>(); auto result = std::make_unique<sql::record>();
int index{0};
for (const auto &col: prototype) { for (const auto &col: prototype) {
result->append({ result->append({
col.name(), col.name(),
col.type(), col.type(),
col.attributes().options(), col.attributes().options(),
col.attributes().size(), col.attributes().size(),
col.index() index++
}); });
} }
return result.release(); return result.release();

View File

@ -8,12 +8,8 @@ query_create_intermediate::query_create_intermediate() {
context_->parts.push_back(std::make_unique<internal::query_create_part>()); context_->parts.push_back(std::make_unique<internal::query_create_part>());
} }
executable_query query_create_intermediate::table(const class table &tab, const std::initializer_list<object::attribute> columns) { query_create_table_intermediate query_create_intermediate::table(const class table &tab) {
return this->table(tab, std::vector<object::attribute>{columns}); context_->parts.push_back(std::make_unique<internal::query_create_table_part>(tab));
}
executable_query query_create_intermediate::table(const class table &tab, const std::vector<object::attribute> &columns) {
context_->parts.push_back(std::make_unique<internal::query_create_table_part>(tab, columns));
return {context_}; return {context_};
} }
@ -21,4 +17,24 @@ executable_query query_create_intermediate::schema( const std::string& schema_na
context_->parts.push_back(std::make_unique<internal::query_create_schema_part>(schema_name)); context_->parts.push_back(std::make_unique<internal::query_create_schema_part>(schema_name));
return {context_}; return {context_};
} }
executable_query query_create_table_columns_intermediate::constraints( std::initializer_list<class object::constraint> constraints ) {
return this->constraints(std::list(constraints));
}
executable_query query_create_table_columns_intermediate::constraints( const std::list<class object::constraint>& constraints ) {
context_->parts.push_back(std::make_unique<internal::query_create_table_constraints_part>(constraints));
return {context_};
}
query_create_table_columns_intermediate query_create_table_intermediate::columns( std::initializer_list<object::attribute> columns ) {
context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns));
return {context_};
}
query_create_table_columns_intermediate query_create_table_intermediate::columns( const std::list<object::attribute>& columns ) {
context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns));
return {context_};
}
} }

View File

@ -344,23 +344,41 @@ void query_create_part::accept(query_part_visitor &visitor)
visitor.visit(*this); visitor.visit(*this);
} }
query_create_table_part::query_create_table_part(class table tab, std::vector<object::attribute> columns) query_create_table_part::query_create_table_part(class table tab)
: query_part(sql::dialect_token::Table) : query_part(sql::dialect_token::Table)
, table_(std::move(tab)) , table_(std::move(tab)) {}
, columns_(std::move(columns)) {}
const table &query_create_table_part::table() const const table &query_create_table_part::table() const
{ {
return table_; return table_;
} }
const std::vector<object::attribute> &query_create_table_part::columns() const 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<object::attribute>& columns)
: query_part( sql::dialect_token::Columns )
, columns_(columns){}
const std::list<object::attribute>& query_create_table_columns_part::columns() const {
return columns_; return columns_;
} }
void query_create_table_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<class object::constraint>& constraints)
: query_part( sql::dialect_token::Constraint )
, constraints_(constraints) {}
const std::list<class object::constraint>& query_create_table_constraints_part::constraints() const {
return constraints_;
}
void query_create_table_constraints_part::accept( query_part_visitor& visitor ) {
visitor.visit(*this); visitor.visit(*this);
} }

View File

@ -27,6 +27,7 @@ sql::query_context query_compiler::compile(const query_data &data,
for (const auto &part: data.parts) { for (const auto &part: data.parts) {
part->accept(*this); part->accept(*this);
} }
finisher_(query_);
connection_ = std::nullopt; connection_ = std::nullopt;
dialect_ = nullptr; dialect_ = nullptr;
data_ = nullptr; data_ = nullptr;
@ -289,55 +290,55 @@ void query_compiler::visit(internal::query_create_part &/*create_part*/)
query_.sql = dialect_->token_at(sql::dialect_token::Create); query_.sql = dialect_->token_at(sql::dialect_token::Create);
} }
struct fk_context { std::string build_create_column(const object::attribute &col, const sql::dialect &d);
std::string column; std::string build_constraint(const class object::constraint &cons, const sql::dialect &d);
std::shared_ptr<object::attribute> reference_column;
};
struct column_context
{
std::vector<std::string> primary_keys;
std::vector<fk_context> foreign_contexts;
};
std::string build_create_column(const object::attribute &col, const sql::dialect &d, column_context &context);
void query_compiler::visit(internal::query_create_table_part &part) void query_compiler::visit(internal::query_create_table_part &part)
{ {
query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(part.table().name()) + " "; query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(part.table().name()) + " (";
query_.table_name = part.table().name(); query_.table_name = part.table().name();
std::string result = "("; // if (!context.primary_keys.empty()) {
// result.append(", CONSTRAINT PK_" + part.table().name() + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")");
// }
// for (const auto &[column, reference_column]: context.foreign_contexts) {
// // ALTER TABLE Orders ADD CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID) REFERENCES Persons(PersonID);
// std::string fk_cmd = "ALTER TABLE " + dialect_->prepare_identifier_string(query_.table_name) + " ADD";
// fk_cmd += " CONSTRAINT FK_" + query_.table_name;
// fk_cmd += "_" + column;
// fk_cmd += " FOREIGN KEY (" + dialect_->prepare_identifier_string(column) + ")";
// fk_cmd += " REFERENCES " + reference_column->table_name() + "(" + reference_column->name() + ")";
// query_.additional_commands.push_back({fk_cmd, sql::sql_command::SQL_ALTER_TABLE});
// }
column_context context; finisher_ = [](sql::query_context &ctx) { ctx.sql += ")"; };
}
void query_compiler::visit(internal::query_create_table_columns_part& part) {
std::string result = "(";
if (part.columns().size() < 2) { if (part.columns().size() < 2) {
for (const auto &col: part.columns()) { for (const auto &col: part.columns()) {
result.append(build_create_column(col, *dialect_, context)); result.append(build_create_column(col, *dialect_));
} }
} else { } else {
auto it = part.columns().begin(); auto it = part.columns().begin();
result.append(build_create_column(*it++, *dialect_, context)); result.append(build_create_column(*it++, *dialect_));
for (; it != part.columns().end(); ++it) { for (; it != part.columns().end(); ++it) {
result.append(", "); result.append(", ");
result.append(build_create_column(*it, *dialect_, context)); result.append(build_create_column(*it, *dialect_));
} }
} }
if (!context.primary_keys.empty()) { query_.sql += result;
result.append(", CONSTRAINT PK_" + part.table().name() + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")"); }
}
for (const auto &[column, reference_column]: context.foreign_contexts) {
// ALTER TABLE Orders ADD CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID) REFERENCES Persons(PersonID);
std::string fk_cmd = "ALTER TABLE " + dialect_->prepare_identifier_string(query_.table_name) + " ADD";
fk_cmd += " CONSTRAINT FK_" + query_.table_name;
fk_cmd += "_" + column;
fk_cmd += " FOREIGN KEY (" + dialect_->prepare_identifier_string(column) + ")";
fk_cmd += " REFERENCES " + reference_column->table_name() + "(" + reference_column->name() + ")";
query_.additional_commands.push_back({fk_cmd, sql::sql_command::SQL_ALTER_TABLE});
}
result += ")"; void query_compiler::visit(internal::query_create_table_constraints_part& part) {
std::string result;
for (const auto& c : part.constraints()) {
result.append(", ");
result.append(build_constraint(c, *dialect_));
}
query_.sql += result; query_.sql += result;
} }
@ -387,7 +388,7 @@ void query_compiler::visit(internal::query_drop_table_part &part)
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name); query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name);
} }
std::string build_create_column(const object::attribute &col, const sql::dialect &d, column_context &context) std::string build_create_column(const object::attribute &col, const sql::dialect &d)
{ {
std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type()); std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type());
if (col.attributes().size() > 0) { if (col.attributes().size() > 0) {
@ -399,16 +400,26 @@ std::string build_create_column(const object::attribute &col, const sql::dialect
if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) { if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) {
result.append(" UNIQUE"); result.append(" UNIQUE");
} }
if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) {
context.primary_keys.emplace_back(col.name());
}
if (is_constraint_set(col.attributes().options(), utils::constraints::ForeignKey)) {
context.foreign_contexts.push_back({col.name(), col.reference_column()});
}
return result; return result;
} }
std::string build_constraint(const class object::constraint& cons, const sql::dialect& d) {
std::string result;
if (!cons.name().empty()) {
result.append(d.constraint()).append(" ").append(d.prepare_identifier_string(cons.name())).append(" ");
}
if (cons.is_primary_key_constraint()) {
result.append(d.primary_key());
} else if (cons.is_foreign_key_constraint()) {
result.append(d.foreign_key());
} else {
// handle error
}
result.append("(").append(cons.attribute()->full_name()).append(")");
return result;
}
std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t)
{ {
return d.token_at(token) + " " + return d.token_at(token) + " " +

View File

@ -172,6 +172,10 @@ const std::string& dialect::commit() const {
return token_at(dialect_token::Commit); return token_at(dialect_token::Commit);
} }
const std::string& dialect::constraint() const {
return token_at(dialect_token::Constraint);
}
const std::string& dialect::create() const { const std::string& dialect::create() const {
return token_at(dialect_token::Create); return token_at(dialect_token::Create);
} }

View File

@ -8,13 +8,14 @@ namespace matador::sql::detail {
template<> template<>
record *create_prototype<record>(const std::vector<object::attribute> &prototype) { record *create_prototype<record>(const std::vector<object::attribute> &prototype) {
auto result = std::make_unique<record>(); auto result = std::make_unique<record>();
int index{0};
for (const auto &col: prototype) { for (const auto &col: prototype) {
result->append({ result->append({
col.name(), col.name(),
col.type(), col.type(),
col.attributes().options(), col.attributes().options(),
col.attributes().size(), col.attributes().size(),
col.index() index++
}); });
} }
return result.release(); return result.release();

View File

@ -22,15 +22,15 @@ TEST_CASE("Generate column definitions from object", "[column][definition][gener
auto columns = attribute_generator::generate<matador::test::product>(repo, obj); auto columns = attribute_generator::generate<matador::test::product>(repo, obj);
const std::vector expected_columns = { const std::vector expected_columns = {
attribute{"product_name", basic_type::type_varchar, constraints::PrimaryKey, null_option_type::NOT_NULL }, attribute{"product_name", basic_type::type_varchar, constraints::PrimaryKey, null_option_type::NotNull },
attribute{"supplier_id", basic_type::type_uint32, constraints::ForeignKey, null_option_type::NOT_NULL }, attribute{"supplier_id", basic_type::type_uint32, constraints::ForeignKey, null_option_type::NotNull },
attribute{"category_id", basic_type::type_uint32, constraints::ForeignKey, null_option_type::NOT_NULL }, attribute{"category_id", basic_type::type_uint32, constraints::ForeignKey, null_option_type::NotNull },
attribute{"quantity_per_unit", basic_type::type_varchar, null_attributes, null_option_type::NOT_NULL }, attribute{"quantity_per_unit", basic_type::type_varchar, null_attributes, null_option_type::NotNull },
attribute{"unit_price", basic_type::type_uint32, null_attributes, null_option_type::NOT_NULL }, attribute{"unit_price", basic_type::type_uint32, null_attributes, null_option_type::NotNull },
attribute{"units_in_stock", basic_type::type_uint32, null_attributes, null_option_type::NOT_NULL }, attribute{"units_in_stock", basic_type::type_uint32, null_attributes, null_option_type::NotNull },
attribute{"units_in_order", basic_type::type_uint32, null_attributes, null_option_type::NOT_NULL }, attribute{"units_in_order", basic_type::type_uint32, null_attributes, null_option_type::NotNull },
attribute{"reorder_level", basic_type::type_uint32, null_attributes, null_option_type::NOT_NULL }, attribute{"reorder_level", basic_type::type_uint32, null_attributes, null_option_type::NotNull },
attribute{"discontinued", basic_type::type_bool, null_attributes, null_option_type::NOT_NULL } attribute{"discontinued", basic_type::type_bool, null_attributes, null_option_type::NotNull }
}; };
REQUIRE(!columns.empty()); REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size()); REQUIRE(columns.size() == expected_columns.size());
@ -49,9 +49,9 @@ TEST_CASE("Generate columns from object with nullable columns", "[column generat
auto columns = attribute_generator::generate<matador::test::optional>(repo, obj); auto columns = attribute_generator::generate<matador::test::optional>(repo, obj);
const std::vector expected_columns = { const std::vector expected_columns = {
attribute{"id", basic_type::type_uint32, constraints::PrimaryKey, null_option_type::NOT_NULL }, attribute{"id", basic_type::type_uint32, constraints::PrimaryKey, null_option_type::NotNull },
attribute{"name", basic_type::type_varchar, null_attributes, null_option_type::NOT_NULL }, attribute{"name", basic_type::type_varchar, null_attributes, null_option_type::NotNull },
attribute{"age", basic_type::type_uint32, null_attributes, null_option_type::NOT_NULL } attribute{"age", basic_type::type_uint32, null_attributes, null_option_type::NotNull }
}; };
REQUIRE(!columns.empty()); REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size()); REQUIRE(columns.size() == expected_columns.size());

View File

@ -6,8 +6,6 @@
#include <matador/query/query.hpp> #include <matador/query/query.hpp>
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
#include "matador/object/attribute_generator.hpp"
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
@ -37,21 +35,32 @@ TEST_CASE_METHOD(QueryFixture, "Test alter table sql statement", "[query][alter]
TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query]") { TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query]") {
auto result = query::create() auto result = query::create()
.table({"person"}, { .table({"person"})
make_pk_column<uint32_t>("id"), .columns({
make_column<std::string>("name", 255), attribute("id", basic_type::type_uint32),
make_column<unsigned short>("age") attribute("name", basic_type::type_varchar, 255),
}).str(*db); attribute("age", basic_type::type_uint16)
})
.constraints({
constraint("PK_person").primary_key({"id"})
})
.str(*db);
REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##"); REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
auto ctx = query::create() auto ctx = query::create()
.table("person", { .table("person")
make_pk_column<uint32_t>("id"), .columns({
make_column<std::string>("name", {255, constraints::Unique}, null_option_type::NOT_NULL), attribute("id", basic_type::type_uint32),
make_column<unsigned short>("age"), attribute("name", basic_type::type_varchar, 255),
make_fk_column<uint32_t>("address", "address", "id") attribute("age", basic_type::type_uint16),
}).compile(*db); attribute("address", basic_type::type_uint32)
})
.constraints({
constraint("PK_person").primary_key({"id"}),
constraint("FK_person_address").foreign_key({"address"}).references("address", {"id"})
})
.compile(*db);
REQUIRE(ctx.sql == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL UNIQUE, "age" INTEGER NOT NULL, "address" BIGINT NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##"); REQUIRE(ctx.sql == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL UNIQUE, "age" INTEGER NOT NULL, "address" BIGINT NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##");
REQUIRE(ctx.additional_commands.size() == 1); REQUIRE(ctx.additional_commands.size() == 1);
@ -210,10 +219,14 @@ TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with offset and
TEST_CASE_METHOD(QueryFixture, "Test create, insert and select a blob column", "[query][blob]") { TEST_CASE_METHOD(QueryFixture, "Test create, insert and select a blob column", "[query][blob]") {
auto result = query::create() auto result = query::create()
.table("person", { .table("person")
make_pk_column<uint32_t>("id"), .columns({
make_column<std::string>("name", 255), attribute("id", basic_type::type_uint32),
make_column<blob>("data") attribute("name", basic_type::type_varchar, 255),
attribute("data", basic_type::type_blob)
})
.constraints({
constraint("PK_person").primary_key({"id"})
}) })
.str(*db); .str(*db);

View File

@ -9,9 +9,7 @@ TEST_CASE("Test create empty column", "[column]") {
attribute c("name"); attribute c("name");
REQUIRE(c.name() == "name"); REQUIRE(c.name() == "name");
REQUIRE(c.index() == -1);
REQUIRE(c.type() == basic_type::type_null); REQUIRE(c.type() == basic_type::type_null);
REQUIRE(!c.reference_column());
c.change_type<std::string>(255); c.change_type<std::string>(255);
REQUIRE(c.type() == basic_type::type_varchar); REQUIRE(c.type() == basic_type::type_varchar);
@ -24,39 +22,39 @@ TEST_CASE("Test copy and move column", "[column]") {
attribute c( attribute c(
"name", "name",
basic_type::type_varchar, basic_type::type_varchar,
2, // 2,
std::make_shared<attribute>("author", basic_type::type_uint32, "books", attribute_options{constraints::ForeignKey}), // std::make_shared<attribute>("author", basic_type::type_uint32, "books", attribute_options{constraints::ForeignKey}),
{255, constraints::ForeignKey}, {255, constraints::ForeignKey},
null_option_type::NOT_NULL null_option_type::NotNull
); );
REQUIRE(c.name() == "name"); REQUIRE(c.name() == "name");
REQUIRE(c.index() == 2); // REQUIRE(c.index() == 2);
REQUIRE(c.reference_column()); // REQUIRE(c.reference_column());
REQUIRE(c.reference_column()->name() == "author"); // REQUIRE(c.reference_column()->name() == "author");
REQUIRE(c.reference_column()->table_name() == "books"); // REQUIRE(c.reference_column()->table_name() == "books");
REQUIRE(c.type() == basic_type::type_varchar); REQUIRE(c.type() == basic_type::type_varchar);
REQUIRE(c.attributes().size() == 255); REQUIRE(c.attributes().size() == 255);
auto c2 = c; auto c2 = c;
REQUIRE(c2.name() == "name"); REQUIRE(c2.name() == "name");
REQUIRE(c2.index() == 2); // REQUIRE(c2.index() == 2);
REQUIRE(c2.reference_column()); // REQUIRE(c2.reference_column());
REQUIRE(c2.reference_column()->name() == "author"); // REQUIRE(c2.reference_column()->name() == "author");
REQUIRE(c2.reference_column()->table_name() == "books"); // REQUIRE(c2.reference_column()->table_name() == "books");
REQUIRE(c2.type() == basic_type::type_varchar); REQUIRE(c2.type() == basic_type::type_varchar);
REQUIRE(c2.attributes().size() == 255); REQUIRE(c2.attributes().size() == 255);
auto c3 = std::move(c2); auto c3 = std::move(c2);
REQUIRE(c3.name() == "name"); REQUIRE(c3.name() == "name");
REQUIRE(c3.index() == 2); // REQUIRE(c3.index() == 2);
REQUIRE(c3.reference_column()); // REQUIRE(c3.reference_column());
REQUIRE(c3.reference_column()->name() == "author"); // REQUIRE(c3.reference_column()->name() == "author");
REQUIRE(c3.reference_column()->table_name() == "books"); // REQUIRE(c3.reference_column()->table_name() == "books");
REQUIRE(c3.type() == basic_type::type_varchar); REQUIRE(c3.type() == basic_type::type_varchar);
REQUIRE(c3.attributes().size() == 255); REQUIRE(c3.attributes().size() == 255);
REQUIRE(c2.name().empty()); REQUIRE(c2.name().empty());
REQUIRE(c2.index() == 2); // REQUIRE(c2.index() == 2);
REQUIRE(!c2.reference_column()); // REQUIRE(!c2.reference_column());
REQUIRE(c2.attributes().size() == 255); REQUIRE(c2.attributes().size() == 255);
} }