schema progress (does not compile)
This commit is contained in:
@@ -227,7 +227,7 @@ query::fetchable_query session::build_select_query(entity_query_data &&data) {
|
||||
.from(*data.root_table)
|
||||
.join_left(data.joins)
|
||||
.where(std::move(data.where_clause))
|
||||
.order_by({data.root_table.get(), data.pk_column_name})
|
||||
.order_by({data.root_table, data.pk_column_name})
|
||||
.asc();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <iostream>
|
||||
|
||||
namespace matador::orm {
|
||||
criteria_transformer::criteria_transformer(const query::schema& repo, const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name)
|
||||
criteria_transformer::criteria_transformer(const query::schema& repo, const std::unordered_map<std::string, query::table>& tables_by_name)
|
||||
: repo_(repo)
|
||||
, tables_by_name_(tables_by_name) {}
|
||||
|
||||
@@ -39,12 +39,15 @@ void criteria_transformer::visit( const query::not_criteria& node ) {
|
||||
}
|
||||
|
||||
void criteria_transformer::update_criteria_column(const query::abstract_column_criteria& node) const {
|
||||
const auto it = tables_by_name_.find(node.col().table()->name());
|
||||
if (it == tables_by_name_.end()) {
|
||||
return;
|
||||
}
|
||||
if (node.col().table() == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto it = tables_by_name_.find(node.col().table()->name());
|
||||
if (it == tables_by_name_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const_cast<query::column&>(node.col()).table(it->second.get());
|
||||
const_cast<query::column&>(node.col()).table(&it->second);
|
||||
}
|
||||
|
||||
void session_query_builder::on_revision(const char *id, uint64_t &/*rev*/) {
|
||||
@@ -52,11 +55,11 @@ void session_query_builder::on_revision(const char *id, uint64_t &/*rev*/) {
|
||||
}
|
||||
|
||||
void session_query_builder::push(const std::string &column_name) {
|
||||
const auto it = processed_tables_.find(table_info_stack_.top().info.get().name());
|
||||
const auto it = processed_tables_.find(table_info_stack_.top().info.name());
|
||||
if (it == processed_tables_.end()) {
|
||||
throw query_builder_exception{query_build_error::UnexpectedError};
|
||||
}
|
||||
entity_query_data_.columns.emplace_back(it->second.get(), column_name, build_alias('c', ++column_index));
|
||||
entity_query_data_.columns.emplace_back(&it->second, column_name, build_alias('c', ++column_index));
|
||||
}
|
||||
|
||||
std::string session_query_builder::build_alias(const char prefix, const unsigned int count) {
|
||||
|
||||
@@ -4,52 +4,61 @@ namespace matador::query {
|
||||
|
||||
column_builder::column_builder(std::string column_name, const utils::basic_type type, const size_t size)
|
||||
: column_name_(std::move(column_name))
|
||||
, type_(type){}
|
||||
, type_(type)
|
||||
, size_(size) {}
|
||||
|
||||
column_builder::operator class query::column() const {
|
||||
return {column_name_};
|
||||
return {nullptr, column_name_, type_, {size_, constraints_}};
|
||||
}
|
||||
|
||||
column_builder& column_builder::not_null() {
|
||||
constraints_ |= utils::constraints::NotNull;
|
||||
return *this;
|
||||
}
|
||||
|
||||
return *this;
|
||||
column_builder & column_builder::primary_key() {
|
||||
constraints_ |= utils::constraints::PrimaryKey;
|
||||
return *this;
|
||||
}
|
||||
|
||||
column_builder & column_builder::unique() {
|
||||
constraints_ |= utils::constraints::Unique;
|
||||
return *this;
|
||||
}
|
||||
|
||||
table_builder::table_builder(std::string name)
|
||||
: table_name( std::move(name) ) {}
|
||||
|
||||
table_builder& table_builder::as( std::string table_alias ) {
|
||||
this->alias = std::move(table_alias);
|
||||
return *this;
|
||||
}
|
||||
|
||||
table_builder::operator class query::table() const {
|
||||
return {table_name, alias, {}};
|
||||
return {table_name, {}};
|
||||
}
|
||||
|
||||
constraint_builder& constraint_builder::constraint( std::string name ) {
|
||||
constraint_name = std::move(name);
|
||||
constraint_name_ = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constraint_builder& constraint_builder::primary_key( std::string name ) {
|
||||
pk_column_name = std::move(name);
|
||||
column_name_ = std::move(name);
|
||||
type_ = utils::constraints::PrimaryKey;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constraint_builder& constraint_builder::foreign_key( std::string name ) {
|
||||
fk_column_name = std::move(name);
|
||||
column_name_ = std::move(name);
|
||||
type_ = utils::constraints::ForeignKey;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constraint_builder& constraint_builder::references( std::string table, std::string column ) {
|
||||
this->table_name = std::move(table);
|
||||
this->column_name = std::move(column);
|
||||
this->ref_table_name_ = std::move(table);
|
||||
this->ref_column_name_ = std::move(column);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constraint_builder::operator class constraint() const {
|
||||
return {};
|
||||
return {constraint_name_, column_name_, ref_table_name_, type_, ref_table_name_, ref_column_name_};
|
||||
}
|
||||
|
||||
constraint_builder constraint( std::string name ) {
|
||||
|
||||
+49
-20
@@ -18,7 +18,7 @@ column operator ""_col(const char *name, const size_t len) {
|
||||
throw std::invalid_argument("Invalid column name: multiple dots found");
|
||||
}
|
||||
|
||||
return column{new table(str.substr(0, pos)), str.substr(pos + 1)};
|
||||
return column{str.substr(pos + 1)};
|
||||
}
|
||||
|
||||
column::column(const char *name)
|
||||
@@ -26,27 +26,25 @@ column::column(const char *name)
|
||||
{}
|
||||
|
||||
column::column(std::string name)
|
||||
: table_(default_table())
|
||||
, name_(std::move(name)) {}
|
||||
: name_(std::move(name)) {}
|
||||
column::column(std::string name, std::string alias)
|
||||
: table_(default_table())
|
||||
, name_(std::move(name))
|
||||
: name_(std::move(name))
|
||||
, alias_(std::move(alias)) {}
|
||||
|
||||
column::column(const sql::sql_function_t func, std::string name)
|
||||
: table_(default_table())
|
||||
, name_(std::move(name))
|
||||
: name_(std::move(name))
|
||||
, function_(func) {}
|
||||
|
||||
column::column(const class table* tab, std::string name)
|
||||
: table_(tab)
|
||||
, name_(std::move(name)) {}
|
||||
|
||||
column::column(const class query::table* tab, std::string name, std::string alias)
|
||||
column::column(const class table* tab, std::string name, std::string alias)
|
||||
: table_(tab)
|
||||
, name_(std::move(name))
|
||||
, alias_(std::move(alias)) {}
|
||||
column::column(const class query::table* tab, std::string name,
|
||||
column::column(const class table* tab,
|
||||
std::string name,
|
||||
const utils::basic_type type,
|
||||
const utils::field_attributes& attributes)
|
||||
: table_(tab)
|
||||
@@ -54,16 +52,53 @@ column::column(const class query::table* tab, std::string name,
|
||||
, type_(type)
|
||||
, attributes_(attributes) {}
|
||||
|
||||
column::column(const class table* tab,
|
||||
std::string name,
|
||||
std::string alias,
|
||||
utils::basic_type type,
|
||||
const utils::field_attributes &attributes)
|
||||
: table_(tab)
|
||||
, name_(std::move(name))
|
||||
, alias_(std::move(alias))
|
||||
, type_(type)
|
||||
, attributes_(attributes) {}
|
||||
|
||||
column & column::operator=(const column &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
table_ = other.table_;
|
||||
name_ = other.name_;
|
||||
alias_ = other.alias_;
|
||||
type_ = other.type_;
|
||||
attributes_ = other.attributes_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
column::column(const column &other)
|
||||
: table_(other.table_)
|
||||
, name_(other.name_)
|
||||
, alias_(other.alias_)
|
||||
, type_(other.type_)
|
||||
, attributes_(other.attributes_) {
|
||||
}
|
||||
|
||||
bool column::equals(const column &x) const {
|
||||
return *table_ == *x.table_ &&
|
||||
name_ == x.name_ &&
|
||||
alias_ == x.alias_ &&
|
||||
function_ == x.function_;
|
||||
if (table_ != nullptr && x.table_ != nullptr) {
|
||||
return *table_ == *x.table_ &&
|
||||
name_ == x.name_ &&
|
||||
alias_ == x.alias_ &&
|
||||
function_ == x.function_;
|
||||
}
|
||||
|
||||
return name_ == x.name_ &&
|
||||
alias_ == x.alias_ &&
|
||||
function_ == x.function_;
|
||||
}
|
||||
|
||||
column column::as(std::string a) {
|
||||
alias_ = std::move(a);
|
||||
return *this;
|
||||
return {table_, name_, alias_, type_, attributes_};
|
||||
}
|
||||
|
||||
const std::string& column::name() const {
|
||||
@@ -109,10 +144,4 @@ void column::table(const query::table* tab) {
|
||||
column::operator const std::string&() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
query::table* column::default_table() {
|
||||
static query::table default_table;
|
||||
|
||||
return &default_table;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,23 @@ constraint::constraint(std::string column_name, std::string table_name, utils::c
|
||||
, referenced_table_(std::move(referenced_table))
|
||||
, referenced_column_(std::move(referenced_column)) {}
|
||||
|
||||
constraint::constraint(std::string name,
|
||||
std::string column_name,
|
||||
std::string table_name,
|
||||
utils::constraints type,
|
||||
std::string referenced_table,
|
||||
std::string referenced_column)
|
||||
: name_(std::move(name))
|
||||
, column_name_(std::move(column_name))
|
||||
, table_name_(std::move(table_name))
|
||||
, type_(type)
|
||||
, referenced_table_(std::move(referenced_table))
|
||||
, referenced_column_(std::move(referenced_column)) {}
|
||||
|
||||
std::string constraint::name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string constraint::column_name() const {
|
||||
return column_name_;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "matador/query/criteria/abstract_column_criteria.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
abstract_column_criteria::abstract_column_criteria(column col)
|
||||
: column_(std::move(col)) {}
|
||||
abstract_column_criteria::abstract_column_criteria(const class column& col)
|
||||
: column_(col) {}
|
||||
|
||||
const column& abstract_column_criteria::col() const {
|
||||
return column_;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#include "matador/query/criteria/criteria_visitor.hpp"
|
||||
|
||||
namespace matador::query{
|
||||
between_criteria::between_criteria(column col, const int64_t min, const int64_t max)
|
||||
: abstract_column_criteria(std::move(col))
|
||||
between_criteria::between_criteria(const class column& col, const int64_t min, const int64_t max)
|
||||
: abstract_column_criteria(col)
|
||||
, min_(utils::value{min})
|
||||
, max_(utils::value{max})
|
||||
{}
|
||||
|
||||
between_criteria::between_criteria(column col, utils::placeholder min, utils::placeholder max)
|
||||
: abstract_column_criteria(std::move(col))
|
||||
between_criteria::between_criteria(const class column& col, utils::placeholder min, utils::placeholder max)
|
||||
: abstract_column_criteria(col)
|
||||
, min_(min)
|
||||
, max_(max)
|
||||
{}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "matador/query/criteria/criteria_visitor.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
binary_criteria::binary_criteria(column col, const binary_operator operand, criteria_value value)
|
||||
: abstract_column_criteria(std::move(col))
|
||||
binary_criteria::binary_criteria(const class column& col, const binary_operator operand, criteria_value value)
|
||||
: abstract_column_criteria(col)
|
||||
, operator_(operand)
|
||||
, value_(std::move(value))
|
||||
{}
|
||||
@@ -21,16 +21,16 @@ const criteria_value& binary_criteria::value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
binary_column_criteria::binary_column_criteria(column left_column, binary_operator operand, column right_column)
|
||||
: left_column_(std::move(left_column))
|
||||
binary_column_criteria::binary_column_criteria(const class column& left_column, const binary_operator operand, const class column& right_column)
|
||||
: left_column_(left_column)
|
||||
, operator_(operand)
|
||||
, right_column_(std::move(right_column)){}
|
||||
, right_column_(right_column){}
|
||||
|
||||
void binary_column_criteria::accept(criteria_visitor& visitor) const {
|
||||
visitor.visit(*this);
|
||||
}
|
||||
|
||||
const column& binary_column_criteria::left_column() const {
|
||||
const class column& binary_column_criteria::left_column() const {
|
||||
return left_column_;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ binary_operator binary_column_criteria::operand() const {
|
||||
return operator_;
|
||||
}
|
||||
|
||||
const column& binary_column_criteria::right_column() const {
|
||||
const class column& binary_column_criteria::right_column() const {
|
||||
return right_column_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#include "matador/query/criteria/collection_criteria.hpp"
|
||||
|
||||
#include "matador/query/criteria/criteria_visitor.hpp"
|
||||
#include "matador/query/column.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
collection_criteria::collection_criteria(column col, const collection_operator operand_, std::vector<criteria_value> values )
|
||||
: abstract_column_criteria(std::move(col))
|
||||
collection_criteria::collection_criteria(const class column& col, const collection_operator operand_, std::vector<criteria_value> values )
|
||||
: abstract_column_criteria(col)
|
||||
, operand_(operand_)
|
||||
, values_(std::move(values))
|
||||
{}
|
||||
|
||||
collection_criteria::collection_criteria(column col, const collection_operator operand_, const std::initializer_list<criteria_value> values )
|
||||
: abstract_column_criteria(std::move(col))
|
||||
collection_criteria::collection_criteria(const class column& col, const collection_operator operand_, const std::initializer_list<criteria_value> values )
|
||||
: abstract_column_criteria(col)
|
||||
, operand_(operand_)
|
||||
, values_(values)
|
||||
{}
|
||||
@@ -27,8 +28,8 @@ const std::vector<criteria_value>& collection_criteria::values() const {
|
||||
return values_;
|
||||
}
|
||||
|
||||
collection_query_criteria::collection_query_criteria(column col, collection_operator operand_, sql::query_context ctx)
|
||||
: abstract_column_criteria(std::move(col))
|
||||
collection_query_criteria::collection_query_criteria(const class column& col, collection_operator operand_, sql::query_context ctx)
|
||||
: abstract_column_criteria(col)
|
||||
, operand_(operand_)
|
||||
, query_context_(std::move(ctx)){
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "matador/query/criteria/like_criteria.hpp"
|
||||
|
||||
#include "matador/query/criteria/criteria_visitor.hpp"
|
||||
#include "matador/query/column.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
like_criteria::like_criteria(column col, std::string pattern)
|
||||
: abstract_column_criteria(std::move(col))
|
||||
like_criteria::like_criteria(const class column& col, std::string pattern)
|
||||
: abstract_column_criteria(col)
|
||||
, pattern_(std::move(pattern)){}
|
||||
|
||||
void like_criteria::accept(criteria_visitor &visitor) const {
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
#include "matador/query/generator.hpp"
|
||||
|
||||
namespace matador::query::generator {
|
||||
column_generator::column_generator(const std::string& table_name, const column_generator_options options)
|
||||
: options_(options) {
|
||||
table_stack_.push(table_name.empty() ? std::make_shared<table>() : std::make_shared<table>(table_name));
|
||||
}
|
||||
|
||||
column_generator::column_generator(const schema& repo, const std::string& table_name, const column_generator_options options)
|
||||
: repo_(std::cref(repo))
|
||||
, options_(options) {
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "matador/query/constraint.hpp"
|
||||
|
||||
#include "matador/object/object.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace matador::query {
|
||||
@@ -26,41 +28,55 @@ executable_query query_create_table_columns_intermediate::constraints(const std:
|
||||
return this->constraints(std::list(constraints));
|
||||
}
|
||||
|
||||
executable_query query_create_table_columns_intermediate::constraints(std::initializer_list<constraint> constraints) {
|
||||
return {context_};
|
||||
executable_query query_create_table_columns_intermediate::constraints(const std::initializer_list<constraint> constraints) {
|
||||
return this->constraints(std::list(constraints));
|
||||
}
|
||||
|
||||
executable_query query_create_table_columns_intermediate::constraints(const std::list<constraint>& restrictions){
|
||||
executable_query query_create_table_columns_intermediate::constraints(const std::list<constraint>& constraints){
|
||||
context_->parts.push_back(std::make_unique<internal::query_create_table_constraints_part>(constraints));
|
||||
return {context_};
|
||||
}
|
||||
|
||||
executable_query query_create_table_columns_intermediate::constraints(const std::list<object::restriction>& restrictions) {
|
||||
std::list<constraint> constraints;
|
||||
for ( const auto& restr : restrictions ) {
|
||||
|
||||
for (const auto& restr : restrictions) {
|
||||
if (restr.is_primary_key_constraint()) {
|
||||
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options());
|
||||
} else if (restr.is_foreign_key_constraint()) {
|
||||
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options(), restr.ref_table_name(), restr.ref_column_name());
|
||||
} else if (restr.is_unique_constraint()) {
|
||||
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options());
|
||||
}
|
||||
}
|
||||
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> attributes) {
|
||||
query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::initializer_list<object::attribute> attributes) {
|
||||
return columns(std::list(attributes));
|
||||
}
|
||||
|
||||
query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<object::attribute>& attributes) {
|
||||
std::list<column> columns;
|
||||
for (const auto& attr : attributes) {
|
||||
auto options = attr.attributes().options();
|
||||
if (!attr.is_nullable()) {
|
||||
options |= utils::constraints::NotNull;
|
||||
}
|
||||
|
||||
columns.emplace_back(nullptr, attr.name(), attr.type(), utils::field_attributes{attr.attributes().size(), options});
|
||||
}
|
||||
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(std::initializer_list<column> columns) {
|
||||
return {context_};
|
||||
return this->columns(std::list(columns));
|
||||
}
|
||||
|
||||
query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<column>& columns) {
|
||||
context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns));
|
||||
|
||||
return {context_};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,18 +38,21 @@ sql::query_context query_compiler::compile(const query_data &data,
|
||||
}
|
||||
|
||||
std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const query_data &data, const column &col) {
|
||||
if (col.is_function()) {
|
||||
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.name());
|
||||
ctx.prototype.back().change_type(utils::basic_type::Int32);
|
||||
} else {
|
||||
ctx.prototype.emplace_back(col.name());
|
||||
}
|
||||
if (col.is_function()) {
|
||||
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.name());
|
||||
ctx.prototype.back().change_type(utils::basic_type::Int32);
|
||||
} else {
|
||||
ctx.prototype.emplace_back(col.name());
|
||||
}
|
||||
|
||||
|
||||
if (col.table() != nullptr) {
|
||||
if (const auto it = data.tables.find(col.table()->name()); it != data.tables.end()) {
|
||||
return prepare_identifier(*d, it->second, {col.name(), col.alias()});
|
||||
return prepare_identifier(*d,{&it->second, col.name(), col.alias()});
|
||||
}
|
||||
}
|
||||
|
||||
return prepare_identifier(*d, col);
|
||||
return prepare_identifier(*d, col);
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_alter_part& part) {
|
||||
@@ -125,7 +128,7 @@ void query_compiler::visit(internal::query_drop_key_constraint_part_by_name& par
|
||||
query_.sql += " " + dialect_->token_at(part.token()) + " " + part.name();
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_drop_key_constraint_part_by_constraint& part) {
|
||||
void query_compiler::visit(internal::query_drop_key_constraint_part_by_constraint& /*part*/) {
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_select_part &part) {
|
||||
@@ -158,8 +161,7 @@ void query_compiler::visit(internal::query_from_part &part) {
|
||||
query_.sql += " " + build_table_name(part.token(), *dialect_, part.table());
|
||||
}
|
||||
|
||||
void query_compiler::visit(internal::query_join_part &part)
|
||||
{
|
||||
void query_compiler::visit(internal::query_join_part &part) {
|
||||
query_.sql += " " + build_table_name(part.token(), *dialect_, part.table());
|
||||
}
|
||||
|
||||
@@ -403,9 +405,9 @@ std::string build_create_column(const column &col, const sql::dialect &d) {
|
||||
|
||||
std::string build_constraint(const constraint& cons, const sql::dialect& d) {
|
||||
std::string result;
|
||||
// if (!cons.name().empty()) {
|
||||
// result.append(d.constraint()).append(" ").append(cons.name()).append(" ");
|
||||
// }
|
||||
if (!cons.name().empty()) {
|
||||
result.append(d.constraint()).append(" ").append(cons.name()).append(" ");
|
||||
}
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
result
|
||||
.append(d.primary_key())
|
||||
@@ -432,11 +434,11 @@ std::string build_constraint(const constraint& cons, const sql::dialect& d) {
|
||||
std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) {
|
||||
return d.token_at(token) + " " +
|
||||
(!d.default_schema_name().empty() ? d.prepare_identifier_string(d.default_schema_name()) + "." : "") +
|
||||
d.prepare_identifier_string(t.name()) +
|
||||
(t.alias().empty() ? "" : " " + d.prepare_identifier_string(t.alias()));
|
||||
d.prepare_identifier_string(t.table_name()) +
|
||||
(!t.has_alias() ? "" : " " + d.prepare_identifier_string(t.name()));
|
||||
}
|
||||
|
||||
std::string query_compiler::build_add_constraint_string(const class constraint &c) {
|
||||
std::string query_compiler::build_add_constraint_string(const class constraint &c) const {
|
||||
std::string result = dialect_->add_constraint() + " " + build_constraint_name(c) + " ";
|
||||
if (c.is_primary_key_constraint()) {
|
||||
result.append(dialect_->primary_key()).append(" (").append(c.column_name()).append(")");
|
||||
@@ -448,7 +450,7 @@ std::string query_compiler::build_add_constraint_string(const class constraint &
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string query_compiler::build_drop_constraint_string(const class constraint &c) {
|
||||
std::string query_compiler::build_drop_constraint_string(const class constraint &c) const {
|
||||
return dialect_->drop_constraint() + " " + build_constraint_name(c);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,15 +3,11 @@
|
||||
#include "matador/query/table.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
std::string prepare_identifier( const sql::dialect& d, const column& col ) {
|
||||
return prepare_identifier(d, *col.table(), col);
|
||||
}
|
||||
|
||||
std::string prepare_identifier( const sql::dialect& d, const table& tab, const column& col ) {
|
||||
std::string prepare_identifier(const sql::dialect& d, const column& col) {
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
if (!tab.name().empty()) {
|
||||
result = d.prepare_identifier_string(tab.has_alias() ? tab.alias() : tab.name()) + ".";
|
||||
if (col.table()) {
|
||||
result = d.prepare_identifier_string(col.table()->name()) + ".";
|
||||
}
|
||||
result += d.prepare_identifier_string(col.name());
|
||||
} else {
|
||||
@@ -24,20 +20,16 @@ std::string prepare_identifier( const sql::dialect& d, const table& tab, const c
|
||||
}
|
||||
|
||||
std::string prepare_criteria(const sql::dialect& d, const column& col) {
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
// if (!col.alias.empty()) {
|
||||
// result = col.alias;
|
||||
// } else {
|
||||
if (!col.table()->name().empty()) {
|
||||
result = d.prepare_identifier_string(col.table()->has_alias() ? col.table()->alias() : col.table()->name()) + ".";
|
||||
}
|
||||
result += d.prepare_identifier_string(col.name());
|
||||
// }
|
||||
} else {
|
||||
result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
|
||||
std::string result;
|
||||
if (!col.is_function()) {
|
||||
if (col.table()) {
|
||||
result = d.prepare_identifier_string(col.table()->name()) + ".";
|
||||
}
|
||||
result += d.prepare_identifier_string(col.name());
|
||||
} else {
|
||||
result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+219
-172
@@ -1,3 +1,5 @@
|
||||
#include <utility>
|
||||
|
||||
#include "matador/query/schema.hpp"
|
||||
|
||||
#include "matador/query/query.hpp"
|
||||
@@ -7,208 +9,253 @@
|
||||
#include "matador/sql/backend_provider.hpp"
|
||||
#include "matador/sql/connection_pool.hpp"
|
||||
#include "matador/sql/dialect.hpp"
|
||||
#include "matador/sql/error_code.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
schema::schema(sql::connection_pool& pool)
|
||||
: repo_(sql::backend_provider::instance().connection_dialect(pool.info().type).default_schema_name())
|
||||
, pool_(pool) {
|
||||
schema_node::schema_node(class table tab, const object::repository_node& node)
|
||||
: table_(std::move(tab))
|
||||
, node_(std::move(node)) {
|
||||
}
|
||||
|
||||
schema::schema(sql::connection_pool &pool, const std::string& name)
|
||||
: repo_(name)
|
||||
, pool_(pool) {}
|
||||
|
||||
utils::result<void, utils::error> schema::create() const {
|
||||
// Step 1: Build dependency graph
|
||||
// std::unordered_map<std::string, std::vector<std::string> > dependency_graph;
|
||||
// std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree;
|
||||
//
|
||||
// for (const auto &node: repo_) {
|
||||
// for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
|
||||
// dependency_graph[node->name()].push_back(it->second->node().name());
|
||||
//
|
||||
// if (const auto dit = in_degree.find(it->second->node().name()); dit == in_degree.end()) {
|
||||
// in_degree[it->second->node().name()] = std::make_pair(1, it->second->node_ptr());
|
||||
// } else {
|
||||
// in_degree[it->second->node().name()].first++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Ensure the current node exists in the graph representation
|
||||
// if (in_degree.find(node->name()) == in_degree.end()) {
|
||||
// in_degree[node->name()] = std::make_pair(0, node);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (const auto &it : dependency_graph) {
|
||||
// std::cout << "Dependency graph " << it.first << std::endl;
|
||||
// for (const auto &neighbor: it.second) {
|
||||
// std::cout << " " << neighbor << std::endl;
|
||||
// }
|
||||
// std::cout << std::endl;
|
||||
// }
|
||||
|
||||
std::vector<std::string> fk_sql_commands;
|
||||
const auto c = pool_.acquire();
|
||||
|
||||
const auto q = query::query::create().schema( repo_.name() ).compile( *c );
|
||||
std::cout << q.sql << std::endl;
|
||||
|
||||
// create plain tables without constraints
|
||||
for (const auto &node: repo_) {
|
||||
auto ctx = query::query::create()
|
||||
.table(node->name())
|
||||
.columns(node->info().attributes())
|
||||
// .constraints(node->info().constraints())
|
||||
.compile(*c);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
|
||||
// create primary key constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto& cons : node->info().constraints()) {
|
||||
if (!cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = build_add_constraint_context(*node, cons);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
// create table constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto& cons : node->info().constraints()) {
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = build_add_constraint_context(*node, cons);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
return utils::ok<void>();
|
||||
const std::string & schema_node::name() const {
|
||||
return table_.name();
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> schema::drop() const {
|
||||
auto c = pool_.acquire();
|
||||
// drop table primary key constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto& cons : node->info().constraints()) {
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = query::query::alter()
|
||||
.table(node->name())
|
||||
.drop_constraint(cons)
|
||||
.compile(*c);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop table constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto& cons : node->info().constraints()) {
|
||||
if (!cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = query::query::alter()
|
||||
.table(node->name())
|
||||
.drop_constraint(cons)
|
||||
.compile(*c);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop table
|
||||
for (const auto &node: repo_) {
|
||||
auto ctx = query::query::drop()
|
||||
.table(node->name())
|
||||
.compile(*c);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = c->execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
const table &schema_node::table() const {
|
||||
return table_;
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> schema::drop_table(const std::string& table_name) const {
|
||||
const auto c = pool_.acquire();
|
||||
auto result = query::query::drop()
|
||||
.table(table_name)
|
||||
.execute(*c);
|
||||
if (result.is_error()) {
|
||||
const object::repository_node& schema_node::node() const {
|
||||
return node_;
|
||||
}
|
||||
|
||||
schema::schema(const std::string &name)
|
||||
: repo_(name) {
|
||||
}
|
||||
|
||||
utils::result<void, utils::error> schema::create(const sql::connection &conn) const {
|
||||
// Step 1: Build dependency graph
|
||||
// std::unordered_map<std::string, std::vector<std::string> > dependency_graph;
|
||||
// std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree;
|
||||
//
|
||||
// for (const auto &node: repo_) {
|
||||
// for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
|
||||
// dependency_graph[node->name()].push_back(it->second->node().name());
|
||||
//
|
||||
// if (const auto dit = in_degree.find(it->second->node().name()); dit == in_degree.end()) {
|
||||
// in_degree[it->second->node().name()] = std::make_pair(1, it->second->node_ptr());
|
||||
// } else {
|
||||
// in_degree[it->second->node().name()].first++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Ensure the current node exists in the graph representation
|
||||
// if (in_degree.find(node->name()) == in_degree.end()) {
|
||||
// in_degree[node->name()] = std::make_pair(0, node);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (const auto &it : dependency_graph) {
|
||||
// std::cout << "Dependency graph " << it.first << std::endl;
|
||||
// for (const auto &neighbor: it.second) {
|
||||
// std::cout << " " << neighbor << std::endl;
|
||||
// }
|
||||
// std::cout << std::endl;
|
||||
// }
|
||||
|
||||
std::vector<std::string> fk_sql_commands;
|
||||
|
||||
const auto q = query::query::create().schema(repo_.name()).compile(conn);
|
||||
std::cout << q.sql << std::endl;
|
||||
|
||||
// create plain tables without constraints
|
||||
for (const auto &node: repo_) {
|
||||
auto ctx = query::query::create()
|
||||
.table(node->name())
|
||||
.columns(node->info().attributes())
|
||||
// .constraints(node->info().constraints())
|
||||
.compile(conn);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
|
||||
// create primary key constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto &cons: node->info().constraints()) {
|
||||
if (!cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = build_add_constraint_context(*node, cons, conn);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
// create table constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto &cons: node->info().constraints()) {
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = build_add_constraint_context(*node, cons, conn);
|
||||
|
||||
return utils::ok<void>();
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<std::vector<object::attribute>, utils::error> schema::describe_table(const std::string& table_name) const {
|
||||
const auto c = pool_.acquire();
|
||||
if (!c.valid()) {
|
||||
return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
|
||||
utils::result<void, utils::error> schema::drop(const sql::connection &conn) const {
|
||||
// drop table primary key constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto &cons: node->info().constraints()) {
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = query::query::alter()
|
||||
.table(node->name())
|
||||
.drop_constraint(cons)
|
||||
.compile(conn);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
return utils::ok(c->describe(table_name).release());
|
||||
}
|
||||
|
||||
// drop table constraints
|
||||
for (const auto &node: repo_) {
|
||||
for (const auto &cons: node->info().constraints()) {
|
||||
if (!cons.is_primary_key_constraint()) {
|
||||
continue;
|
||||
}
|
||||
auto ctx = query::query::alter()
|
||||
.table(node->name())
|
||||
.drop_constraint(cons)
|
||||
.compile(conn);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drop table
|
||||
for (const auto &node: repo_) {
|
||||
auto ctx = query::query::drop()
|
||||
.table(node->name())
|
||||
.compile(conn);
|
||||
|
||||
std::cout << ctx.sql << std::endl;
|
||||
if (auto result = conn.execute(ctx.sql); !result) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> schema::table_exists(const std::string& table_name) const {
|
||||
const auto c = pool_.acquire();
|
||||
if (!c.valid()) {
|
||||
return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
|
||||
}
|
||||
return c->exists(repo_.name(), table_name);
|
||||
utils::result<void, utils::error> schema::drop_table(const std::string &table_name, const sql::connection &conn) const {
|
||||
auto result = query::query::drop()
|
||||
.table(table_name)
|
||||
.execute(conn);
|
||||
if (result.is_error()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
return utils::ok<void>();
|
||||
}
|
||||
|
||||
sql::query_context schema::build_add_constraint_context( const object::repository_node& node, const object::restriction& cons ) const {
|
||||
utils::result<std::vector<object::attribute>, utils::error>
|
||||
schema::describe_table(const std::string &table_name, const sql::connection &conn) const {
|
||||
// if (!conn.valid()) {
|
||||
// return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
|
||||
// }
|
||||
return utils::ok(conn.describe(table_name).release());
|
||||
}
|
||||
|
||||
utils::result<bool, utils::error> schema::table_exists(const std::string &table_name, const sql::connection &conn) const {
|
||||
// if (!c.valid()) {
|
||||
// return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
|
||||
// }
|
||||
return conn.exists(repo_.name(), table_name);
|
||||
}
|
||||
|
||||
schema::iterator schema::begin() {
|
||||
return schema_nodes_.begin();
|
||||
}
|
||||
|
||||
schema::iterator schema::end() {
|
||||
return schema_nodes_.end();
|
||||
}
|
||||
|
||||
schema::const_iterator schema::begin() const {
|
||||
return schema_nodes_.begin();
|
||||
}
|
||||
|
||||
schema::const_iterator schema::end() const {
|
||||
return schema_nodes_.end();
|
||||
}
|
||||
|
||||
schema::iterator schema::find(const std::string &name) {
|
||||
const auto result = repo_.basic_info(name);
|
||||
if (!result) {
|
||||
return schema_nodes_.end();
|
||||
}
|
||||
|
||||
return schema_nodes_.find(result->get().type_index());
|
||||
}
|
||||
|
||||
schema::const_iterator schema::find(const std::string &name) const {
|
||||
const auto result = repo_.basic_info(name);
|
||||
if (!result) {
|
||||
return schema_nodes_.end();
|
||||
}
|
||||
|
||||
return schema_nodes_.find(result->get().type_index());
|
||||
}
|
||||
|
||||
sql::query_context schema::build_add_constraint_context(const object::repository_node &node,
|
||||
const object::restriction &cons,
|
||||
const sql::connection &conn) const {
|
||||
if (cons.is_foreign_key_constraint()) {
|
||||
return query::query::alter()
|
||||
.table(node.name())
|
||||
.add_constraint(cons)
|
||||
.compile(*pool_.acquire());
|
||||
.table(node.name())
|
||||
.add_constraint(cons)
|
||||
.compile(conn);
|
||||
}
|
||||
if (cons.is_primary_key_constraint()) {
|
||||
return query::query::alter()
|
||||
.table(node.name())
|
||||
.add_constraint(cons)
|
||||
.compile(*pool_.acquire());
|
||||
return query::query::alter()
|
||||
.table(node.name())
|
||||
.add_constraint(cons)
|
||||
.compile(conn);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
sql::query_context schema::build_drop_constraint_context( const object::repository_node& node, const object::restriction& cons ) const {
|
||||
sql::query_context schema::build_drop_constraint_context(const object::repository_node &node,
|
||||
const object::restriction &cons,
|
||||
const sql::connection &conn) const {
|
||||
return query::query::alter()
|
||||
.table(node.name())
|
||||
.drop_constraint(cons)
|
||||
.compile(*pool_.acquire());
|
||||
.table(node.name())
|
||||
.drop_constraint(cons)
|
||||
.compile(conn);
|
||||
}
|
||||
|
||||
void schema::insert_table(const std::type_index& ti, const object::repository_node& node) {
|
||||
void schema::insert_table(const std::type_index &ti, const object::repository_node &node) {
|
||||
std::vector<column> columns;
|
||||
for (const auto &attr : node.info().attributes()) {
|
||||
for (const auto &attr: node.info().attributes()) {
|
||||
columns.emplace_back(nullptr, attr.name(), attr.type(), attr.attributes());
|
||||
}
|
||||
std::ignore = tables_.insert({ti, table(node.name(), "", columns)}).first;
|
||||
std::ignore = schema_nodes_.insert({ti, schema_node{table(node.name(), columns), node}}).first;
|
||||
}
|
||||
} // namespace matador::query
|
||||
} // namespace matador::query
|
||||
|
||||
+69
-21
@@ -1,3 +1,5 @@
|
||||
#include <utility>
|
||||
|
||||
#include "matador/query/table.hpp"
|
||||
|
||||
namespace matador::query {
|
||||
@@ -6,46 +8,63 @@ table::table(const char* name)
|
||||
: table(std::string(name))
|
||||
{}
|
||||
|
||||
table::table(std::string name)
|
||||
: name_(std::move(name))
|
||||
{}
|
||||
table::table(const std::string& name)
|
||||
: table(name, name, {}) {}
|
||||
|
||||
table::table(std::string name, std::string as)
|
||||
: name_(std::move(name))
|
||||
, alias_(std::move(as))
|
||||
{}
|
||||
table::table(const std::string& name, const std::vector<column> &columns)
|
||||
: table(name, name, columns) {
|
||||
}
|
||||
|
||||
table::table( std::string name, std::string as, const std::vector<query::column>& columns )
|
||||
table::table(std::string name, std::string alias, const std::vector<column> &columns)
|
||||
: name_(std::move(name))
|
||||
, alias_(std::move(as))
|
||||
, alias_(std::move(alias))
|
||||
, columns_(columns) {
|
||||
for (auto& col : columns_) {
|
||||
col.table_ = this;
|
||||
for (auto &col : columns_) {
|
||||
col.table(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool table::operator==( const table& x ) const {
|
||||
return name_ == x.name_;
|
||||
table::table(const table &other)
|
||||
: table(other.name_, other.alias_, other.columns_) {
|
||||
for (auto &col : columns_) {
|
||||
col.table(this);
|
||||
}
|
||||
}
|
||||
|
||||
table table::as(const std::string &a) {
|
||||
alias_ = a;
|
||||
table & table::operator=(const table &other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
return *this = table(other);
|
||||
}
|
||||
|
||||
table::table(table &&other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
table & table::operator=(table &&other) noexcept {
|
||||
name_ = std::move(other.name_);
|
||||
alias_ = std::move(other.alias_);
|
||||
columns_ = std::move(other.columns_);
|
||||
for (auto &col : columns_) {
|
||||
col.table(this);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
table table::as(const std::string &a) const {
|
||||
return { name_, a, columns_ };
|
||||
bool table::operator==(const table& x) const {
|
||||
return name_ == x.name_ && alias_ == x.alias_;
|
||||
}
|
||||
|
||||
bool table::has_alias() const {
|
||||
return !alias_.empty();
|
||||
table table::as(const std::string &alias) const {
|
||||
return { name_, alias, columns_ };
|
||||
}
|
||||
|
||||
const std::string& table::name() const {
|
||||
const std::string & table::table_name() const {
|
||||
return name_;
|
||||
}
|
||||
|
||||
const std::string& table::alias() const {
|
||||
const std::string& table::name() const {
|
||||
return alias_;
|
||||
}
|
||||
|
||||
@@ -53,10 +72,39 @@ const std::vector<column>& table::columns() const {
|
||||
return columns_;
|
||||
}
|
||||
|
||||
bool table::has_alias() const {
|
||||
return name_ != alias_;
|
||||
}
|
||||
|
||||
table::operator const std::vector<query::column>&() const {
|
||||
return columns_;
|
||||
}
|
||||
|
||||
const class column* table::operator[](const std::string &column_name) const {
|
||||
for (const auto &col : columns_) {
|
||||
if (col.name() == column_name) {
|
||||
return &col;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const class column * table::column_by_name(const table &tab, const std::string &column_name) {
|
||||
for (const auto &col : tab.columns_) {
|
||||
if (col.name() == column_name) {
|
||||
return &col;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const column& table::create_column(class table &tab, const std::string &name) {
|
||||
tab.columns_.emplace_back(name);
|
||||
tab.columns_.back().table(&tab);
|
||||
return tab.columns_.back();
|
||||
}
|
||||
|
||||
|
||||
table operator ""_tab(const char *name, size_t len) {
|
||||
return {{name, len}};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user