schema creation progress

This commit is contained in:
Sascha Kühl 2025-12-05 07:32:59 +01:00
parent d2f1bc0b8e
commit 98da0884f1
12 changed files with 122 additions and 117 deletions

View File

@ -234,7 +234,7 @@ utils::result<std::vector<object::attribute>, utils::error> postgres_connection:
} }
char *end = nullptr; char *end = nullptr;
// Todo: Handle error // Todo: Handle error
auto index = strtoul(reader.column(0), &end, 10) - 1; // auto index = strtoul(reader.column(0), &end, 10) - 1;
std::string name = reader.column(1); std::string name = reader.column(1);
// Todo: extract size // Todo: extract size

View File

@ -99,6 +99,7 @@ public:
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name) const; [[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name) const;
utils::result<void, utils::error> create_schema() const; utils::result<void, utils::error> create_schema() const;
utils::result<void, utils::error> drop_schema() const;
/** /**
* Insert the given object into the session. * Insert the given object into the session.
@ -144,6 +145,7 @@ private:
friend class query_select; friend class query_select;
static query::fetchable_query build_select_query(entity_query_data &&data); static query::fetchable_query build_select_query(entity_query_data &&data);
static sql::query_context build_add_constraint_context(const std::string& table_name, const class object::constraint& cons, const sql::connection_ptr &conn) ;
private: private:
mutable sql::statement_cache cache_; mutable sql::statement_cache cache_;

View File

@ -9,7 +9,7 @@ class query_alter_intermediate : public query_intermediate {
public: public:
query_alter_intermediate(); query_alter_intermediate();
query_alter_table_intermediate table(const table &tab) const; [[nodiscard]] query_alter_table_intermediate table(const table &tab) const;
}; };
} }

View File

@ -36,7 +36,6 @@ public:
using query_intermediate::query_intermediate; using query_intermediate::query_intermediate;
query_add_key_constraint_intermediate add_constraint(const std::string& name); query_add_key_constraint_intermediate add_constraint(const std::string& name);
executable_query add_constraint(const class object::constraint& constraint);
executable_query drop_constraint(const std::string& name); executable_query drop_constraint(const std::string& name);
}; };
} }

View File

@ -84,38 +84,34 @@ utils::result<void, utils::error> schema::create() const {
} }
utils::result<void, utils::error> schema::drop() const { utils::result<void, utils::error> schema::drop() const {
std::vector<std::string> drop_sql_commands;
auto c = pool_.acquire(); auto c = pool_.acquire();
// drop table constraints
for (const auto &node: repo_) { for (const auto &node: repo_) {
auto ctx = query::query::drop() for (const auto& cons : node->info().constraints()) {
.table(node->name()) auto ctx = query::query::alter()
.compile(*c); .table(node->name())
.drop_constraint(cons.name())
.compile(*c);
drop_sql_commands.push_back(ctx.sql); std::cout << ctx.sql << std::endl;
// determine constraints and drop them if (auto result = c->execute(ctx.sql); !result) {
for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
const auto& endpoint = *(it->second);
if (endpoint.type() == object::relation_type::BELONGS_TO) {
continue;
}
const auto drop_fk_ctx = query::query::alter()
.table( endpoint.node().name() )
.drop_constraint( "FK_" + endpoint.node().name() + "_" + endpoint.foreign_endpoint()->field_name() )
.compile(*c);
std::cout << drop_fk_ctx.sql << std::endl;
if (auto result = c->execute(drop_fk_ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
} }
// execute additional commands (e.g. ALTER TABLE ADD FK) // drop table
for (const auto &sql: drop_sql_commands) { for (const auto &node: repo_) {
std::cout << sql << std::endl; auto ctx = query::query::drop()
if (auto result = c->execute(sql); !result) { .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::failure(result.err());
} }
} }
return utils::ok<void>(); return utils::ok<void>();
} }

View File

@ -20,59 +20,110 @@ session::session(session_context&& ctx)
utils::result<void, utils::error> session::create_schema() const { utils::result<void, utils::error> session::create_schema() const {
// Step 1: Build dependency graph // Step 1: Build dependency graph
std::unordered_map<std::string, std::vector<std::string> > 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; // std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree;
for (const auto &node: *schema_) { // for (const auto &node: *schema_) {
for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) { // for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
dependency_graph[node->name()].push_back(it->second->node().name()); // 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;
// }
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;
auto c = cache_.pool().acquire(); auto c = cache_.pool().acquire();
for (const auto &node: *schema_) { for (const auto &node: *schema_) {
auto ctx = query::query::create() auto ctx = query::query::create()
.table(node->name()) .table(node->name())
.columns(node->info().attributes()) .columns(node->info().attributes())
.constraints(node->info().constraints())
.compile(*c); .compile(*c);
// for ( const auto& [sql, command] : ctx.additional_commands ) {
// fk_sql_commands.push_back( sql );
// }
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = c->execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
// execute additional commands (e.g. ALTER TABLE ADD FK) // create table constraints
for (const auto &sql: fk_sql_commands) { for (const auto &node: *schema_) {
std::cout << sql << std::endl; for (const auto& cons : node->info().constraints()) {
if (auto result = c->execute(sql); !result) { auto ctx = build_add_constraint_context(node->name(), cons, c);
std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) {
return utils::failure(result.err());
}
}
}
return utils::ok<void>();
}
sql::query_context session::build_add_constraint_context(const std::string& table_name, const class object::constraint& cons, const sql::connection_ptr &conn) {
if (cons.is_foreign_key_constraint()) {
return query::query::alter()
.table(table_name)
.add_constraint( cons.name() )
.foreign_key(cons.column_name())
.references(cons.ref_table_name(), {cons.ref_column_name()})
.compile(*conn);
}
if (cons.is_primary_key_constraint()) {
return query::query::alter()
.table(table_name)
.add_constraint( cons.name() )
.primary_key(cons.column_name())
.compile(*conn);
}
return {};
}
utils::result<void, utils::error> session::drop_schema() const {
auto c = cache_.pool().acquire();
// drop table constraints
for (const auto &node: *schema_) {
for (const auto& cons : node->info().constraints()) {
auto ctx = query::query::alter()
.table(node->name())
.drop_constraint(cons.name())
.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: *schema_) {
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::failure(result.err());
} }
} }
return utils::ok<void>(); return utils::ok<void>();
} }

View File

@ -35,10 +35,6 @@ query_add_key_constraint_intermediate query_alter_table_intermediate::add_constr
return {context_}; return {context_};
} }
executable_query query_alter_table_intermediate::add_constraint( const class object::constraint& constraint ) {
return {context_};
}
executable_query query_alter_table_intermediate::drop_constraint( const std::string& name ) { executable_query query_alter_table_intermediate::drop_constraint( const std::string& name ) {
context_->parts.push_back(std::make_unique<internal::query_drop_key_constraint_part>(name)); context_->parts.push_back(std::make_unique<internal::query_drop_key_constraint_part>(name));
return {context_}; return {context_};

View File

@ -36,9 +36,6 @@ 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) { std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const query_data &data, const column &col) {
// ctx.result_vars.emplace_back(col.column_name());
const auto& column_table = col.table().get();
// ctx.column_aliases.insert({column_table->has_alias() ? column_table->alias() : column_table->name() + "." + col.column_name(), col.alias()});
if (col.is_function()) { if (col.is_function()) {
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.column_name()); ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.column_name());
ctx.prototype.back().change_type(utils::basic_type::type_int32); ctx.prototype.back().change_type(utils::basic_type::type_int32);
@ -153,7 +150,6 @@ void query_compiler::visit(internal::query_select_part &part) {
void query_compiler::visit(internal::query_from_part &part) { void query_compiler::visit(internal::query_from_part &part) {
query_.table_name = part.table().name(); query_.table_name = part.table().name();
query_.sql += " " + build_table_name(part.token(), *dialect_, part.table()); query_.sql += " " + build_table_name(part.token(), *dialect_, part.table());
// query_.table_aliases.insert({query_.table_name, part.table().alias()});
} }
void query_compiler::visit(internal::query_join_part &part) void query_compiler::visit(internal::query_join_part &part)
@ -177,40 +173,33 @@ void query_compiler::visit(internal::query_group_by_part &part) {
query_.sql += " " + dialect_->group_by() + " " + prepare_identifier(*dialect_, part.column()); query_.sql += " " + dialect_->group_by() + " " + prepare_identifier(*dialect_, part.column());
} }
void query_compiler::visit(internal::query_order_by_part &part) void query_compiler::visit(internal::query_order_by_part &part) {
{
query_.sql += " " + dialect_->order_by() + query_.sql += " " + dialect_->order_by() +
" " + prepare_criteria(*dialect_, part.column()); " " + prepare_criteria(*dialect_, part.column());
} }
void query_compiler::visit(internal::query_order_by_asc_part &/*order_by_asc_part*/) void query_compiler::visit(internal::query_order_by_asc_part &/*order_by_asc_part*/) {
{
query_.sql += " " + dialect_->asc(); query_.sql += " " + dialect_->asc();
} }
void query_compiler::visit(internal::query_order_by_desc_part &/*order_by_desc_part*/) void query_compiler::visit(internal::query_order_by_desc_part &/*order_by_desc_part*/) {
{
query_.sql += " " + dialect_->desc(); query_.sql += " " + dialect_->desc();
} }
void query_compiler::visit(internal::query_offset_part &part) void query_compiler::visit(internal::query_offset_part &part) {
{
query_.sql += " " + dialect_->offset() + " " + std::to_string(part.offset()); query_.sql += " " + dialect_->offset() + " " + std::to_string(part.offset());
} }
void query_compiler::visit(internal::query_limit_part &part) void query_compiler::visit(internal::query_limit_part &part) {
{
query_.sql += " " + dialect_->limit() + " " + std::to_string(part.limit()); query_.sql += " " + dialect_->limit() + " " + std::to_string(part.limit());
} }
void query_compiler::visit(internal::query_insert_part &/*insert_part*/) void query_compiler::visit(internal::query_insert_part &/*insert_part*/) {
{
query_.command = sql::sql_command::SQL_INSERT; query_.command = sql::sql_command::SQL_INSERT;
query_.sql = dialect_->insert(); query_.sql = dialect_->insert();
} }
void query_compiler::visit(internal::query_into_part &part) void query_compiler::visit(internal::query_into_part &part) {
{
query_.table_name = part.table().name(); query_.table_name = part.table().name();
query_.sql += " " + dialect_->into() + query_.sql += " " + dialect_->into() +
" " + dialect_->prepare_identifier_string(part.table().name()); " " + dialect_->prepare_identifier_string(part.table().name());
@ -383,14 +372,12 @@ void query_compiler::visit(internal::query_set_part &part) {
query_.sql += result; query_.sql += result;
} }
void query_compiler::visit(internal::query_drop_table_part &part) void query_compiler::visit(internal::query_drop_table_part &part) {
{
query_.table_name = part.table().name(); query_.table_name = part.table().name();
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name); query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name);
} }
std::string build_create_column(const object::attribute &col, const sql::dialect &d) std::string build_create_column(const object::attribute &col, const sql::dialect &d) {
{
std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type()); std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type());
if (col.attributes().size() > 0) { if (col.attributes().size() > 0) {
result.append("(" + std::to_string(col.attributes().size()) + ")"); result.append("(" + std::to_string(col.attributes().size()) + ")");
@ -433,8 +420,7 @@ std::string build_constraint(const class object::constraint& cons, const sql::di
return result; return result;
} }
std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) {
{
return d.token_at(token) + " " + return d.token_at(token) + " " +
(!d.default_schema_name().empty() ? d.prepare_identifier_string(d.default_schema_name()) + "." : "") + (!d.default_schema_name().empty() ? d.prepare_identifier_string(d.default_schema_name()) + "." : "") +
d.prepare_identifier_string(t.name()) + d.prepare_identifier_string(t.name()) +

View File

@ -50,7 +50,7 @@ TEST_CASE_METHOD( QueryFixture, "Insert and select basic datatypes", "[query][da
ullval = (std::numeric_limits<long long>::max)(); ullval = (std::numeric_limits<long long>::max)();
} }
bool bval = true; bool bval = true;
const char *cstr("Armer schwarzer Kater"); // const char *cstr("Armer schwarzer Kater");
std::string varcharval("hallo welt"); std::string varcharval("hallo welt");
std::string strval = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam " std::string strval = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam "
"nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " "nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, "

View File

@ -5,13 +5,12 @@
namespace matador::test { namespace matador::test {
SessionFixture::SessionFixture() SessionFixture::SessionFixture()
: pool(connection::dns, 4), ses({bus, pool}) {} : pool(connection::dns, 4)
, ses({bus, pool}) {}
SessionFixture::~SessionFixture() { SessionFixture::~SessionFixture() {
while (!tables_to_drop.empty()) { const auto result = ses.drop_schema();
drop_table_if_exists(tables_to_drop.top()); REQUIRE(result.is_ok());
tables_to_drop.pop();
}
} }
void SessionFixture::drop_table_if_exists(const std::string &table_name) const { void SessionFixture::drop_table_if_exists(const std::string &table_name) const {

View File

@ -18,7 +18,6 @@ public:
protected: protected:
sql::connection_pool pool; sql::connection_pool pool;
std::stack <std::string> tables_to_drop;
orm::session ses; orm::session ses;
utils::message_bus bus; utils::message_bus bus;

View File

@ -20,8 +20,6 @@ TEST_CASE_METHOD(SessionFixture, "Session insert test", "[session][insert]") {
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
tables_to_drop.emplace("airplanes");
auto plane = ses.insert<airplane>(1, "Boeing", "A380"); auto plane = ses.insert<airplane>(1, "Boeing", "A380");
REQUIRE(plane.is_ok()); REQUIRE(plane.is_ok());
@ -38,8 +36,6 @@ TEST_CASE_METHOD(SessionFixture, "Session update test", "[session][update]") {
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
tables_to_drop.emplace("airplanes");
auto result = ses.insert<airplane>(1, "Boeing", "747"); auto result = ses.insert<airplane>(1, "Boeing", "747");
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
@ -70,8 +66,6 @@ TEST_CASE_METHOD(SessionFixture, "Session delete test", "[session][delete]") {
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
tables_to_drop.emplace("airplanes");
auto result = ses.insert<airplane>(1, "Boeing", "747"); auto result = ses.insert<airplane>(1, "Boeing", "747");
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
@ -94,9 +88,6 @@ TEST_CASE_METHOD(SessionFixture, "Session relation test", "[session][relation]")
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
tables_to_drop.emplace("airplanes");
tables_to_drop.emplace("flights");
auto plane = ses.insert<airplane>(1, "Boeing", "A380"); auto plane = ses.insert<airplane>(1, "Boeing", "A380");
REQUIRE(plane.is_ok()); REQUIRE(plane.is_ok());
auto f = ses.insert<flight>(2, *plane, "sully"); auto f = ses.insert<flight>(2, *plane, "sully");
@ -118,8 +109,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find object with id", "[session
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
tables_to_drop.emplace("airplanes");
auto a380 = ses.insert<airplane>(1, "Boeing", "A380"); auto a380 = ses.insert<airplane>(1, "Boeing", "A380");
REQUIRE(a380.is_ok()); REQUIRE(a380.is_ok());
@ -139,8 +128,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects", "[session][f
.and_then([this] { return ses.create_schema(); } ); .and_then([this] { return ses.create_schema(); } );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
tables_to_drop.emplace("airplanes");
std::vector<std::unique_ptr<airplane>> planes; std::vector<std::unique_ptr<airplane>> planes;
planes.emplace_back(new airplane(1, "Airbus", "A380")); planes.emplace_back(new airplane(1, "Airbus", "A380"));
planes.emplace_back(new airplane(2, "Boeing", "707")); planes.emplace_back(new airplane(2, "Boeing", "707"));
@ -174,9 +161,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with one-to-ma
.and_then( [this] { return ses.attach<book>("books"); } ) .and_then( [this] { return ses.attach<book>("books"); } )
.and_then( [this] { return ses.create_schema(); } ); .and_then( [this] { return ses.create_schema(); } );
tables_to_drop.emplace("authors");
tables_to_drop.emplace("books");
std::vector<std::unique_ptr<author>> authors; std::vector<std::unique_ptr<author>> authors;
authors.emplace_back(new author{1, "Michael", "Crichton", "23.10.1942", 1975, true, {}}); authors.emplace_back(new author{1, "Michael", "Crichton", "23.10.1942", 1975, true, {}});
authors.emplace_back(new author{ 2, "Steven", "King", "21.9.1947", 1956, false, {}}); authors.emplace_back(new author{ 2, "Steven", "King", "21.9.1947", 1956, false, {}});
@ -227,9 +211,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with one-to-ma
.and_then( [this] { return ses.attach<employee>("employees"); } ) .and_then( [this] { return ses.attach<employee>("employees"); } )
.and_then( [this] { return ses.create_schema(); } ); .and_then( [this] { return ses.create_schema(); } );
tables_to_drop.emplace("departments");
tables_to_drop.emplace("employees");
std::vector<std::unique_ptr<department>> departments; std::vector<std::unique_ptr<department>> departments;
departments.emplace_back(new department{1, "Insurance", {}}); departments.emplace_back(new department{1, "Insurance", {}});
departments.emplace_back(new department{ 2, "Invoice", {}}); departments.emplace_back(new department{ 2, "Invoice", {}});
@ -283,10 +264,6 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with many-to-m
.and_then( [this] { return ses.attach<ingredient>("ingredients"); } ) .and_then( [this] { return ses.attach<ingredient>("ingredients"); } )
.and_then( [this] { return ses.create_schema(); } ); .and_then( [this] { return ses.create_schema(); } );
tables_to_drop.emplace("recipes");
tables_to_drop.emplace("ingredients");
tables_to_drop.emplace("recipe_ingredients");
std::vector<std::unique_ptr<ingredient>> ingredients; std::vector<std::unique_ptr<ingredient>> ingredients;
ingredients.push_back(std::make_unique<ingredient>(1, "Apple")); ingredients.push_back(std::make_unique<ingredient>(1, "Apple"));
ingredients.push_back(std::make_unique<ingredient>(2, "Strawberry")); ingredients.push_back(std::make_unique<ingredient>(2, "Strawberry"));