Skip to content

Commit c1a4ba6

Browse files
Pierre-Luc Gagnéclaude
andcommitted
feat: add instance-based overloads for validate_table and validate_database
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1d55830 commit c1a4ba6

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

99
## [Unreleased]
1010

11+
### Added
12+
13+
- Instance-based overloads for `mysql_connection::validate_table` and `validate_database` — e.g. `db->validate_table(trade{})` and `db->validate_database(trade_db{})` as alternatives to the template-only forms
14+
1115
---
1216

1317
## [4.3.0] – 2026-03-29

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Style: Google-based, 120-char line limit, 4-space indent (`.clang-format` at roo
6767

6868
### Schema Generation and Validation
6969

70-
Tables are described as C++ structs. `schema_generator.hpp` reflects struct fields via Boost.PFR at compile time. To override the SQL type for a specific field, specialize `field_schema<T, I>`. `mysql_connection::validate_table<T>()` checks a live database schema against the C++ definition and returns detailed error messages on mismatch.
70+
Tables are described as C++ structs. `schema_generator.hpp` reflects struct fields via Boost.PFR at compile time. To override the SQL type for a specific field, specialize `field_schema<T, I>`. `mysql_connection::validate_table(T{})` / `validate_table<T>()` checks a live database schema against the C++ definition and returns detailed error messages on mismatch. `validate_database(DB{})` / `validate_database<DB>()` validates all tables in a database schema struct.
7171

7272
### Error Handling
7373

lib/include/ds_mysql/mysql_connection.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,11 @@ class mysql_connection {
401401
//
402402
// Returns std::expected<void, std::string>.
403403
// On mismatch, the error string lists every discrepancy found.
404+
template <ValidTable T>
405+
[[nodiscard]] std::expected<void, std::string> validate_table(T const&) const {
406+
return validate_table<T>();
407+
}
408+
404409
template <ValidTable T>
405410
[[nodiscard]] std::expected<void, std::string> validate_table() const {
406411
auto describe_result = query(describe(T{}));
@@ -436,6 +441,11 @@ class mysql_connection {
436441
//
437442
// Returns std::expected<void, std::string>.
438443
// On mismatch, the error string aggregates every discrepancy across all tables.
444+
template <Database DB>
445+
[[nodiscard]] std::expected<void, std::string> validate_database(DB const&) const {
446+
return validate_database<DB>();
447+
}
448+
439449
template <Database DB>
440450
[[nodiscard]] std::expected<void, std::string> validate_database() const {
441451
using tables_tuple = typename database_tables<DB>::type;

tests/integration/mysql/test_query_builder.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,23 @@ suite<"Schema Validation Integration"> schema_validation_suite = [] {
792792
(result.has_value() ? "" : result.error());
793793
};
794794

795+
"validate_table instance-based succeeds when table matches C++ struct"_test = [] {
796+
auto const config = mysql_config_from_env();
797+
expect(fatal(config.has_value()));
798+
799+
auto const db = mysql_connection::connect(*config);
800+
expect(fatal(db));
801+
auto _ = scope_guard{[&] {
802+
(void)(db->execute(drop_table(trade{}).if_exists()));
803+
}};
804+
805+
expect(db->execute(create_table(trade{}).if_not_exists()).has_value());
806+
807+
auto const result = db->validate_table(trade{});
808+
expect(result.has_value()) << "validate_table(trade{}) should succeed — " +
809+
(result.has_value() ? "" : result.error());
810+
};
811+
795812
"validate_table fails when table does not exist"_test = [] {
796813
auto const config = mysql_config_from_env();
797814
expect(fatal(config.has_value()));
@@ -848,6 +865,23 @@ suite<"Schema Validation Integration"> schema_validation_suite = [] {
848865
(result.has_value() ? "" : result.error());
849866
};
850867

868+
"validate_database instance-based succeeds when all registered tables match"_test = [] {
869+
auto const config = mysql_config_from_env();
870+
expect(fatal(config.has_value()));
871+
872+
auto const db = mysql_connection::connect(*config);
873+
expect(fatal(db));
874+
auto _ = scope_guard{[&] {
875+
(void)(db->execute(drop_table(trade{}).if_exists()));
876+
}};
877+
878+
expect(db->execute(create_table(trade{}).if_not_exists()).has_value());
879+
880+
auto const result = db->validate_database(trade_db{});
881+
expect(result.has_value()) << "validate_database(trade_db{}) should succeed — " +
882+
(result.has_value() ? "" : result.error());
883+
};
884+
851885
"validate_database reports error when a table is absent"_test = [] {
852886
auto const config = mysql_config_from_env();
853887
expect(fatal(config.has_value()));

0 commit comments

Comments
 (0)