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

View File

@ -79,10 +79,11 @@ int main() {
object::repository repo("Administration");
auto result = repo.attach<admin::CollectionCenter>("collection_centers");
repo.create(pool);
repo.drop(pool);
// repo.create(pool);
// repo.drop(pool);
orm::session ses(pool);
utils::message_bus bus;
orm::session ses({bus, pool});
result = ses.attach<admin::CollectionCenter>("collection_centers")
.and_then([&ses] { return ses.attach<admin::UserDirectory>("user_directories"); })

View File

@ -77,7 +77,7 @@ public:
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;
[[nodiscard]] sql::query_context compile(const sql::dialect &d, query_mode mode) const;
[[nodiscard]] sql::query_context compile(const sql::dialect &d) const;
private:
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::executor &exec) const;

View File

@ -9,8 +9,7 @@
namespace matador::query {
class query_create_intermediate : public query_intermediate
{
class query_create_intermediate : public query_intermediate {
public:
query_create_intermediate();
@ -20,6 +19,7 @@ public:
executable_query table(const sql::table &table, const object::repository &schema) {
return this->table(table, object::attribute_definition_generator::generate<Type>(schema));
}
executable_query schema(const std::string &schema_name);
};
}

View File

@ -5,12 +5,12 @@
namespace matador::query {
class query_drop_intermediate : query_intermediate
{
class query_drop_intermediate : query_intermediate {
public:
query_drop_intermediate();
executable_query table(const sql::table &table);
executable_query schema(const std::string &schema_name);
};
}

View File

@ -3,6 +3,7 @@
#include "matador/sql/column.hpp"
#include "matador/utils/placeholder.hpp"
#include "matador/utils/types.hpp"
namespace matador::query::internal {
@ -12,13 +13,14 @@ public:
key_value_pair(const sql::column &col, utils::database_type value);
key_value_pair(std::string name, utils::database_type value);
key_value_pair(const char *name, utils::database_type value);
key_value_pair(const char *name, utils::placeholder p);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const utils::database_type& value() const;
[[nodiscard]] const std::variant<utils::placeholder, utils::database_type>& value() const;
private:
std::string name_;
utils::database_type value_;
std::variant<utils::placeholder, utils::database_type> value_;
};
}

View File

@ -91,7 +91,7 @@ private:
class query_drop_foreign_key_constraint_part final : public query_part {
public:
explicit query_drop_foreign_key_constraint_part( const std::vector<sql::column>& columns);
query_drop_foreign_key_constraint_part();
void accept(query_part_visitor &visitor) override;
};
@ -377,6 +377,19 @@ private:
std::vector<object::attribute_definition> columns_;
};
class query_create_schema_part final : public query_part {
public:
explicit query_create_schema_part(std::string schema);
[[nodiscard]] const std::string& schema() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::string schema_;
};
class query_drop_part final : public query_part
{
public:
@ -400,5 +413,18 @@ private:
sql::table table_;
};
class query_drop_schema_part final : public query_part {
public:
explicit query_drop_schema_part(std::string schema_);
[[nodiscard]] const std::string& schema() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::string schema_;
};
}
#endif //QUERY_QUERY_PARTS_HPP

View File

@ -20,6 +20,7 @@ class query
public:
[[nodiscard]] static query_create_intermediate create();
[[nodiscard]] static query_drop_intermediate drop();
[[nodiscard]] static query_select_intermediate select();
[[nodiscard]] static query_select_intermediate select(std::initializer_list<sql::column> columns);
[[nodiscard]] static query_select_intermediate select(const std::vector<sql::column>& columns);
[[nodiscard]] static query_select_intermediate select(const std::vector<std::string> &column_names);

View File

@ -22,8 +22,7 @@ struct basic_type_to_string_visitor;
struct query_data;
struct value_visitor;
class query_compiler final : public query_part_visitor
{
class query_compiler final : public query_part_visitor {
public:
sql::query_context compile(const query_data &data,
const sql::dialect &d,
@ -33,42 +32,45 @@ protected:
void visit(internal::query_alter_part& part) override;
void visit(internal::query_alter_table_part& part) override;
void visit(internal::query_add_key_constraint_part& part) override;
void visit( internal::query_add_foreign_key_constraint_part& part ) override;
void visit( internal::query_add_primary_key_constraint_part& part ) override;
void visit( internal::query_add_foreign_key_reference_part& part ) override;
void visit(internal::query_add_foreign_key_constraint_part& part) override;
void visit(internal::query_add_primary_key_constraint_part& part) override;
void visit(internal::query_add_foreign_key_reference_part& part) override;
void visit(internal::query_drop_key_constraint_part& part) override;
void visit(internal::query_drop_foreign_key_constraint_part& part) override;
void visit(internal::query_select_part &select_part) override;
void visit(internal::query_from_part &from_part) override;
void visit(internal::query_join_part &join_part) override;
void visit(internal::query_on_part &on_part) override;
void visit(internal::query_where_part &where_part) override;
void visit(internal::query_group_by_part &group_by_part) override;
void visit(internal::query_order_by_part &order_by_part) override;
void visit(internal::query_order_by_asc_part &order_by_asc_part) override;
void visit(internal::query_order_by_desc_part &order_by_desc_part) override;
void visit(internal::query_offset_part &offset_part) override;
void visit(internal::query_limit_part &limit_part) override;
void visit(internal::query_insert_part &insert_part) override;
void visit(internal::query_into_part &into_part) override;
void visit(internal::query_values_part &values_part) override;
protected:
void visit(internal::query_select_part &part) override;
void visit(internal::query_from_part &part) override;
void visit(internal::query_join_part &part) override;
void visit(internal::query_on_part &part) override;
void visit(internal::query_where_part &part) override;
void visit(internal::query_group_by_part &part) override;
void visit(internal::query_order_by_part &part) override;
void visit(internal::query_order_by_asc_part &part) override;
void visit(internal::query_order_by_desc_part &part) override;
void visit(internal::query_offset_part &part) override;
void visit(internal::query_limit_part &part) override;
void visit(internal::query_insert_part &part) override;
void visit(internal::query_into_part &part) override;
void visit(internal::query_values_part &part) override;
void visit(internal::query_update_part &update_part) override;
void visit(internal::query_set_part &set_part) override;
void visit(internal::query_update_part &part) override;
void visit(internal::query_set_part &part) override;
void visit(internal::query_delete_part &delete_part) override;
void visit(internal::query_delete_from_part &delete_from_part) override;
void visit(internal::query_delete_part &part) override;
void visit(internal::query_delete_from_part &part) override;
void visit(internal::query_create_part &create_part) override;
void visit(internal::query_create_table_part &create_table_part) override;
void visit(internal::query_create_part &part) override;
void visit(internal::query_create_table_part &part) override;
void visit(internal::query_create_schema_part& part) override;
void visit(internal::query_drop_part &drop_part) override;
void visit(internal::query_drop_table_part &drop_table_part) override;
void visit(internal::query_drop_part &part) override;
void visit(internal::query_drop_table_part &part) override;
void visit(internal::query_drop_schema_part& part) override;
static std::string build_table_name(sql::dialect_token token, const sql::dialect &d, const sql::table& t);
std::string determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val);
std::string determine_set_value(internal::basic_type_to_string_visitor &visitor, const utils::database_type &val);
static std::string determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val);
protected:
const query_data *data_{};

View File

@ -12,16 +12,10 @@
namespace matador::query {
enum struct query_mode {
Direct = 0,
Prepared = 1
};
struct query_data {
std::vector<std::unique_ptr<query_part>> parts{};
std::vector<object::attribute_definition> columns{};
std::unordered_map<std::string, sql::table> tables{};
query_mode mode = query_mode::Direct;
std::vector<std::unique_ptr<query_part>> parts{};
std::vector<object::attribute_definition> columns{};
std::unordered_map<std::string, sql::table> tables{};
};
}

View File

@ -8,6 +8,7 @@ class query_alter_part;
class query_alter_table_part;
class query_add_key_constraint_part;
class query_drop_key_constraint_part;
class query_drop_foreign_key_constraint_part;
class query_add_foreign_key_constraint_part;
class query_add_foreign_key_reference_part;
class query_add_primary_key_constraint_part;
@ -31,8 +32,10 @@ class query_delete_part;
class query_delete_from_part;
class query_create_part;
class query_create_table_part;
class query_create_schema_part;
class query_drop_part;
class query_drop_table_part;
class query_drop_schema_part;
}
class query_part_visitor {
@ -46,34 +49,37 @@ public:
virtual void visit(internal::query_add_primary_key_constraint_part &part) = 0;
virtual void visit(internal::query_add_foreign_key_reference_part &part) = 0;
virtual void visit(internal::query_drop_key_constraint_part &part) = 0;
virtual void visit(internal::query_drop_foreign_key_constraint_part &part) = 0;
virtual void visit(internal::query_select_part &select_part) = 0;
virtual void visit(internal::query_from_part &from_part) = 0;
virtual void visit(internal::query_join_part &join_part) = 0;
virtual void visit(internal::query_on_part &on_part) = 0;
virtual void visit(internal::query_where_part &where_part) = 0;
virtual void visit(internal::query_group_by_part &group_by_part) = 0;
virtual void visit(internal::query_order_by_part &order_by_part) = 0;
virtual void visit(internal::query_order_by_asc_part &order_by_asc_part) = 0;
virtual void visit(internal::query_order_by_desc_part &order_by_desc_part) = 0;
virtual void visit(internal::query_offset_part &offset_part) = 0;
virtual void visit(internal::query_limit_part &limit_part) = 0;
virtual void visit(internal::query_select_part &part) = 0;
virtual void visit(internal::query_from_part &part) = 0;
virtual void visit(internal::query_join_part &part) = 0;
virtual void visit(internal::query_on_part &part) = 0;
virtual void visit(internal::query_where_part &part) = 0;
virtual void visit(internal::query_group_by_part &part) = 0;
virtual void visit(internal::query_order_by_part &part) = 0;
virtual void visit(internal::query_order_by_asc_part &part) = 0;
virtual void visit(internal::query_order_by_desc_part &part) = 0;
virtual void visit(internal::query_offset_part &part) = 0;
virtual void visit(internal::query_limit_part &part) = 0;
virtual void visit(internal::query_insert_part &insert_part) = 0;
virtual void visit(internal::query_into_part &into_part) = 0;
virtual void visit(internal::query_values_part &values_part) = 0;
virtual void visit(internal::query_insert_part &part) = 0;
virtual void visit(internal::query_into_part &part) = 0;
virtual void visit(internal::query_values_part &part) = 0;
virtual void visit(internal::query_update_part &update_part) = 0;
virtual void visit(internal::query_set_part &set_part) = 0;
virtual void visit(internal::query_update_part &part) = 0;
virtual void visit(internal::query_set_part &part) = 0;
virtual void visit(internal::query_delete_part &delete_part) = 0;
virtual void visit(internal::query_delete_from_part &delete_from_part) = 0;
virtual void visit(internal::query_delete_part &part) = 0;
virtual void visit(internal::query_delete_from_part &part) = 0;
virtual void visit(internal::query_create_part &create_part) = 0;
virtual void visit(internal::query_create_table_part &create_table_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_schema_part &part) = 0;
virtual void visit(internal::query_drop_part &drop_part) = 0;
virtual void visit(internal::query_drop_table_part &drop_table_part) = 0;
virtual void visit(internal::query_drop_part &part) = 0;
virtual void visit(internal::query_drop_table_part &part) = 0;
virtual void visit(internal::query_drop_schema_part &part) = 0;
};
}

View File

@ -136,58 +136,57 @@ private:
escape_identifier_t identifier_escape_type_ = escape_identifier_t::ESCAPE_BOTH_SAME;
std::string default_schema_name_;
// std::unique_ptr<query_compiler> compiler_;
token_to_string_map tokens_ {
{dialect_token::Create, "CREATE"},
{dialect_token::Drop, "DROP"},
{dialect_token::Remove, "DELETE"},
{dialect_token::Insert, "INSERT"},
{dialect_token::Alter, "ALTER"},
{dialect_token::Table, "TABLE"},
{dialect_token::Into, "INTO"},
{dialect_token::Values, "VALUES"},
{dialect_token::Update, "UPDATE"},
{dialect_token::Select, "SELECT"},
{dialect_token::Columns, "COLUMNS"},
{dialect_token::Column, "COLUMN"},
{dialect_token::From, "FROM"},
{dialect_token::Join, "LEFT JOIN"},
{dialect_token::On, "ON"},
{dialect_token::Where, "WHERE"},
{dialect_token::And, "AND"},
{dialect_token::Or, "OR"},
{dialect_token::Not, "NOT"},
{dialect_token::Like, "LIKE"},
{dialect_token::Between, "BETWEEN"},
{dialect_token::In, "IN"},
{dialect_token::OrderBy, "ORDER BY"},
{dialect_token::GroupBy, "GROUP BY"},
{dialect_token::Asc, "ASC"},
{dialect_token::Desc, "DESC"},
{dialect_token::Offset, "OFFSET"},
{dialect_token::Limit, "LIMIT"},
{dialect_token::As, "AS"},
{dialect_token::Offset, "OFFSET"},
{dialect_token::Distinct, "DISTINCT"},
{dialect_token::Set, "SET"},
{dialect_token::NotNull, "NOT NULL"},
{dialect_token::PrimaryKey, "PRIMARY KEY"},
{dialect_token::ForeignKey, "FOREIGN KEY"},
{dialect_token::References, "REFERENCES"},
{dialect_token::AddConstraint, "ADD CONSTRAINT"},
{dialect_token::DropConstraint, "DROP CONSTRAINT"},
{dialect_token::Alter, "ALTER"},
{dialect_token::And, "AND"},
{dialect_token::As, "AS"},
{dialect_token::Asc, "ASC"},
{dialect_token::Asterisk, "*"},
{dialect_token::Begin, "BEGIN TRANSACTION"},
{dialect_token::Commit, "COMMIT TRANSACTION"},
{dialect_token::Rollback, "ROLLBACK TRANSACTION"},
{dialect_token::StartQuote, "\""},
{dialect_token::EndQuote, "\""},
{dialect_token::StringQuote, "'"},
{dialect_token::BeginBinaryData, "X'"},
{dialect_token::EndBinaryData, "'"},
{dialect_token::BeginStringData, "'"},
{dialect_token::Between, "BETWEEN"},
{dialect_token::Column, "COLUMN"},
{dialect_token::Columns, "COLUMNS"},
{dialect_token::Commit, "COMMIT TRANSACTION"},
{dialect_token::Create, "CREATE"},
{dialect_token::Desc, "DESC"},
{dialect_token::Distinct, "DISTINCT"},
{dialect_token::Drop, "DROP"},
{dialect_token::DropConstraint, "DROP CONSTRAINT"},
{dialect_token::EndBinaryData, "'"},
{dialect_token::EndQuote, "\""},
{dialect_token::EndStringData, "'"},
{dialect_token::None, ""}
{dialect_token::ForeignKey, "FOREIGN KEY"},
{dialect_token::From, "FROM"},
{dialect_token::GroupBy, "GROUP BY"},
{dialect_token::In, "IN"},
{dialect_token::Insert, "INSERT"},
{dialect_token::Into, "INTO"},
{dialect_token::Join, "LEFT JOIN"},
{dialect_token::Like, "LIKE"},
{dialect_token::Limit, "LIMIT"},
{dialect_token::None, ""},
{dialect_token::Not, "NOT"},
{dialect_token::NotNull, "NOT NULL"},
{dialect_token::Offset, "OFFSET"},
{dialect_token::On, "ON"},
{dialect_token::Or, "OR"},
{dialect_token::OrderBy, "ORDER BY"},
{dialect_token::PrimaryKey, "PRIMARY KEY"},
{dialect_token::References, "REFERENCES"},
{dialect_token::Remove, "DELETE"},
{dialect_token::Rollback, "ROLLBACK TRANSACTION"},
{dialect_token::Select, "SELECT"},
{dialect_token::Set, "SET"},
{dialect_token::StartQuote, "\""},
{dialect_token::StringQuote, "'"},
{dialect_token::Table, "TABLE"},
{dialect_token::Update, "UPDATE"},
{dialect_token::Values, "VALUES"},
{dialect_token::Where, "WHERE"}
};
data_type_to_string_map data_types_ {

View File

@ -6,59 +6,57 @@
namespace matador::sql {
enum class dialect_token : uint8_t {
Create = 0,
Drop,
Remove,
Insert,
Update,
Select,
AddConstraint = 0,
Alter,
ForeignKey,
PrimaryKey,
AddConstraint,
DropConstraint,
References,
Schema,
Database,
Table,
Values,
InsertValues,
Columns,
Column,
From,
Join,
On,
Into,
Where,
WhereClause,
And,
Or,
Not,
Like,
Between,
In,
OrderBy,
GroupBy,
Asc,
Desc,
Limit,
As,
Offset,
Distinct,
Set,
UpdateValues,
NotNull,
Asc,
Asterisk,
Begin,
Commit,
Rollback,
StartQuote,
EndQuote,
StringQuote,
BeginBinaryData,
EndBinaryData,
BeginStringData,
Between,
Column,
Columns,
Commit,
Create,
Database,
Desc,
Distinct,
Drop,
DropConstraint,
EndBinaryData,
EndQuote,
EndStringData,
None
ForeignKey,
From,
GroupBy,
In,
Insert,
Into,
Join,
Like,
Limit,
None,
Not,
NotNull,
Offset,
On,
Or,
OrderBy,
PrimaryKey,
References,
Remove,
Rollback,
Schema,
Select,
Set,
StartQuote,
StringQuote,
Table,
Update,
Values,
Where
};
}

View File

@ -10,6 +10,7 @@ namespace matador::sql {
enum class sql_command {
SQL_UNKNOWN,
SQL_CREATE,
SQL_CREATE_TABLE,
SQL_CREATE_SCHEMA,
SQL_CREATE_DATABASE,
@ -17,6 +18,7 @@ enum class sql_command {
SQL_INSERT,
SQL_DELETE,
SQL_SELECT,
SQL_DROP,
SQL_DROP_TABLE,
SQL_DROP_SCHEMA,
SQL_DROP_DATABASE,

View File

@ -10,8 +10,7 @@ namespace matador::sql {
struct column;
class record
{
class record final {
private:
using field_ref = std::reference_wrapper<field>;
using field_by_index = std::vector<field_ref>;
@ -45,13 +44,11 @@ public:
[[nodiscard]] const field& at(const column &col) const;
[[nodiscard]] const field& at(size_t index) const;
template<class Type>
std::optional<Type> at(const column &col) const
{
std::optional<Type> at(const column &col) const {
return at(col).as<Type>();
}
template<class Type>
std::optional<Type> at(size_t index) const
{
std::optional<Type> at(const size_t index) const {
return at(index).as<Type>();
}
@ -70,8 +67,6 @@ public:
[[nodiscard]] bool empty() const;
void clear();
// [[nodiscard]] bool unknown() const;
private:
void init();
void add_to_map(field &col, size_t index);
@ -79,8 +74,6 @@ private:
private:
field_by_index fields_;
field_by_name_map fields_by_name_;
// int pk_index_{-1};
};
}

View File

@ -68,7 +68,7 @@ public:
return bus_.subscribe<EventType>(handler);
}
connection_pool& pool() const;
[[nodiscard]] connection_pool& pool() const;
private:
size_t max_size_{};

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

View File

@ -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));
}

View File

@ -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()));
}
}

View File

@ -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_};
}
}

View File

@ -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_};
}

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_;
}
}

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);
}
}

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});
}

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)

View File

@ -66,6 +66,14 @@ TEST_CASE_METHOD(QueryFixture, "Test drop table sql statement string", "[query]"
REQUIRE(result == R"(DROP TABLE "person")");
}
TEST_CASE_METHOD(QueryFixture, "Test select all columns with asterisk", "[query][select][asterisk]") {
const auto result = query::select()
.from("person")
.str(*db);
REQUIRE(result == R"(SELECT * FROM "person")");
}
TEST_CASE_METHOD(QueryFixture, "Test select sql statement string", "[query]") {
const auto result = query::select({"id", "name", "age"})
.from("person")

View File

@ -172,11 +172,11 @@ TEST_CASE("Test LRU cache evicts oldest entries", "[statement][cache][evict]") {
result = cache.acquire({"SELECT title FROM book"});
REQUIRE(result);
auto stmt2 = result.value();
result = cache.acquire({"SELECT name FROM author"}); // Should evict first statement
result = cache.acquire({"SELECT name FROM author"}); // Should evict the first statement
REQUIRE(result);
auto stmt3 = result.value();
// Trigger re-prepare of evicted statement
// Trigger re-prepares of an evicted statement
result = cache.acquire({"SELECT 1"});
REQUIRE(result);
auto stmt4 = result.value();
@ -317,6 +317,7 @@ TEST_CASE("Race condition simulation with mixed access", "[statement_cache][race
};
std::vector<std::thread> jobs;
jobs.reserve(threads);
for (int i = 0; i < threads; ++i) {
jobs.emplace_back(task, i);
}