Skip to content

Commit ac6822b

Browse files
Pierre-Luc Gagnéclaude
andcommitted
feat: add column_attr::primary_key for inline single-column primary keys
Allows declaring PRIMARY KEY directly on a column field instead of requiring a separate table_constraints<T> specialization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7860227 commit ac6822b

7 files changed

Lines changed: 25 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1010

1111
### Added
1212

13+
- `column_attr::primary_key` — inline column-level `PRIMARY KEY` attribute for single-column primary keys, e.g. `COLUMN_FIELD(id, uint32_t, column_attr::primary_key, column_attr::auto_increment)`
1314
- `date_type` for MySQL `DATE` columns — stores `std::chrono::sys_days`, supports serialization (`'YYYY-MM-DD'`), deserialization, and `std::optional<date_type>` for nullable columns
1415

1516
---
@@ -18,7 +19,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1819

1920
### Removed
2021

21-
- `table_inline_primary_key<T>` trait and automatic `PRIMARY KEY AUTO_INCREMENT` on the first column — define primary keys explicitly via `table_constraints<T>` or column attributes (`column_attr::auto_increment`)
22+
- `table_inline_primary_key<T>` trait and automatic `PRIMARY KEY AUTO_INCREMENT` on the first column — define primary keys explicitly via `column_attr::primary_key`, `table_constraints<T>`, or both
2223

2324
---
2425

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Style: Google-based, 120-char line limit, 4-space indent (`.clang-format` at roo
5353
- `sql_dql.hpp``select(col1{}, col2{})`, `count(T{})`, `describe(T{})`
5454
- `connect_options.hpp``connect_options` fluent builder and `ssl_mode` enum for pre-connect `mysql_options()` configuration (timeouts, SSL/TLS, charset, compression, etc.)
5555
- `charset_name.hpp``charset_name` strong type for character set names
56-
- `column_field.hpp` / `column_field_base_*.hpp``column_field<"name", Type>` descriptors and `COLUMN_FIELD(name, type)` macro
56+
- `column_field.hpp` / `column_field_base_*.hpp``column_field<"name", Type, Attrs...>` descriptors, `COLUMN_FIELD(name, type, attrs...)` macro, and column attributes (`column_attr::primary_key`, `auto_increment`, `unique`, `default_current_timestamp`, `on_update_current_timestamp`, `comment<"...">`, `collate<"...">`)
5757
- `schema_generator.hpp` — derives CREATE TABLE SQL from a C++ struct at compile time using Boost.PFR
5858
- `sql_varchar.hpp`, `sql_numeric.hpp`, `sql_temporal.hpp` — library-specific SQL types (`varchar_type<N>`, `decimal_type<P,S>`, `datetime_type<FSP>`, etc.)
5959
- `metadata.hpp` — types for querying `information_schema`

lib/include/ds_mysql/column_field.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ struct column_field : column_field_detail::base<T> {
4242
using column_field_detail::base<T>::base;
4343
using column_field_detail::base<T>::operator=;
4444

45+
static constexpr bool ddl_primary_key = (std::same_as<Attrs, column_attr::primary_key> || ...);
4546
static constexpr bool ddl_auto_increment = (std::same_as<Attrs, column_attr::auto_increment> || ...);
4647
static constexpr bool ddl_unique = (std::same_as<Attrs, column_attr::unique> || ...);
4748
static constexpr bool ddl_default_current_timestamp =

lib/include/ds_mysql/column_field_base_core.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct column_field_tag {};
1515

1616
namespace column_attr {
1717

18+
struct primary_key {};
1819
struct auto_increment {};
1920
struct unique {};
2021
struct default_current_timestamp {};

lib/include/ds_mysql/sql_ddl.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,9 @@ template <typename T, std::size_t I>
10241024
if constexpr (!is_field_nullable_v<field_type>) {
10251025
col += " NOT NULL";
10261026
}
1027+
if constexpr (requires { field_type::ddl_primary_key; } && field_type::ddl_primary_key) {
1028+
col += " PRIMARY KEY";
1029+
}
10271030
if constexpr (requires { field_type::ddl_auto_increment; } && field_type::ddl_auto_increment) {
10281031
col += " AUTO_INCREMENT";
10291032
}

tests/integration/mysql/test_query_builder.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace ds_mysql {
2020
namespace {
2121

2222
struct trade {
23-
COLUMN_FIELD(id, uint32_t)
23+
COLUMN_FIELD(id, uint32_t, column_attr::primary_key, column_attr::auto_increment)
2424
COLUMN_FIELD(account_id, std::optional<uint32_t>)
2525
COLUMN_FIELD(code, varchar_type<32>)
2626
COLUMN_FIELD(type, varchar_type<64>)
@@ -1449,7 +1449,7 @@ suite<"Typed Query Column Count Coverage"> typed_query_col_count_suite = [] {
14491449
// ===================================================================
14501450

14511451
struct auto_inc_row {
1452-
COLUMN_FIELD(id, uint32_t, column_attr::auto_increment)
1452+
COLUMN_FIELD(id, uint32_t, column_attr::primary_key, column_attr::auto_increment)
14531453
COLUMN_FIELD(label, varchar_type<64>)
14541454
};
14551455

tests/unit/test_ddl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ struct table_with_attrs {
196196
COLUMN_FIELD(id, uint32_t)
197197
COLUMN_FIELD(name, varchar_type<255>)
198198
};
199+
200+
struct table_with_pk {
201+
COLUMN_FIELD(id, uint32_t, column_attr::primary_key, column_attr::auto_increment)
202+
COLUMN_FIELD(name, varchar_type<255>)
203+
};
199204
} // namespace
200205

201206
template <>
@@ -800,6 +805,16 @@ suite<"DDL"> ddl_suite = [] {
800805
expect(!sql.contains("AUTO_INCREMENT")) << sql;
801806
};
802807

808+
"create_table - column_attr::primary_key emits PRIMARY KEY on column"_test = [] {
809+
auto const sql = create_table(table_with_pk{}).build_sql();
810+
expect(sql ==
811+
"CREATE TABLE table_with_pk (\n"
812+
" id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\n"
813+
" name VARCHAR(255) NOT NULL\n"
814+
");\n"s)
815+
<< sql;
816+
};
817+
803818
"create_table with table_attributes trait - emits default ENGINE and CHARSET"_test = [] {
804819
auto const sql = create_table(table_with_attrs{}).build_sql();
805820
expect(sql ==

0 commit comments

Comments
 (0)