query builder progress
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace matador::object {
|
||||
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,
|
||||
@@ -14,8 +14,9 @@ attribute::attribute(std::string name,
|
||||
const utils::field_attributes &attr,
|
||||
const null_option_type null_opt)
|
||||
: name_(std::move(name))
|
||||
, options_{attr, null_opt}
|
||||
, type_(type)
|
||||
, options_(attr)
|
||||
, null_option_(null_opt)
|
||||
{}
|
||||
|
||||
const std::string &attribute::name() const {
|
||||
@@ -30,20 +31,16 @@ std::string attribute::full_name() const {
|
||||
return owner_ ? owner_->name() + "." + name_ : name_;
|
||||
}
|
||||
|
||||
int attribute::index() const {
|
||||
return options_.index;
|
||||
}
|
||||
|
||||
const utils::field_attributes &attribute::attributes() const {
|
||||
return options_.attributes;
|
||||
return options_;
|
||||
}
|
||||
|
||||
utils::field_attributes& attribute::attributes() {
|
||||
return options_.attributes;
|
||||
return options_;
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -54,16 +51,8 @@ object* attribute::owner() const {
|
||||
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) {
|
||||
options_.attributes = attr;
|
||||
options_ = attr;
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ const std::list<attribute>& basic_object_info::attributes() const {
|
||||
return object_->attributes();
|
||||
}
|
||||
|
||||
const std::list<class constraint>& basic_object_info::constraints() const {
|
||||
return object_->constraints();
|
||||
}
|
||||
|
||||
bool basic_object_info::has_primary_key() const {
|
||||
return object_->has_primary_key();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "matador/object/constraint.hpp"
|
||||
#include "matador/object/attribute.hpp"
|
||||
|
||||
namespace matador::object {
|
||||
constraint::constraint(std::string name)
|
||||
@@ -8,6 +9,49 @@ const std::string & constraint::name() const {
|
||||
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_name = std::move(name);
|
||||
return *this;
|
||||
@@ -35,10 +79,11 @@ constraint_builder & constraint_builder::references(std::string table, std::stri
|
||||
constraint_builder::operator class constraint() const {
|
||||
class constraint c;
|
||||
c.name_ = constraint_name;
|
||||
c.attr_ = column_name;
|
||||
c.options_ = options_;
|
||||
c.ref_column_name_ = ref_column_name;
|
||||
c.ref_table_name_ = ref_table_name;
|
||||
return {};
|
||||
return c;
|
||||
}
|
||||
|
||||
constraint_builder constraint(std::string name) {
|
||||
|
||||
@@ -110,7 +110,7 @@ attribute* repository_node::determine_reference_column(const std::type_index& ti
|
||||
repository& repo) {
|
||||
const auto it = repo.missing_references_.find(ti);
|
||||
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;
|
||||
|
||||
@@ -57,7 +57,9 @@ matador::utils::result<void, matador::utils::error> matador::orm::schema::create
|
||||
// std::cout << result.sql << std::endl;
|
||||
for (const auto &node: repo_) {
|
||||
auto ctx = query::query::create()
|
||||
.table(node->name(), node->info().attributes())
|
||||
.table(node->name())
|
||||
.columns(node->info().attributes())
|
||||
.constraints(node->info().constraints())
|
||||
.compile(*c);
|
||||
|
||||
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();
|
||||
for (const auto &node: *schema_) {
|
||||
auto ctx = query::query::create()
|
||||
.table(node->name(), node->info().attributes())
|
||||
.table(node->name())
|
||||
.columns(node->info().attributes())
|
||||
.constraints(node->info().constraints())
|
||||
.compile(*c);
|
||||
|
||||
for ( const auto& [sql, command] : ctx.additional_commands ) {
|
||||
|
||||
@@ -9,13 +9,14 @@ namespace matador::query {
|
||||
namespace detail {
|
||||
sql::record *create_prototype(const std::vector<object::attribute> &prototype) {
|
||||
auto result = std::make_unique<sql::record>();
|
||||
int index{0};
|
||||
for (const auto &col: prototype) {
|
||||
result->append({
|
||||
col.name(),
|
||||
col.type(),
|
||||
col.attributes().options(),
|
||||
col.attributes().size(),
|
||||
col.index()
|
||||
index++
|
||||
});
|
||||
}
|
||||
return result.release();
|
||||
|
||||
@@ -8,12 +8,8 @@ query_create_intermediate::query_create_intermediate() {
|
||||
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) {
|
||||
return this->table(tab, std::vector<object::attribute>{columns});
|
||||
}
|
||||
|
||||
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));
|
||||
query_create_table_intermediate query_create_intermediate::table(const class table &tab) {
|
||||
context_->parts.push_back(std::make_unique<internal::query_create_table_part>(tab));
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
, table_(std::move(tab))
|
||||
, columns_(std::move(columns)) {}
|
||||
, table_(std::move(tab)) {}
|
||||
|
||||
const table &query_create_table_part::table() const
|
||||
{
|
||||
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_;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ sql::query_context query_compiler::compile(const query_data &data,
|
||||
for (const auto &part: data.parts) {
|
||||
part->accept(*this);
|
||||
}
|
||||
finisher_(query_);
|
||||
connection_ = std::nullopt;
|
||||
dialect_ = 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);
|
||||
}
|
||||
|
||||
struct fk_context {
|
||||
std::string column;
|
||||
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);
|
||||
std::string build_create_column(const object::attribute &col, const sql::dialect &d);
|
||||
std::string build_constraint(const class object::constraint &cons, const sql::dialect &d);
|
||||
|
||||
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();
|
||||
|
||||
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) {
|
||||
for (const auto &col: part.columns()) {
|
||||
result.append(build_create_column(col, *dialect_, context));
|
||||
result.append(build_create_column(col, *dialect_));
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
result.append(", ");
|
||||
result.append(build_create_column(*it, *dialect_, context));
|
||||
result.append(build_create_column(*it, *dialect_));
|
||||
}
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
query_.sql += result;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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());
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return d.token_at(token) + " " +
|
||||
|
||||
@@ -172,6 +172,10 @@ const std::string& dialect::commit() const {
|
||||
return token_at(dialect_token::Commit);
|
||||
}
|
||||
|
||||
const std::string& dialect::constraint() const {
|
||||
return token_at(dialect_token::Constraint);
|
||||
}
|
||||
|
||||
const std::string& dialect::create() const {
|
||||
return token_at(dialect_token::Create);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ namespace matador::sql::detail {
|
||||
template<>
|
||||
record *create_prototype<record>(const std::vector<object::attribute> &prototype) {
|
||||
auto result = std::make_unique<record>();
|
||||
int index{0};
|
||||
for (const auto &col: prototype) {
|
||||
result->append({
|
||||
col.name(),
|
||||
col.type(),
|
||||
col.attributes().options(),
|
||||
col.attributes().size(),
|
||||
col.index()
|
||||
index++
|
||||
});
|
||||
}
|
||||
return result.release();
|
||||
|
||||
Reference in New Issue
Block a user