identity generator progress

This commit is contained in:
Sascha Kühl 2026-02-11 16:01:44 +01:00
parent 881e93e0f6
commit 4c63322024
20 changed files with 68 additions and 69 deletions

View File

@ -4,8 +4,7 @@
#include "matador/utils/basic_types.hpp" #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; using namespace matador::sql;
const static dialect d = dialect_builder::builder() const static dialect d = dialect_builder::builder()
.create() .create()
@ -13,16 +12,17 @@
return "$" + std::to_string(index); return "$" + std::to_string(index);
}) })
.with_token_replace_map({ .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({ .with_data_type_replace_map({
{matador::utils::basic_type::Int8, "SMALLINT"}, {matador::utils::basic_type::Int8, "SMALLINT"},
{matador::utils::basic_type::UInt8, "SMALLINT"}, {matador::utils::basic_type::UInt8, "SMALLINT"},
{matador::utils::basic_type::Float, "REAL"}, {matador::utils::basic_type::Float, "REAL"},
{matador::utils::basic_type::Double, "DOUBLE PRECISION"}, {matador::utils::basic_type::Double, "DOUBLE PRECISION"},
{matador::utils::basic_type::Time, "TIME(6)"}, {matador::utils::basic_type::Time, "TIME(6)"},
{matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"}, {matador::utils::basic_type::DateTime, "TIMESTAMPTZ(6)"},
{matador::utils::basic_type::Blob, "BYTEA"} {matador::utils::basic_type::Blob, "BYTEA"}
}) })
.with_bool_strings("TRUE", "FALSE") .with_bool_strings("TRUE", "FALSE")
.with_default_schema_name("public") .with_default_schema_name("public")

View File

@ -70,6 +70,7 @@ public:
column_builder& not_null(); column_builder& not_null();
column_builder& primary_key(); column_builder& primary_key();
column_builder& unique(); column_builder& unique();
column_builder& identity();
private: private:
std::string column_name_; std::string column_name_;

View File

@ -36,11 +36,17 @@ public:
query_create_table_columns_intermediate columns(const std::vector<table_column> &columns); query_create_table_columns_intermediate columns(const std::vector<table_column> &columns);
}; };
class query_create_sequence_intermediate : public executable_query {
public:
using executable_query::executable_query;
};
class query_create_intermediate : public query_intermediate { class query_create_intermediate : public query_intermediate {
public: public:
query_create_intermediate(); query_create_intermediate();
query_create_table_intermediate table(const table &tab); 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); executable_query schema(const std::string &schema_name);
}; };

View File

@ -52,8 +52,6 @@ private:
std::vector<table_column> columns_; std::vector<table_column> columns_;
}; };
table operator ""_tab(const char *name, size_t len);
template<typename Type = table> template<typename Type = table>
class typed_table : public table { class typed_table : public table {
public: public:

View File

@ -148,6 +148,7 @@ public:
[[nodiscard]] const std::string& foreign_key() const; [[nodiscard]] const std::string& foreign_key() const;
[[nodiscard]] const std::string& from() const; [[nodiscard]] const std::string& from() const;
[[nodiscard]] const std::string& group_by() const; [[nodiscard]] const std::string& group_by() const;
[[nodiscard]] const std::string& identity() const;
[[nodiscard]] const std::string& in() const; [[nodiscard]] const std::string& in() const;
[[nodiscard]] const std::string& insert() const; [[nodiscard]] const std::string& insert() const;
[[nodiscard]] const std::string& into() const; [[nodiscard]] const std::string& into() const;
@ -213,9 +214,10 @@ private:
{dialect_token::EndBinaryData, "'"}, {dialect_token::EndBinaryData, "'"},
{dialect_token::EndQuote, "\""}, {dialect_token::EndQuote, "\""},
{dialect_token::EndStringData, "'"}, {dialect_token::EndStringData, "'"},
{dialect_token::ForeignKey, "FOREIGN KEY"}, {dialect_token::ForeignKey, "FOREIGN KEY"},
{dialect_token::From, "FROM"}, {dialect_token::From, "FROM"},
{dialect_token::GroupBy, "GROUP BY"}, {dialect_token::GroupBy, "GROUP BY"},
{dialect_token::Identity, "AUTO INCREMENT"},
{dialect_token::In, "IN"}, {dialect_token::In, "IN"},
{dialect_token::Insert, "INSERT"}, {dialect_token::Insert, "INSERT"},
{dialect_token::Into, "INTO"}, {dialect_token::Into, "INTO"},
@ -238,7 +240,7 @@ private:
{dialect_token::Schema, "SCHEMA"}, {dialect_token::Schema, "SCHEMA"},
{dialect_token::Select, "SELECT"}, {dialect_token::Select, "SELECT"},
{dialect_token::Set, "SET"}, {dialect_token::Set, "SET"},
{dialect_token::StartQuote, "\""}, {dialect_token::StartQuote, "\""},
{dialect_token::StringQuote, "'"}, {dialect_token::StringQuote, "'"},
{dialect_token::Table, "TABLE"}, {dialect_token::Table, "TABLE"},
{dialect_token::Unique, "UNIQUE"}, {dialect_token::Unique, "UNIQUE"},

View File

@ -32,6 +32,7 @@ enum class dialect_token : uint8_t {
ForeignKey, ForeignKey,
From, From,
GroupBy, GroupBy,
Identity,
In, In,
Insert, Insert,
Into, Into,

View File

@ -7,10 +7,11 @@ enum class constraints : unsigned char {
None = 0, None = 0,
Index = 1 << 0, Index = 1 << 0,
Unique = 1 << 1, Unique = 1 << 1,
PrimaryKey = 1 << 2, PrimaryKey = 1 << 2,
ForeignKey = 1 << 3, ForeignKey = 1 << 3,
Default = 1 << 4, Identity = 1 << 4,
NotNull = 1 << 5 Default = 1 << 5,
NotNull = 1 << 6
}; };
inline constraints operator|(constraints a, constraints b) { return static_cast<constraints>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); } inline constraints operator|(constraints a, constraints b) { return static_cast<constraints>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); }

View File

@ -26,6 +26,11 @@ column_builder & column_builder::unique() {
return *this; return *this;
} }
column_builder& column_builder::identity() {
constraints_ |= utils::constraints::Identity;
return *this;
}
table_builder::table_builder(std::string name) table_builder::table_builder(std::string name)
: table_name( std::move(name) ) {} : table_name( std::move(name) ) {}

View File

@ -18,6 +18,9 @@ query_create_table_intermediate query_create_intermediate::table(const class tab
context_->parts.push_back(std::make_unique<internal::query_create_table_part>(tab)); context_->parts.push_back(std::make_unique<internal::query_create_table_part>(tab));
return {context_}; 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 ) { 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)); context_->parts.push_back(std::make_unique<internal::query_create_schema_part>(schema_name));

View File

@ -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)) { if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) {
out.append(" ").append(d.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)) { if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) {
out.append(" ").append(d.primary_key()); out.append(" ").append(d.primary_key());
} }

View File

@ -13,35 +13,6 @@
namespace matador::query { namespace matador::query {
utils::result<void, utils::error> schema::create(const sql::connection &conn) const { utils::result<void, utils::error> schema::create(const sql::connection &conn) const {
// Step 1: Build dependency graph
// std::unordered_map<std::string, std::vector<std::string> > dependency_graph;
// std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree;
//
// for (const auto &node: repo_) {
// for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
// dependency_graph[node->name()].push_back(it->second->node().name());
//
// if (const auto dit = in_degree.find(it->second->node().name()); dit == in_degree.end()) {
// in_degree[it->second->node().name()] = std::make_pair(1, it->second->node_ptr());
// } else {
// in_degree[it->second->node().name()].first++;
// }
// }
//
// // Ensure the current node exists in the graph representation
// if (in_degree.find(node->name()) == in_degree.end()) {
// in_degree[node->name()] = std::make_pair(0, node);
// }
// }
//
// for (const auto &it : dependency_graph) {
// std::cout << "Dependency graph " << it.first << std::endl;
// for (const auto &neighbor: it.second) {
// std::cout << " " << neighbor << std::endl;
// }
// std::cout << std::endl;
// }
std::vector<std::string> fk_sql_commands; std::vector<std::string> fk_sql_commands;
const auto q = query::create().schema(repo_.name()).compile(conn); const auto q = query::create().schema(repo_.name()).compile(conn);
@ -52,7 +23,6 @@ utils::result<void, utils::error> schema::create(const sql::connection &conn) co
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(conn); .compile(conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;

View File

@ -103,10 +103,4 @@ const table_column& table::create_column(class table &tab, const std::string &na
tab.columns_.back().table(&tab); tab.columns_.back().table(&tab);
return tab.columns_.back(); return tab.columns_.back();
} }
table operator ""_tab(const char *name, size_t len) {
return {{name, len}};
}
} }

View File

@ -175,6 +175,10 @@ const std::string &dialect::from() const {
return token_at(dialect_token::From); return token_at(dialect_token::From);
} }
const std::string &dialect::identity() const {
return token_at(dialect_token::Identity);
}
const std::string &dialect::in() const { const std::string &dialect::in() const {
return token_at(dialect_token::In); return token_at(dialect_token::In);
} }

View File

@ -17,10 +17,8 @@ TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-man
using namespace matador::test; using namespace matador::test;
query::schema repo; query::schema repo;
// auto result = repo.attach<department>("departments") auto result = repo.attach<department>("departments")
// .and_then([&repo] { return repo.attach<employee>("employees"); }); .and_then([&repo] { return repo.attach<employee>("employees"); });
auto result = repo.attach<employee>("employees")
.and_then([&repo] { return repo.attach<department>("departments"); });
REQUIRE(result); REQUIRE(result);
auto conn = pool.acquire(); auto conn = pool.acquire();

View File

@ -44,8 +44,8 @@ utils::result<utils::version, utils::error> test_connection::server_version() co
return utils::ok(utils::version{3, 2, 1}); return utils::ok(utils::version{3, 2, 1});
} }
utils::result<size_t, utils::error> test_connection::execute(const std::string &/*stmt*/) { utils::result<sql::execute_result, utils::error> test_connection::execute(const sql::query_context &/*context*/) {
return utils::ok(static_cast<size_t>(4)); return utils::ok(sql::execute_result{4});
} }
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_connection::fetch(const sql::query_context &context) { utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_connection::fetch(const sql::query_context &context) {

View File

@ -2,6 +2,7 @@
#define QUERY_NOOP_CONNECTION_HPP #define QUERY_NOOP_CONNECTION_HPP
#include "matador/sql/interface/connection_impl.hpp" #include "matador/sql/interface/connection_impl.hpp"
#include "matador/sql/execute_result.hpp"
namespace matador::test::orm { namespace matador::test::orm {
@ -16,7 +17,7 @@ public:
[[nodiscard]] utils::result<bool, utils::error> is_valid() const override; [[nodiscard]] utils::result<bool, utils::error> is_valid() const override;
[[nodiscard]] utils::result<utils::version, utils::error> client_version() const override; [[nodiscard]] utils::result<utils::version, utils::error> client_version() const override;
[[nodiscard]] utils::result<utils::version, utils::error> server_version() const override; [[nodiscard]] utils::result<utils::version, utils::error> server_version() const override;
utils::result<size_t, utils::error> execute(const std::string &stmt) override; utils::result<sql::execute_result, utils::error> execute(const sql::query_context &context) override;
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &context) override; utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &context) override;
utils::result<std::unique_ptr<sql::statement_impl>, utils::error> prepare(const sql::query_context &context) override; utils::result<std::unique_ptr<sql::statement_impl>, utils::error> prepare(const sql::query_context &context) override;
utils::result<std::vector<object::attribute>, utils::error> describe(const std::string &table) override; utils::result<std::vector<object::attribute>, utils::error> describe(const std::string &table) override;

View File

@ -10,12 +10,12 @@ namespace matador::test::orm {
test_statement::test_statement(const sql::query_context &query) test_statement::test_statement(const sql::query_context &query)
: statement_impl(query, 0) {} : statement_impl(query, 0) {}
utils::result<size_t, utils::error> test_statement::execute(const sql::parameter_binder &/*bindings*/) { utils::result<sql::execute_result, utils::error> test_statement::execute(const sql::parameter_binder &/*bindings*/) {
using namespace std::chrono_literals; using namespace std::chrono_literals;
std::mt19937 rng(query_.sql.size()); std::mt19937 rng(query_.sql.size());
std::uniform_int_distribution dist(10, 50); std::uniform_int_distribution dist(10, 50);
std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng))); std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng)));
return utils::ok(static_cast<size_t>(8)); return utils::ok(sql::execute_result{8});
} }
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_statement::fetch(const sql::parameter_binder &/*bindings*/) { utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> test_statement::fetch(const sql::parameter_binder &/*bindings*/) {

View File

@ -2,13 +2,14 @@
#define TEST_STATEMENT_HPP #define TEST_STATEMENT_HPP
#include "matador/sql/interface/statement_impl.hpp" #include "matador/sql/interface/statement_impl.hpp"
#include "matador/sql/execute_result.hpp"
namespace matador::test::orm { namespace matador::test::orm {
class test_statement final : public sql::statement_impl { class test_statement final : public sql::statement_impl {
public: public:
explicit test_statement(const sql::query_context &query); explicit test_statement(const sql::query_context &query);
utils::result<size_t, utils::error> execute(const sql::parameter_binder &bindings) override; utils::result<sql::execute_result, utils::error> execute(const sql::parameter_binder &bindings) override;
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder &bindings) override; utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder &bindings) override;
void reset() override; void reset() override;

View File

@ -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)))##"); 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() auto ctx = query::create()
.table("person") .table("person")
.columns({ .columns({

View File

@ -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, // If it's a varchar/string and has a defined size, use it if it's reasonable,
// otherwise fall back to type defaults. // otherwise fall back to type defaults.
if ((f.is_varchar() || f.is_string()) && f.size() > 0 && f.size() < 100) { if ((f.is_varchar() || f.is_string()) && f.size() > 0 && f.size() < 100) {
return std::max(f.name().length(), f.size()); return static_cast<int>(std::max(f.name().length(), f.size()));
} }
// Find the default width for type // Find the default width for type
// Note: field class doesn't expose basic_type directly but we can use value().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. // if we had access. For now we use name length as a minimum.
constexpr size_t w = 15; constexpr size_t w = 15;
// In a real implementation we would probe the field's underlying type. // In a real implementation we would probe the field's underlying type.
return std::max(f.name().length(), w); return static_cast<int>(std::max(f.name().length(), w));
} }
} }