added alter table command to fluent query builder

This commit is contained in:
Sascha Kühl
2025-11-05 11:05:03 +01:00
parent c87a4c29b4
commit 4b51ad21da
27 changed files with 343 additions and 282 deletions
+3 -3
View File
@@ -19,6 +19,7 @@ add_library(matador-orm STATIC
../../include/matador/query/intermediates/executable_query.hpp
../../include/matador/query/intermediates/fetchable_query.hpp
../../include/matador/query/intermediates/query_alter_intermediate.hpp
../../include/matador/query/intermediates/query_alter_table_intermediate.hpp
../../include/matador/query/intermediates/query_create_intermediate.hpp
../../include/matador/query/intermediates/query_delete_from_intermediate.hpp
../../include/matador/query/intermediates/query_delete_intermediate.hpp
@@ -97,6 +98,7 @@ add_library(matador-orm STATIC
query/intermediates/executable_query.cpp
query/intermediates/fetchable_query.cpp
query/intermediates/query_alter_intermediate.cpp
query/intermediates/query_alter_table_intermediate.cpp
query/intermediates/query_create_intermediate.cpp
query/intermediates/query_delete_from_intermediate.cpp
query/intermediates/query_delete_intermediate.cpp
@@ -118,6 +120,7 @@ add_library(matador-orm STATIC
query/intermediates/query_order_direction_intermediate.cpp
query/intermediates/query_select_intermediate.cpp
query/intermediates/query_set_intermediate.cpp
query/intermediates/query_update_intermediate.cpp
query/intermediates/query_where_intermediate.cpp
query/internal/basic_type_to_string_visitor.cpp
query/internal/key_value_pair.cpp
@@ -127,7 +130,6 @@ add_library(matador-orm STATIC
query/query.cpp
query/query_compiler.cpp
query/query_part.cpp
query/query_update_intermediate.cpp
query/value_extractor.cpp
sql/backend_provider.cpp
sql/column.cpp
@@ -152,8 +154,6 @@ add_library(matador-orm STATIC
sql/statement.cpp
sql/statement_cache.cpp
sql/table.cpp
../../include/matador/query/intermediates/query_alter_table_intermediate.hpp
query/intermediates/query_alter_table_intermediate.cpp
)
target_include_directories(matador-orm
@@ -8,25 +8,21 @@ namespace matador::query {
utils::result<size_t, utils::error> executable_query::execute(const sql::executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Direct;
return exec.execute(compiler.compile(*context_, exec.dialect(), std::nullopt));
}
utils::result<sql::statement, utils::error> executable_query::prepare(sql::executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Prepared;
return exec.prepare(compiler.compile(*context_, exec.dialect(), std::nullopt));
}
sql::query_context executable_query::compile( const sql::executor& exec ) const {
query_compiler compiler;
context_->mode = query_mode::Prepared;
return compiler.compile(*context_, exec.dialect(), std::nullopt);
}
std::string executable_query::str(const sql::executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Direct;
return exec.str(compiler.compile(*context_, exec.dialect(), std::nullopt));
}
@@ -34,7 +34,6 @@ sql::record *create_prototype(const std::vector<object::attribute_definition> &p
}
utils::result<sql::query_result<sql::record>, utils::error> fetchable_query::fetch_all(const sql::executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Direct;
const auto ctx = compiler.compile(*context_, exec.dialect(), std::nullopt);
return exec.fetch(ctx)
.and_then([](auto &&res) {
@@ -47,7 +46,6 @@ utils::result<sql::query_result<sql::record>, utils::error> fetchable_query::fet
utils::result<std::optional<sql::record>, utils::error> fetchable_query::fetch_one(const sql::executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Direct;
auto result = exec.fetch(compiler.compile(*context_, exec.dialect(), std::nullopt));
if (!result.is_ok()) {
return utils::failure(result.err());
@@ -66,21 +64,20 @@ utils::result<std::optional<sql::record>, utils::error> fetchable_query::fetch_o
}
std::string fetchable_query::str(const sql::executor &exec) const {
return exec.str(compile(exec.dialect(), query_mode::Direct));
return exec.str(compile(exec.dialect()));
}
sql::query_context fetchable_query::compile(const sql::dialect &d, const query_mode mode) const {
sql::query_context fetchable_query::compile(const sql::dialect &d) const {
query_compiler compiler;
context_->mode = mode;
return compiler.compile(*context_, d, std::nullopt);
}
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetchable_query::fetch(const sql::executor &exec) const {
return exec.fetch(compile(exec.dialect(), query_mode::Direct));
return exec.fetch(compile(exec.dialect()));
}
utils::result<sql::statement, utils::error> fetchable_query::prepare(sql::executor &exec) const {
return exec.prepare(compile(exec.dialect(), query_mode::Prepared));
return exec.prepare(compile(exec.dialect()));
}
}
@@ -4,20 +4,21 @@
namespace matador::query {
query_create_intermediate::query_create_intermediate()
{
query_create_intermediate::query_create_intermediate() {
context_->parts.push_back(std::make_unique<internal::query_create_part>());
}
executable_query query_create_intermediate::table(const sql::table &table, const std::initializer_list<object::attribute_definition> columns)
{
executable_query query_create_intermediate::table(const sql::table &table, const std::initializer_list<object::attribute_definition> columns) {
return this->table(table, std::vector<object::attribute_definition>{columns});
}
executable_query query_create_intermediate::table(const sql::table &table, const std::vector<object::attribute_definition> &columns)
{
executable_query query_create_intermediate::table(const sql::table &table, const std::vector<object::attribute_definition> &columns) {
context_->parts.push_back(std::make_unique<internal::query_create_table_part>(table, columns));
return {context_};
}
executable_query query_create_intermediate::schema( const std::string& schema_name ) {
context_->parts.push_back(std::make_unique<internal::query_create_schema_part>(schema_name));
return {context_};
}
}
@@ -4,13 +4,11 @@
namespace matador::query {
query_drop_intermediate::query_drop_intermediate()
{
query_drop_intermediate::query_drop_intermediate() {
context_->parts.push_back(std::make_unique<internal::query_drop_part>());
}
executable_query query_drop_intermediate::table(const sql::table &table)
{
executable_query query_drop_intermediate::table(const sql::table &table) {
context_->parts.push_back(std::make_unique<internal::query_drop_table_part>(table));
return {context_};
}
+7 -3
View File
@@ -15,15 +15,19 @@ key_value_pair::key_value_pair(const sql::column &col, utils::database_type valu
}
key_value_pair::key_value_pair(const char *name, utils::database_type value)
: name_(name)
, value_(std::move(value)) {
: name_(name)
, value_(std::move(value)) {
}
key_value_pair::key_value_pair( const char* name, utils::placeholder p )
: name_(name)
, value_(p) {}
const std::string &key_value_pair::name() const {
return name_;
}
const utils::database_type& key_value_pair::value() const {
const std::variant<utils::placeholder, utils::database_type>& key_value_pair::value() const {
return value_;
}
}
+30
View File
@@ -46,6 +46,13 @@ const std::string& query_drop_key_constraint_part::name() const {
return name_;
}
query_drop_foreign_key_constraint_part::query_drop_foreign_key_constraint_part()
: query_part( sql::dialect_token::DropConstraint ) {}
void query_drop_foreign_key_constraint_part::accept( query_part_visitor& visitor ) {
visitor.visit(*this);
}
query_add_foreign_key_constraint_part::query_add_foreign_key_constraint_part(const std::vector<sql::column>& columns)
: query_part(sql::dialect_token::ForeignKey)
, columns_(columns) {}
@@ -357,6 +364,18 @@ void query_create_table_part::accept(query_part_visitor &visitor)
visitor.visit(*this);
}
query_create_schema_part::query_create_schema_part(std::string schema)
: query_part( sql::dialect_token::Schema )
, schema_( std::move( schema ) ){}
const std::string& query_create_schema_part::schema() const {
return schema_;
}
void query_create_schema_part::accept( query_part_visitor& visitor ) {
visitor.visit(*this);
}
query_drop_part::query_drop_part()
: query_part(sql::dialect_token::Drop) {}
@@ -379,4 +398,15 @@ void query_drop_table_part::accept(query_part_visitor &visitor)
visitor.visit(*this);
}
query_drop_schema_part::query_drop_schema_part(std::string schema_)
: query_part( sql::dialect_token::Schema )
, schema_( std::move( schema_ ) ) {}
const std::string& query_drop_schema_part::schema() const {
return schema_;
}
void query_drop_schema_part::accept( query_part_visitor& visitor ) {
visitor.visit(*this);
}
}
+4
View File
@@ -32,6 +32,10 @@ query_drop_intermediate query::drop() {
return {};
}
query_select_intermediate query::select() {
return query_select_intermediate{{}};
}
query_select_intermediate query::select( const std::initializer_list<sql::column> columns) {
return select(std::vector<sql::column>{columns});
}
+78 -80
View File
@@ -65,7 +65,7 @@ void query_compiler::visit(internal::query_add_key_constraint_part& part) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::AddConstraint) + " " + part.name();
}
void query_compiler::visit( internal::query_add_foreign_key_constraint_part& part ) {
void query_compiler::visit(internal::query_add_foreign_key_constraint_part& part) {
query_.sql += " " + dialect_->token_at(part.token()) + " (";
if (part.columns().size() < 2) {
@@ -82,9 +82,9 @@ void query_compiler::visit( internal::query_add_foreign_key_constraint_part& par
query_.sql += ")";
}
void query_compiler::visit( internal::query_add_primary_key_constraint_part& part ) {}
void query_compiler::visit(internal::query_add_primary_key_constraint_part& part) {}
void query_compiler::visit( internal::query_add_foreign_key_reference_part& part ) {
void query_compiler::visit(internal::query_add_foreign_key_reference_part& part) {
query_.sql += " " + dialect_->token_at(part.token()) + " " +
part.table().name + " (";
@@ -106,7 +106,10 @@ void query_compiler::visit(internal::query_drop_key_constraint_part& part) {
query_.sql += " " + dialect_->token_at(part.token()) + " " + part.name();
}
void query_compiler::visit(internal::query_select_part &select_part)
void query_compiler::visit(internal::query_drop_foreign_key_constraint_part& part) {
}
void query_compiler::visit(internal::query_select_part &part)
{
query_.command = sql::sql_command::SQL_SELECT;
query_.sql = dialect_->token_at(sql::dialect_token::Select) + " ";
@@ -114,7 +117,9 @@ void query_compiler::visit(internal::query_select_part &select_part)
query_.prototype.clear();
std::string result;
if (const auto &columns = select_part.columns(); columns.size() < 2) {
if (part.columns().empty()) {
result = dialect_->token_at(sql::dialect_token::Asterisk);
} else if (const auto &columns = part.columns(); columns.size() < 2) {
for (const auto &col: columns) {
result.append(handle_column(query_, dialect_, *data_, col ));
}
@@ -130,38 +135,38 @@ void query_compiler::visit(internal::query_select_part &select_part)
query_.sql += result;
}
void query_compiler::visit(internal::query_from_part &from_part)
void query_compiler::visit(internal::query_from_part &part)
{
query_.table = from_part.table();
query_.sql += " " + build_table_name(from_part.token(), *dialect_, query_.table);
query_.table = part.table();
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table);
query_.table_aliases.insert({query_.table.name, query_.table.alias});
}
void query_compiler::visit(internal::query_join_part &join_part)
void query_compiler::visit(internal::query_join_part &part)
{
query_.sql += " " + query_compiler::build_table_name(join_part.token(), *dialect_, join_part.table());
query_.sql += " " + query_compiler::build_table_name(part.token(), *dialect_, part.table());
}
void query_compiler::visit(internal::query_on_part &on_part) {
void query_compiler::visit(internal::query_on_part &part) {
criteria_evaluator evaluator(*dialect_, query_);
query_.sql += " " + dialect_->token_at(sql::dialect_token::On) +
" " + evaluator.evaluate(on_part.condition());
" " + evaluator.evaluate(part.condition());
}
void query_compiler::visit(internal::query_where_part &where_part) {
void query_compiler::visit(internal::query_where_part &part) {
criteria_evaluator evaluator(*dialect_, query_);
query_.sql += " " + dialect_->token_at(sql::dialect_token::Where) +
" " + evaluator.evaluate(where_part.condition());
" " + evaluator.evaluate(part.condition());
}
void query_compiler::visit(internal::query_group_by_part &group_by_part) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::GroupBy) + " " + dialect_->prepare_identifier(group_by_part.column());
void query_compiler::visit(internal::query_group_by_part &part) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::GroupBy) + " " + dialect_->prepare_identifier(part.column());
}
void query_compiler::visit(internal::query_order_by_part &order_by_part)
void query_compiler::visit(internal::query_order_by_part &part)
{
query_.sql += " " + dialect_->token_at(sql::dialect_token::OrderBy) +
" " + dialect_->prepare_condition(order_by_part.column());
" " + dialect_->prepare_condition(part.column());
}
void query_compiler::visit(internal::query_order_by_asc_part &/*order_by_asc_part*/)
@@ -174,14 +179,14 @@ void query_compiler::visit(internal::query_order_by_desc_part &/*order_by_desc_p
query_.sql += " " + dialect_->token_at(sql::dialect_token::Desc);
}
void query_compiler::visit(internal::query_offset_part &offset_part)
void query_compiler::visit(internal::query_offset_part &part)
{
query_.sql += " " + dialect_->token_at(sql::dialect_token::Offset) + " " + std::to_string(offset_part.offset());
query_.sql += " " + dialect_->token_at(sql::dialect_token::Offset) + " " + std::to_string(part.offset());
}
void query_compiler::visit(internal::query_limit_part &limit_part)
void query_compiler::visit(internal::query_limit_part &part)
{
query_.sql += " " + dialect_->token_at(sql::dialect_token::Limit) + " " + std::to_string(limit_part.limit());
query_.sql += " " + dialect_->token_at(sql::dialect_token::Limit) + " " + std::to_string(part.limit());
}
void query_compiler::visit(internal::query_insert_part &/*insert_part*/)
@@ -190,21 +195,21 @@ void query_compiler::visit(internal::query_insert_part &/*insert_part*/)
query_.sql = dialect_->token_at(sql::dialect_token::Insert);
}
void query_compiler::visit(internal::query_into_part &into_part)
void query_compiler::visit(internal::query_into_part &part)
{
query_.table = into_part.table();
query_.table = part.table();
query_.sql += " " + dialect_->token_at(sql::dialect_token::Into) +
" " + dialect_->prepare_identifier_string(into_part.table().name);
" " + dialect_->prepare_identifier_string(part.table().name);
std::string result{"("};
if (into_part.columns().size() < 2) {
for (const auto &col: into_part.columns()) {
if (part.columns().size() < 2) {
for (const auto &col: part.columns()) {
result.append(dialect_->prepare_identifier_string(col.name));
}
} else {
auto it = into_part.columns().begin();
auto it = part.columns().begin();
result.append(dialect_->prepare_identifier_string((it++)->name));
for (; it != into_part.columns().end(); ++it) {
for (; it != part.columns().end(); ++it) {
result.append(", ");
result.append(dialect_->prepare_identifier_string(it->name));
}
@@ -222,7 +227,7 @@ struct value_visitor {
}
void operator()(const utils::placeholder &/*val*/) {
value_to_string_visitor.query.bind_vars.emplace_back("unknown");
value_to_string_visitor.query.bind_vars.emplace_back(std::string("value_") + std::to_string(value_to_string_visitor.query.bind_vars.size() + 1));
value_to_string_visitor.result = value_to_string_visitor.writer->dialect().next_placeholder(value_to_string_visitor.query.bind_vars);
}
@@ -230,31 +235,26 @@ struct value_visitor {
};
std::string query_compiler::determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val) {
if (data_->mode == query_mode::Direct) {
std::visit(visitor, val);
return visitor.value_to_string_visitor.result;
}
query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1));
return dialect_->next_placeholder(query_.bind_vars);
std::visit(visitor, val);
return visitor.value_to_string_visitor.result;
}
void query_compiler::visit(internal::query_values_part &values_part) {
void query_compiler::visit(internal::query_values_part &part) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::Values);
attribute_string_writer writer(*dialect_, connection_);
value_visitor visitor(writer, query_);
std::string result{"("};
if (values_part.values().size() < 2) {
for (const auto& val: values_part.values()) {
if (part.values().size() < 2) {
for (const auto& val: part.values()) {
result.append(determine_value(visitor, val));
}
} else {
auto it = values_part.values().begin();
auto it = part.values().begin();
auto val = *it++;
result.append(determine_value(visitor, val));
for (; it != values_part.values().end(); ++it) {
for (; it != part.values().end(); ++it) {
result.append(", ");
val = *it;
result.append(determine_value(visitor, val));
@@ -265,11 +265,11 @@ void query_compiler::visit(internal::query_values_part &values_part) {
query_.sql += " " + result;
}
void query_compiler::visit(internal::query_update_part &update_part)
void query_compiler::visit(internal::query_update_part &part)
{
query_.command = sql::sql_command::SQL_UPDATE;
query_.table = update_part.table();
query_.sql += query_compiler::build_table_name(update_part.token(), *dialect_, query_.table);
query_.table = part.table();
query_.sql += query_compiler::build_table_name(part.token(), *dialect_, query_.table);
}
void query_compiler::visit(internal::query_delete_part &/*delete_part*/)
@@ -278,10 +278,10 @@ void query_compiler::visit(internal::query_delete_part &/*delete_part*/)
query_.sql = dialect_->token_at(sql::dialect_token::Remove);
}
void query_compiler::visit(internal::query_delete_from_part &delete_from_part)
void query_compiler::visit(internal::query_delete_from_part &part)
{
query_.table = delete_from_part.table();
query_.sql += " " + build_table_name(delete_from_part.token(), *dialect_, query_.table);
query_.table = part.table();
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table);
}
void query_compiler::visit(internal::query_create_part &/*create_part*/)
@@ -303,30 +303,30 @@ struct column_context
std::string build_create_column(const object::attribute_definition &col, const sql::dialect &d, column_context &context);
void query_compiler::visit(internal::query_create_table_part &create_table_part)
void query_compiler::visit(internal::query_create_table_part &part)
{
query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(create_table_part.table().name) + " ";
query_.table = create_table_part.table();
query_.sql += " " + dialect_->token_at(sql::dialect_token::Table) + " " + dialect_->prepare_identifier_string(part.table().name) + " ";
query_.table = part.table();
std::string result = "(";
column_context context;
if (create_table_part.columns().size() < 2) {
for (const auto &col: create_table_part.columns()) {
if (part.columns().size() < 2) {
for (const auto &col: part.columns()) {
result.append(build_create_column(col, *dialect_, context));
}
} else {
auto it = create_table_part.columns().begin();
auto it = part.columns().begin();
result.append(build_create_column(*it++, *dialect_, context));
for (; it != create_table_part.columns().end(); ++it) {
for (; it != part.columns().end(); ++it) {
result.append(", ");
result.append(build_create_column(*it, *dialect_, context));
}
}
if (!context.primary_keys.empty()) {
result.append(", CONSTRAINT PK_" + create_table_part.table().name + " PRIMARY KEY (" + utils::join(context.primary_keys, ", ") + ")");
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);
@@ -342,52 +342,50 @@ void query_compiler::visit(internal::query_create_table_part &create_table_part)
query_.sql += result;
}
void query_compiler::visit(internal::query_drop_part &/*drop_part*/)
{
void query_compiler::visit( internal::query_create_schema_part& part ) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::Create) + " " +
dialect_->token_at(sql::dialect_token::Schema) + " " + dialect_->prepare_identifier_string(part.schema());
}
void query_compiler::visit(internal::query_drop_part &part) {
query_.command = sql::sql_command::SQL_DROP_TABLE;
query_.sql = dialect_->token_at(sql::dialect_token::Drop);
query_.sql = dialect_->token_at(part.token());
}
std::string query_compiler::determine_set_value(internal::basic_type_to_string_visitor &visitor, const utils::database_type &val) {
if (data_->mode == query_mode::Direct) {
std::visit(visitor, val);
return visitor.result;
}
query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1));
return dialect_->next_placeholder(query_.bind_vars);
void query_compiler::visit( internal::query_drop_schema_part& part ) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::Drop) + " " +
dialect_->token_at(sql::dialect_token::Schema) + " " + dialect_->prepare_identifier_string(part.schema());
}
void query_compiler::visit(internal::query_set_part &set_part)
{
void query_compiler::visit(internal::query_set_part &part) {
query_.sql += " " + dialect_->token_at(sql::dialect_token::Set) + " ";
attribute_string_writer writer(*dialect_, connection_);
internal::basic_type_to_string_visitor visitor(writer, query_);
std::string result;
if (set_part.key_values().size() < 2) {
for (const auto &col: set_part.key_values()) {
value_visitor visitor(writer, query_); if (part.key_values().size() < 2) {
for (const auto &col: part.key_values()) {
result.append(dialect_->prepare_identifier_string(col.name()) + "=");
result.append(determine_set_value(visitor, col.value()));
result.append(determine_value(visitor, col.value()));
}
} else {
auto it = set_part.key_values().begin();
auto it = part.key_values().begin();
result.append(dialect_->prepare_identifier_string(it->name()) + "=");
result.append(determine_set_value(visitor, (it++)->value()));
for (; it != set_part.key_values().end(); ++it) {
result.append(determine_value(visitor, (it++)->value()));
for (; it != part.key_values().end(); ++it) {
result.append(", ");
result.append(dialect_->prepare_identifier_string(it->name()) + "=");
result.append(determine_set_value(visitor, it->value()));
result.append(determine_value(visitor, it->value()));
}
}
query_.sql += result;
}
void query_compiler::visit(internal::query_drop_table_part &drop_table_part)
void query_compiler::visit(internal::query_drop_table_part &part)
{
query_.table = drop_table_part.table();
query_.sql += " " + query_compiler::build_table_name(drop_table_part.token(), *dialect_, query_.table);
query_.table = part.table();
query_.sql += " " + query_compiler::build_table_name(part.token(), *dialect_, query_.table);
}
std::string build_create_column(const object::attribute_definition &col, const sql::dialect &d, column_context &context)