query builder progress
This commit is contained in:
parent
c156ab5e74
commit
bfbbd4c589
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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_{};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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&) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"},
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ enum class dialect_token : uint8_t {
|
||||||
Column,
|
Column,
|
||||||
Columns,
|
Columns,
|
||||||
Commit,
|
Commit,
|
||||||
|
Constraint,
|
||||||
Create,
|
Create,
|
||||||
Database,
|
Database,
|
||||||
Desc,
|
Desc,
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 ) {
|
||||||
|
|
|
||||||
|
|
@ -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 ) {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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_};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,13 +400,23 @@ 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());
|
return result;
|
||||||
}
|
|
||||||
if (is_constraint_set(col.attributes().options(), utils::constraints::ForeignKey)) {
|
|
||||||
context.foreign_contexts.push_back({col.name(), col.reference_column()});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue