From 4c6332202473783a733a59fc41ddcc6080597c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Wed, 11 Feb 2026 16:01:44 +0100 Subject: [PATCH] identity generator progress --- backends/postgres/src/postgres_dialect.cpp | 22 +++++++------- include/matador/query/builder.hpp | 1 + .../query_create_intermediate.hpp | 6 ++++ include/matador/query/table.hpp | 2 -- include/matador/sql/dialect.hpp | 6 ++-- include/matador/sql/dialect_token.hpp | 1 + include/matador/utils/constraints.hpp | 9 +++--- source/orm/query/builder.cpp | 5 ++++ .../query_create_intermediate.cpp | 3 ++ source/orm/query/query_builder.cpp | 3 ++ source/orm/query/schema.cpp | 30 ------------------- source/orm/query/table.cpp | 6 ---- source/orm/sql/dialect.cpp | 4 +++ test/backends/SchemaTest.cpp | 6 ++-- test/orm/backend/test_connection.cpp | 4 +-- test/orm/backend/test_connection.hpp | 3 +- test/orm/backend/test_statement.cpp | 4 +-- test/orm/backend/test_statement.hpp | 3 +- test/orm/query/QueryBuilderTest.cpp | 11 +++++++ test/utils/record_printer.cpp | 8 ++--- 20 files changed, 68 insertions(+), 69 deletions(-) diff --git a/backends/postgres/src/postgres_dialect.cpp b/backends/postgres/src/postgres_dialect.cpp index 0a7a957..50e5e76 100644 --- a/backends/postgres/src/postgres_dialect.cpp +++ b/backends/postgres/src/postgres_dialect.cpp @@ -4,8 +4,7 @@ #include "matador/utils/basic_types.hpp" -[[maybe_unused]] const matador::sql::dialect *get_dialect() -{ +[[maybe_unused]] const matador::sql::dialect *get_dialect() { using namespace matador::sql; const static dialect d = dialect_builder::builder() .create() @@ -13,16 +12,17 @@ return "$" + std::to_string(index); }) .with_token_replace_map({ - {dialect_token::BeginBinaryData, "'\\x"} - }) + {dialect_token::BeginBinaryData, "'\\x"}, + {dialect_token::Identity, "GENERATED BY DEFAULT AS IDENTITY"} + }) .with_data_type_replace_map({ - {matador::utils::basic_type::Int8, "SMALLINT"}, - {matador::utils::basic_type::UInt8, "SMALLINT"}, - {matador::utils::basic_type::Float, "REAL"}, - {matador::utils::basic_type::Double, "DOUBLE PRECISION"}, - {matador::utils::basic_type::Time, "TIME(6)"}, - {matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"}, - {matador::utils::basic_type::Blob, "BYTEA"} + {matador::utils::basic_type::Int8, "SMALLINT"}, + {matador::utils::basic_type::UInt8, "SMALLINT"}, + {matador::utils::basic_type::Float, "REAL"}, + {matador::utils::basic_type::Double, "DOUBLE PRECISION"}, + {matador::utils::basic_type::Time, "TIME(6)"}, + {matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"}, + {matador::utils::basic_type::Blob, "BYTEA"} }) .with_bool_strings("TRUE", "FALSE") .with_default_schema_name("public") diff --git a/include/matador/query/builder.hpp b/include/matador/query/builder.hpp index 755d722..2f81364 100644 --- a/include/matador/query/builder.hpp +++ b/include/matador/query/builder.hpp @@ -70,6 +70,7 @@ public: column_builder& not_null(); column_builder& primary_key(); column_builder& unique(); + column_builder& identity(); private: std::string column_name_; diff --git a/include/matador/query/intermediates/query_create_intermediate.hpp b/include/matador/query/intermediates/query_create_intermediate.hpp index 0db55e9..5608e5a 100644 --- a/include/matador/query/intermediates/query_create_intermediate.hpp +++ b/include/matador/query/intermediates/query_create_intermediate.hpp @@ -36,11 +36,17 @@ public: query_create_table_columns_intermediate columns(const std::vector &columns); }; +class query_create_sequence_intermediate : public executable_query { +public: + using executable_query::executable_query; +}; + class query_create_intermediate : public query_intermediate { public: query_create_intermediate(); query_create_table_intermediate table(const table &tab); + query_create_sequence_intermediate sequence(const std::string &sequence_name); executable_query schema(const std::string &schema_name); }; diff --git a/include/matador/query/table.hpp b/include/matador/query/table.hpp index c853066..9c7dee6 100644 --- a/include/matador/query/table.hpp +++ b/include/matador/query/table.hpp @@ -52,8 +52,6 @@ private: std::vector columns_; }; -table operator ""_tab(const char *name, size_t len); - template class typed_table : public table { public: diff --git a/include/matador/sql/dialect.hpp b/include/matador/sql/dialect.hpp index cf1f285..105b29e 100644 --- a/include/matador/sql/dialect.hpp +++ b/include/matador/sql/dialect.hpp @@ -148,6 +148,7 @@ public: [[nodiscard]] const std::string& foreign_key() const; [[nodiscard]] const std::string& from() const; [[nodiscard]] const std::string& group_by() const; + [[nodiscard]] const std::string& identity() const; [[nodiscard]] const std::string& in() const; [[nodiscard]] const std::string& insert() const; [[nodiscard]] const std::string& into() const; @@ -213,9 +214,10 @@ private: {dialect_token::EndBinaryData, "'"}, {dialect_token::EndQuote, "\""}, {dialect_token::EndStringData, "'"}, - {dialect_token::ForeignKey, "FOREIGN KEY"}, + {dialect_token::ForeignKey, "FOREIGN KEY"}, {dialect_token::From, "FROM"}, {dialect_token::GroupBy, "GROUP BY"}, + {dialect_token::Identity, "AUTO INCREMENT"}, {dialect_token::In, "IN"}, {dialect_token::Insert, "INSERT"}, {dialect_token::Into, "INTO"}, @@ -238,7 +240,7 @@ private: {dialect_token::Schema, "SCHEMA"}, {dialect_token::Select, "SELECT"}, {dialect_token::Set, "SET"}, - {dialect_token::StartQuote, "\""}, + {dialect_token::StartQuote, "\""}, {dialect_token::StringQuote, "'"}, {dialect_token::Table, "TABLE"}, {dialect_token::Unique, "UNIQUE"}, diff --git a/include/matador/sql/dialect_token.hpp b/include/matador/sql/dialect_token.hpp index f40a523..770d489 100644 --- a/include/matador/sql/dialect_token.hpp +++ b/include/matador/sql/dialect_token.hpp @@ -32,6 +32,7 @@ enum class dialect_token : uint8_t { ForeignKey, From, GroupBy, + Identity, In, Insert, Into, diff --git a/include/matador/utils/constraints.hpp b/include/matador/utils/constraints.hpp index 99e8e62..429c015 100644 --- a/include/matador/utils/constraints.hpp +++ b/include/matador/utils/constraints.hpp @@ -7,10 +7,11 @@ enum class constraints : unsigned char { None = 0, Index = 1 << 0, Unique = 1 << 1, - PrimaryKey = 1 << 2, - ForeignKey = 1 << 3, - Default = 1 << 4, - NotNull = 1 << 5 + PrimaryKey = 1 << 2, + ForeignKey = 1 << 3, + Identity = 1 << 4, + Default = 1 << 5, + NotNull = 1 << 6 }; inline constraints operator|(constraints a, constraints b) { return static_cast(static_cast(a) | static_cast(b)); } diff --git a/source/orm/query/builder.cpp b/source/orm/query/builder.cpp index 50e072c..ff5dd78 100644 --- a/source/orm/query/builder.cpp +++ b/source/orm/query/builder.cpp @@ -26,6 +26,11 @@ column_builder & column_builder::unique() { return *this; } +column_builder& column_builder::identity() { + constraints_ |= utils::constraints::Identity; + return *this; +} + table_builder::table_builder(std::string name) : table_name( std::move(name) ) {} diff --git a/source/orm/query/intermediates/query_create_intermediate.cpp b/source/orm/query/intermediates/query_create_intermediate.cpp index d7567a5..646ef84 100644 --- a/source/orm/query/intermediates/query_create_intermediate.cpp +++ b/source/orm/query/intermediates/query_create_intermediate.cpp @@ -18,6 +18,9 @@ query_create_table_intermediate query_create_intermediate::table(const class tab context_->parts.push_back(std::make_unique(tab)); return {context_}; } +query_create_sequence_intermediate query_create_intermediate::sequence(const std::string& sequence_name) { + return {context_}; +} executable_query query_create_intermediate::schema( const std::string& schema_name ) { context_->parts.push_back(std::make_unique(schema_name)); diff --git a/source/orm/query/query_builder.cpp b/source/orm/query/query_builder.cpp index 5c6d5c2..47ea193 100644 --- a/source/orm/query/query_builder.cpp +++ b/source/orm/query/query_builder.cpp @@ -378,6 +378,9 @@ void build_create_column(std::string &out, const table_column &col, const sql::d if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) { out.append(" ").append(d.unique()); } + if (is_constraint_set(col.attributes().options(), utils::constraints::Identity)) { + out.append(" ").append(d.identity()); + } if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) { out.append(" ").append(d.primary_key()); } diff --git a/source/orm/query/schema.cpp b/source/orm/query/schema.cpp index 730b54f..55e5404 100644 --- a/source/orm/query/schema.cpp +++ b/source/orm/query/schema.cpp @@ -13,35 +13,6 @@ namespace matador::query { utils::result schema::create(const sql::connection &conn) const { - // Step 1: Build dependency graph - // std::unordered_map > dependency_graph; - // std::unordered_map> 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 fk_sql_commands; const auto q = query::create().schema(repo_.name()).compile(conn); @@ -52,7 +23,6 @@ utils::result schema::create(const sql::connection &conn) co auto ctx = query::query::create() .table(node.name()) .columns(node.info().attributes()) - // .constraints(node->info().constraints()) .compile(conn); std::cout << ctx.sql << std::endl; diff --git a/source/orm/query/table.cpp b/source/orm/query/table.cpp index 03f8517..100f1e5 100644 --- a/source/orm/query/table.cpp +++ b/source/orm/query/table.cpp @@ -103,10 +103,4 @@ const table_column& table::create_column(class table &tab, const std::string &na tab.columns_.back().table(&tab); return tab.columns_.back(); } - - -table operator ""_tab(const char *name, size_t len) { - return {{name, len}}; -} - } diff --git a/source/orm/sql/dialect.cpp b/source/orm/sql/dialect.cpp index 0a70b5d..cc72e6b 100644 --- a/source/orm/sql/dialect.cpp +++ b/source/orm/sql/dialect.cpp @@ -175,6 +175,10 @@ const std::string &dialect::from() const { return token_at(dialect_token::From); } +const std::string &dialect::identity() const { + return token_at(dialect_token::Identity); +} + const std::string &dialect::in() const { return token_at(dialect_token::In); } diff --git a/test/backends/SchemaTest.cpp b/test/backends/SchemaTest.cpp index 560ee56..10a3d86 100644 --- a/test/backends/SchemaTest.cpp +++ b/test/backends/SchemaTest.cpp @@ -17,10 +17,8 @@ TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-man using namespace matador::test; query::schema repo; - // auto result = repo.attach("departments") - // .and_then([&repo] { return repo.attach("employees"); }); - auto result = repo.attach("employees") - .and_then([&repo] { return repo.attach("departments"); }); + auto result = repo.attach("departments") + .and_then([&repo] { return repo.attach("employees"); }); REQUIRE(result); auto conn = pool.acquire(); diff --git a/test/orm/backend/test_connection.cpp b/test/orm/backend/test_connection.cpp index 12915fe..49eb048 100644 --- a/test/orm/backend/test_connection.cpp +++ b/test/orm/backend/test_connection.cpp @@ -44,8 +44,8 @@ utils::result test_connection::server_version() co return utils::ok(utils::version{3, 2, 1}); } -utils::result test_connection::execute(const std::string &/*stmt*/) { - return utils::ok(static_cast(4)); +utils::result test_connection::execute(const sql::query_context &/*context*/) { + return utils::ok(sql::execute_result{4}); } utils::result, utils::error> test_connection::fetch(const sql::query_context &context) { diff --git a/test/orm/backend/test_connection.hpp b/test/orm/backend/test_connection.hpp index 9d83516..ef95731 100644 --- a/test/orm/backend/test_connection.hpp +++ b/test/orm/backend/test_connection.hpp @@ -2,6 +2,7 @@ #define QUERY_NOOP_CONNECTION_HPP #include "matador/sql/interface/connection_impl.hpp" +#include "matador/sql/execute_result.hpp" namespace matador::test::orm { @@ -16,7 +17,7 @@ public: [[nodiscard]] utils::result is_valid() const override; [[nodiscard]] utils::result client_version() const override; [[nodiscard]] utils::result server_version() const override; - utils::result execute(const std::string &stmt) override; + utils::result execute(const sql::query_context &context) override; utils::result, utils::error> fetch(const sql::query_context &context) override; utils::result, utils::error> prepare(const sql::query_context &context) override; utils::result, utils::error> describe(const std::string &table) override; diff --git a/test/orm/backend/test_statement.cpp b/test/orm/backend/test_statement.cpp index 8a63b50..42ab5bb 100644 --- a/test/orm/backend/test_statement.cpp +++ b/test/orm/backend/test_statement.cpp @@ -10,12 +10,12 @@ namespace matador::test::orm { test_statement::test_statement(const sql::query_context &query) : statement_impl(query, 0) {} -utils::result test_statement::execute(const sql::parameter_binder &/*bindings*/) { +utils::result test_statement::execute(const sql::parameter_binder &/*bindings*/) { using namespace std::chrono_literals; std::mt19937 rng(query_.sql.size()); std::uniform_int_distribution dist(10, 50); std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng))); - return utils::ok(static_cast(8)); + return utils::ok(sql::execute_result{8}); } utils::result, utils::error> test_statement::fetch(const sql::parameter_binder &/*bindings*/) { diff --git a/test/orm/backend/test_statement.hpp b/test/orm/backend/test_statement.hpp index 50dd818..883f4c8 100644 --- a/test/orm/backend/test_statement.hpp +++ b/test/orm/backend/test_statement.hpp @@ -2,13 +2,14 @@ #define TEST_STATEMENT_HPP #include "matador/sql/interface/statement_impl.hpp" +#include "matador/sql/execute_result.hpp" namespace matador::test::orm { class test_statement final : public sql::statement_impl { public: explicit test_statement(const sql::query_context &query); - utils::result execute(const sql::parameter_binder &bindings) override; + utils::result execute(const sql::parameter_binder &bindings) override; utils::result, utils::error> fetch(const sql::parameter_binder &bindings) override; void reset() override; diff --git a/test/orm/query/QueryBuilderTest.cpp b/test/orm/query/QueryBuilderTest.cpp index 5bea7d4..d238137 100644 --- a/test/orm/query/QueryBuilderTest.cpp +++ b/test/orm/query/QueryBuilderTest.cpp @@ -50,6 +50,17 @@ TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL, CONSTRAINT PK_person PRIMARY KEY (id)))##"); + result = query::create() + .table({"person"}) + .columns({ + column("id", basic_type::UInt32).primary_key().identity(), + column("name", basic_type::Varchar, 255), + column("age", basic_type::UInt16) + }) + .str(*db); + + REQUIRE(result == R"##(CREATE TABLE "person" ("id" BIGINT NOT NULL AUTO INCREMENT PRIMARY KEY, "name" VARCHAR(255) NOT NULL, "age" INTEGER NOT NULL))##"); + auto ctx = query::create() .table("person") .columns({ diff --git a/test/utils/record_printer.cpp b/test/utils/record_printer.cpp index 85cef80..b070c1d 100644 --- a/test/utils/record_printer.cpp +++ b/test/utils/record_printer.cpp @@ -58,15 +58,15 @@ int record_printer::width(const sql::field &f) { // If it's a varchar/string and has a defined size, use it if it's reasonable, // otherwise fall back to type defaults. if ((f.is_varchar() || f.is_string()) && f.size() > 0 && f.size() < 100) { - return std::max(f.name().length(), f.size()); + return static_cast(std::max(f.name().length(), f.size())); } // Find the default width for type - // Note: field class doesn't expose basic_type directly but we can use value().type() - // if we had access. For now we use name length as minimum. + // Note: field class doesn't expose basic_type directly, but we can use value().type() + // if we had access. For now we use name length as a minimum. constexpr size_t w = 15; // In a real implementation we would probe the field's underlying type. - return std::max(f.name().length(), w); + return static_cast(std::max(f.name().length(), w)); } }