From b656569fc0aeacf477601a496216585645f611e7 Mon Sep 17 00:00:00 2001 From: Hayodea Hekol Date: Fri, 5 Jun 2026 12:53:05 -0400 Subject: [PATCH] Support enum headers and other stuff --- README.md | 13 ++ cmake/CppBeSSOT.cmake | 14 ++ cmake/dbGenMigrations.cmake | 10 +- cmake/scripts/run_odb_migrations.cmake | 139 +++++++++++- .../cpp-odb-json/model-header.mustache | 8 +- tests/db-actions/CMakeLists.txt | 1 + .../db-actions/scripts/migration_policy.cmake | 204 ++++++++++++++++++ 7 files changed, 374 insertions(+), 15 deletions(-) create mode 100644 tests/db-actions/scripts/migration_policy.cmake diff --git a/README.md b/README.md index 1f813f9..37c5332 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,13 @@ cppbessot_enable() - default: empty - target schema basename for `db_gen_migrations` +- `CPPBESSOT_GEN_MIGRATION_BACKENDS` + - default: `sqlite;pgsql` + - ODB backends for `db_gen_migrations` + - supported values: `sqlite`, `pgsql` + - `pgsql` writes artifacts under the historical `postgre` output directory + - compatibility alias: `CPPBESSOT_GEN_MIGRATIONS_BACKENDS` + - `DB_SCHEMA_CHANGES_ARE_ERROR` - default: `OFF` - used by schema-drift checking logic @@ -303,6 +310,7 @@ Primary variables: - `CPPBESSOT_WORKDIR` - `DB_SCHEMA_DIR_MIGRATION_FROM` - `DB_SCHEMA_DIR_MIGRATION_TO` +- `CPPBESSOT_GEN_MIGRATION_BACKENDS` Output: @@ -313,6 +321,11 @@ Notes: - `from` and `to` must differ - if either migration variable is empty, `db_gen_migrations` is still registered but intentionally fails with guidance +- enum-only generated C++ headers are skipped; only headers with ODB object pragmas produce migration SQL +- missing source-version changelog XML means the target-version model is treated as a new table and generated from an empty changelog baseline +- PostgreSQL migrations remain incremental when source-version changelog XML exists +- SQLite migrations remain incremental except when ODB reports SQLite's drop-column limitation; in that case only that model is regenerated from the empty changelog baseline with a warning +- for production upgrades, PostgreSQL migration SQL is the meaningful upgrade path; SQLite greenfield fallback artifacts are generated for tree completeness, not as a guaranteed runnable SQLite upgrade path ### `db_gen_orm_serdes_and_zod` diff --git a/cmake/CppBeSSOT.cmake b/cmake/CppBeSSOT.cmake index 5380f69..a85423e 100644 --- a/cmake/CppBeSSOT.cmake +++ b/cmake/CppBeSSOT.cmake @@ -31,6 +31,19 @@ if(NOT DEFINED DB_SCHEMA_DIR_MIGRATION_TO) "Optional target schema directory basename for migration generation") endif() +if(NOT DEFINED CPPBESSOT_GEN_MIGRATION_BACKENDS) + if(DEFINED CPPBESSOT_GEN_MIGRATIONS_BACKENDS) + set(CPPBESSOT_GEN_MIGRATION_BACKENDS "${CPPBESSOT_GEN_MIGRATIONS_BACKENDS}") + else() + set(CPPBESSOT_GEN_MIGRATION_BACKENDS "sqlite;pgsql") + endif() +endif() + +set(CPPBESSOT_GEN_MIGRATION_BACKENDS "${CPPBESSOT_GEN_MIGRATION_BACKENDS}" CACHE STRING + "ODB backends for db_gen_migrations; supported values: sqlite, pgsql") +set(CPPBESSOT_GEN_MIGRATIONS_BACKENDS "${CPPBESSOT_GEN_MIGRATION_BACKENDS}" CACHE STRING + "Compatibility alias for CPPBESSOT_GEN_MIGRATION_BACKENDS" FORCE) + if(NOT DEFINED DB_SCHEMA_CHANGES_ARE_ERROR) option(DB_SCHEMA_CHANGES_ARE_ERROR "Treat dirty schema changes as hard CMake error" OFF) endif() @@ -249,6 +262,7 @@ function(cppbessot_enable) # - DB_SCHEMA_DIR_TO_GENERATE # - DB_SCHEMA_DIR_MIGRATION_FROM # - DB_SCHEMA_DIR_MIGRATION_TO + # - CPPBESSOT_GEN_MIGRATION_BACKENDS # - DB_SCHEMA_CHANGES_ARE_ERROR (optional behavior control) # Outputs: # - Custom targets: diff --git a/cmake/dbGenMigrations.cmake b/cmake/dbGenMigrations.cmake index 62cb4db..aa078bc 100644 --- a/cmake/dbGenMigrations.cmake +++ b/cmake/dbGenMigrations.cmake @@ -9,6 +9,7 @@ function(cppbessot_add_db_gen_migrations_target from_schema_dir to_schema_dir) # - from_schema_dir: Source schema directory basename. # - to_schema_dir: Target schema directory basename. # - CPPBESSOT_ODB_EXECUTABLE: Path to `odb` compiler. + # - CPPBESSOT_GEN_MIGRATION_BACKENDS: List of ODB backends to generate. # Outputs: # - CMake target: `db_gen_migrations` (EXCLUDE_FROM_ALL). # - Files under `migrations/-/{sqlite,postgre}`. @@ -26,10 +27,11 @@ function(cppbessot_add_db_gen_migrations_target from_schema_dir to_schema_dir) add_custom_target(db_gen_migrations COMMAND "${CMAKE_COMMAND}" - -DCPPBESSOT_ODB_EXECUTABLE=${CPPBESSOT_ODB_EXECUTABLE} - -DCPPBESSOT_FROM_VERSION_DIR=${_from_dir} - -DCPPBESSOT_TO_VERSION_DIR=${_to_dir} - -DCPPBESSOT_MIGRATION_DIR=${_migration_dir} + "-DCPPBESSOT_ODB_EXECUTABLE=${CPPBESSOT_ODB_EXECUTABLE}" + "-DCPPBESSOT_FROM_VERSION_DIR=${_from_dir}" + "-DCPPBESSOT_TO_VERSION_DIR=${_to_dir}" + "-DCPPBESSOT_MIGRATION_DIR=${_migration_dir}" + "-DCPPBESSOT_GEN_MIGRATION_BACKENDS=${CPPBESSOT_GEN_MIGRATION_BACKENDS}" -P "${_CPPBESSOT_DB_GEN_MIGRATIONS_DIR}/scripts/run_odb_migrations.cmake" COMMENT "Generating DB migrations: ${from_schema_dir} -> ${to_schema_dir}" VERBATIM diff --git a/cmake/scripts/run_odb_migrations.cmake b/cmake/scripts/run_odb_migrations.cmake index e291cb6..a496664 100644 --- a/cmake/scripts/run_odb_migrations.cmake +++ b/cmake/scripts/run_odb_migrations.cmake @@ -13,36 +13,130 @@ if(NOT DEFINED CPPBESSOT_MIGRATION_DIR OR CPPBESSOT_MIGRATION_DIR STREQUAL "") message(FATAL_ERROR "CPPBESSOT_MIGRATION_DIR is required") endif() +function(cppbessot_migration_resolve_backends out_var) + if(NOT DEFINED CPPBESSOT_GEN_MIGRATION_BACKENDS OR CPPBESSOT_GEN_MIGRATION_BACKENDS STREQUAL "") + if(DEFINED CPPBESSOT_GEN_MIGRATIONS_BACKENDS AND NOT CPPBESSOT_GEN_MIGRATIONS_BACKENDS STREQUAL "") + set(_raw_backends "${CPPBESSOT_GEN_MIGRATIONS_BACKENDS}") + else() + set(_raw_backends "sqlite;pgsql") + endif() + else() + set(_raw_backends "${CPPBESSOT_GEN_MIGRATION_BACKENDS}") + endif() + + set(_resolved_backends "") + foreach(_backend IN LISTS _raw_backends) + string(STRIP "${_backend}" _backend) + string(TOLOWER "${_backend}" _backend) + + if(_backend STREQUAL "") + message(FATAL_ERROR "CPPBESSOT_GEN_MIGRATION_BACKENDS contains an empty backend name.") + endif() + + if(NOT _backend STREQUAL "sqlite" AND NOT _backend STREQUAL "pgsql") + message(FATAL_ERROR + "Unsupported migration backend `${_backend}`. " + "CPPBESSOT_GEN_MIGRATION_BACKENDS supports sqlite and pgsql.") + endif() + + if(NOT _backend IN_LIST _resolved_backends) + list(APPEND _resolved_backends "${_backend}") + endif() + endforeach() + + if(NOT _resolved_backends) + message(FATAL_ERROR "CPPBESSOT_GEN_MIGRATION_BACKENDS must name at least one backend.") + endif() + + set(${out_var} "${_resolved_backends}" PARENT_SCOPE) +endfunction() + +function(cppbessot_migration_backend_metadata backend out_subdir out_odb_database out_database_attr) + if("${backend}" STREQUAL "sqlite") + set(${out_subdir} "sqlite" PARENT_SCOPE) + set(${out_odb_database} "sqlite" PARENT_SCOPE) + set(${out_database_attr} "sqlite" PARENT_SCOPE) + elseif("${backend}" STREQUAL "pgsql") + set(${out_subdir} "postgre" PARENT_SCOPE) + set(${out_odb_database} "pgsql" PARENT_SCOPE) + set(${out_database_attr} "pgsql" PARENT_SCOPE) + else() + message(FATAL_ERROR "Unsupported migration backend `${backend}`.") + endif() +endfunction() + +function(cppbessot_migration_write_empty_changelog changelog_path database_attr) + if(NOT EXISTS "${changelog_path}") + file(WRITE "${changelog_path}" +"\n" +" \n" +" \n" +"\n") + endif() +endfunction() + +function(cppbessot_migration_should_retry_sqlite_from_empty out_var backend from_xml empty_changelog stdout stderr) + set(_should_retry FALSE) + if("${backend}" STREQUAL "sqlite" AND NOT "${from_xml}" STREQUAL "${empty_changelog}") + set(_diagnostics "${stdout}\n${stderr}") + if(_diagnostics MATCHES "SQLite does not support dropping of columns") + set(_should_retry TRUE) + endif() + endif() + set(${out_var} "${_should_retry}" PARENT_SCOPE) +endfunction() + +cppbessot_migration_resolve_backends(_migration_backends) + set(_to_include_dir "${CPPBESSOT_TO_VERSION_DIR}/generated-cpp-source/include") file(GLOB _to_headers "${_to_include_dir}/*/model/*.h") if(NOT _to_headers) message(FATAL_ERROR "No target-version headers found under ${_to_include_dir}") endif() -foreach(_backend IN ITEMS sqlite pgsql) - if(_backend STREQUAL "sqlite") - set(_subdir sqlite) - else() - set(_subdir postgre) +set(_object_headers "") +foreach(_header IN LISTS _to_headers) + file(READ "${_header}" _header_contents) + if(_header_contents MATCHES "#pragma db object") + list(APPEND _object_headers "${_header}") endif() +endforeach() + +if(NOT _object_headers) + message(FATAL_ERROR "No ODB object headers found under ${_to_include_dir}") +endif() + +set(_empty_changelog_dir "${CPPBESSOT_MIGRATION_DIR}/.empty-baseline") +file(MAKE_DIRECTORY "${_empty_changelog_dir}") + +foreach(_backend IN LISTS _migration_backends) + cppbessot_migration_backend_metadata( + "${_backend}" + _subdir + _odb_database + _database_attr) + + set(_empty_changelog "${_empty_changelog_dir}/${_subdir}-empty.xml") + cppbessot_migration_write_empty_changelog("${_empty_changelog}" "${_database_attr}") set(_migration_backend_dir "${CPPBESSOT_MIGRATION_DIR}/${_subdir}") file(MAKE_DIRECTORY "${_migration_backend_dir}") - foreach(_header IN LISTS _to_headers) + foreach(_header IN LISTS _object_headers) get_filename_component(_name "${_header}" NAME_WE) set(_in_xml "${CPPBESSOT_FROM_VERSION_DIR}/generated-odb-source/${_subdir}/${_name}.xml") set(_out_xml "${CPPBESSOT_TO_VERSION_DIR}/generated-odb-source/${_subdir}/${_name}.xml") - if(NOT EXISTS "${_in_xml}") - message(FATAL_ERROR "Missing changelog input for `${_name}`: ${_in_xml}") + set(_from_xml "${_in_xml}") + if(NOT EXISTS "${_from_xml}") + set(_from_xml "${_empty_changelog}") endif() execute_process( - COMMAND "${CPPBESSOT_ODB_EXECUTABLE}" -I "${_to_include_dir}" --std c++11 -d "${_backend}" + COMMAND "${CPPBESSOT_ODB_EXECUTABLE}" -I "${_to_include_dir}" --std c++11 -d "${_odb_database}" --generate-schema --schema-format sql -q -o "${_migration_backend_dir}" - --changelog-in "${_in_xml}" + --changelog-in "${_from_xml}" --changelog-out "${_out_xml}" "${_header}" RESULT_VARIABLE _result @@ -50,6 +144,31 @@ foreach(_backend IN ITEMS sqlite pgsql) ERROR_VARIABLE _stderr ) + cppbessot_migration_should_retry_sqlite_from_empty( + _retry_from_empty + "${_backend}" + "${_from_xml}" + "${_empty_changelog}" + "${_stdout}" + "${_stderr}") + + if(NOT _result EQUAL 0 AND _retry_from_empty) + message(WARNING + "SQLite incremental migration failed for `${_name}`; retrying from empty baseline. " + "Generated SQLite migration SQL is a greenfield create for this model.") + execute_process( + COMMAND "${CPPBESSOT_ODB_EXECUTABLE}" -I "${_to_include_dir}" --std c++11 -d "${_odb_database}" + --generate-schema --schema-format sql -q + -o "${_migration_backend_dir}" + --changelog-in "${_empty_changelog}" + --changelog-out "${_out_xml}" + "${_header}" + RESULT_VARIABLE _result + OUTPUT_VARIABLE _stdout + ERROR_VARIABLE _stderr + ) + endif() + if(NOT _result EQUAL 0) message(FATAL_ERROR "Migration generation failed for `${_name}` backend `${_backend}`.\n${_stdout}\n${_stderr}") diff --git a/openapi/templates/cpp-odb-json/model-header.mustache b/openapi/templates/cpp-odb-json/model-header.mustache index 3b30073..89e7616 100644 --- a/openapi/templates/cpp-odb-json/model-header.mustache +++ b/openapi/templates/cpp-odb-json/model-header.mustache @@ -13,6 +13,12 @@ #include #include +{{#vars}} +{{#vendorExtensions.x-cppType}} +#include +{{/vendorExtensions.x-cppType}} +{{/vars}} + namespace models { {{#isEnum}} @@ -41,7 +47,7 @@ public: {{#vendorExtensions.x-odbAddedIn}} // odbAddedIn: {{.}} {{/vendorExtensions.x-odbAddedIn}} - {{#isString}}std::string{{/isString}}{{^isString}}{{#isDateTime}}std::string{{/isDateTime}}{{^isDateTime}}{{dataType}}{{/isDateTime}}{{/isString}} {{nameInCamelCase}}{}; + {{#vendorExtensions.x-cppType}}{{vendorExtensions.x-cppType}}{{/vendorExtensions.x-cppType}}{{^vendorExtensions.x-cppType}}{{#isString}}std::string{{/isString}}{{^isString}}{{#isDateTime}}std::string{{/isDateTime}}{{^isDateTime}}{{#isBoolean}}bool{{/isBoolean}}{{^isBoolean}}{{#isInteger}}int32_t{{/isInteger}}{{^isInteger}}{{#isLong}}int64_t{{/isLong}}{{^isLong}}{{dataType}}{{/isLong}}{{/isInteger}}{{/isBoolean}}{{/isDateTime}}{{/isString}}{{/vendorExtensions.x-cppType}} {{nameInCamelCase}}{}; {{/vars}} NLOHMANN_DEFINE_TYPE_INTRUSIVE({{classname}}{{#vars}}, {{nameInCamelCase}}{{/vars}}) diff --git a/tests/db-actions/CMakeLists.txt b/tests/db-actions/CMakeLists.txt index ab5b5bf..ac89588 100644 --- a/tests/db-actions/CMakeLists.txt +++ b/tests/db-actions/CMakeLists.txt @@ -68,6 +68,7 @@ cppbessot_add_db_action_test(cppbessot_db_action_pgsql_tests_createfrom_mock pgs cppbessot_add_db_action_test(cppbessot_db_action_pgsql_migrate_order pgsql_migrate_order.cmake) cppbessot_add_db_action_test(cppbessot_db_action_pgsql_stale_abort pgsql_stale_abort.cmake) cppbessot_add_db_action_test(cppbessot_db_action_backfill_env_no_structural backfill_env_no_structural.cmake) +cppbessot_add_db_action_test(cppbessot_db_gen_migrations_policy migration_policy.cmake) cppbessot_add_real_pgsql_db_action_test( cppbessot_db_action_pgsql_createfrom_real pgsql_createfrom_real.cmake diff --git a/tests/db-actions/scripts/migration_policy.cmake b/tests/db-actions/scripts/migration_policy.cmake new file mode 100644 index 0000000..b6d751f --- /dev/null +++ b/tests/db-actions/scripts/migration_policy.cmake @@ -0,0 +1,204 @@ +include("${CMAKE_CURRENT_LIST_DIR}/../cmake/TestCommon.cmake") + +cppbessot_test_require_var(CPPBESSOT_TEST_BINARY_DIR) +cppbessot_test_require_var(CPPBESSOT_TEST_MODULE_SOURCE_DIR) + +set(_script_under_test "${CPPBESSOT_TEST_MODULE_SOURCE_DIR}/cmake/scripts/run_odb_migrations.cmake") + +function(_cppbessot_migration_policy_fixture out_root) + cppbessot_test_case_dir(_case_dir) + set(_root "${_case_dir}/${ARGV1}") + cppbessot_test_reset_dir("${_root}") + file(MAKE_DIRECTORY + "${_root}/from/generated-odb-source/sqlite" + "${_root}/from/generated-odb-source/postgre" + "${_root}/to/generated-cpp-source/include/cppbessot/model" + "${_root}/to/generated-odb-source/sqlite" + "${_root}/to/generated-odb-source/postgre" + "${_root}/migrations") + cppbessot_test_write_file( + "${_root}/to/generated-cpp-source/include/cppbessot/model/Agent.h" + "#pragma db object\n" + "class Agent {};\n") + cppbessot_test_write_file( + "${_root}/to/generated-cpp-source/include/cppbessot/model/AgentPasswordHashType.h" + "enum class AgentPasswordHashType { argon2id };\n") + set(${out_root} "${_root}" PARENT_SCOPE) +endfunction() + +function(_cppbessot_migration_policy_run root odb_executable result_var stdout_var stderr_var) + set(_args + "-DCPPBESSOT_ODB_EXECUTABLE=${odb_executable}" + "-DCPPBESSOT_FROM_VERSION_DIR=${root}/from" + "-DCPPBESSOT_TO_VERSION_DIR=${root}/to" + "-DCPPBESSOT_MIGRATION_DIR=${root}/migrations") + foreach(_extra_arg IN LISTS ARGN) + list(APPEND _args "${_extra_arg}") + endforeach() + + execute_process( + COMMAND "${CMAKE_COMMAND}" ${_args} -P "${_script_under_test}" + RESULT_VARIABLE _result + OUTPUT_VARIABLE _stdout + ERROR_VARIABLE _stderr) + + set(${result_var} "${_result}" PARENT_SCOPE) + set(${stdout_var} "${_stdout}" PARENT_SCOPE) + set(${stderr_var} "${_stderr}" PARENT_SCOPE) +endfunction() + +function(_cppbessot_migration_policy_true_tool out_tool log_path) + get_filename_component(_tool_dir "${log_path}" DIRECTORY) + cppbessot_test_write_shell_script( + "${_tool_dir}/odb-true.sh" + "#!/usr/bin/env bash\n" + "printf '%s\\n' \"$*\" >> \"${log_path}\"\n") + set(${out_tool} "${_tool_dir}/odb-true.sh" PARENT_SCOPE) +endfunction() + +function(_cppbessot_migration_policy_retry_tool out_tool tool_dir) + cppbessot_test_write_shell_script( + "${tool_dir}/odb-retry.sh" + "#!/usr/bin/env bash\n" + "while [[ $# -gt 0 ]]; do\n" + " if [[ \"$1\" == \"--changelog-in\" ]]; then\n" + " changelog=\"$2\"\n" + " shift 2\n" + " else\n" + " shift\n" + " fi\n" + "done\n" + "if [[ \"$changelog\" == *\".empty-baseline\"* ]]; then\n" + " exit 0\n" + "fi\n" + "echo \"error: SQLite does not support dropping of columns\" >&2\n" + "exit 1\n") + set(${out_tool} "${tool_dir}/odb-retry.sh" PARENT_SCOPE) +endfunction() + +function(_cppbessot_migration_policy_false_tool out_tool tool_dir) + cppbessot_test_write_shell_script( + "${tool_dir}/odb-false.sh" + "#!/usr/bin/env bash\n" + "echo \"error: unrelated ODB failure\" >&2\n" + "exit 1\n") + set(${out_tool} "${tool_dir}/odb-false.sh" PARENT_SCOPE) +endfunction() + +cppbessot_test_case_dir(_case_dir) +set(_configure_root "${_case_dir}/configure-policy") +set(_configure_build "${_case_dir}/configure-policy-build") +cppbessot_test_reset_dir("${_configure_root}") +cppbessot_test_write_file( + "${_configure_root}/CMakeLists.txt" + "cmake_minimum_required(VERSION 3.20)\n" + "project(cppbessot_migration_policy_configure LANGUAGES CXX)\n" + "set(CPPBESSOT_AUTO_ENABLE OFF CACHE BOOL \"\")\n" + "include(\"${CPPBESSOT_TEST_MODULE_SOURCE_DIR}/cmake/CppBeSSOT.cmake\")\n") +execute_process( + COMMAND "${CMAKE_COMMAND}" -S "${_configure_root}" -B "${_configure_build}" + RESULT_VARIABLE _result + ERROR_VARIABLE _stderr) +cppbessot_test_assert_success("${_result}" "${_stderr}" "migration backend default configure") +file(READ "${_configure_build}/CMakeCache.txt" _cache_text) +cppbessot_test_assert_contains( + "${_cache_text}" + "CPPBESSOT_GEN_MIGRATION_BACKENDS:STRING=sqlite;pgsql" + "migration backend default cache") +cppbessot_test_assert_contains( + "${_cache_text}" + "CPPBESSOT_GEN_MIGRATIONS_BACKENDS:STRING=sqlite;pgsql" + "migration backend alias default cache") + +execute_process( + COMMAND "${CMAKE_COMMAND}" -S "${_configure_root}" -B "${_configure_build}" -DCPPBESSOT_GEN_MIGRATION_BACKENDS=pgsql + RESULT_VARIABLE _result + ERROR_VARIABLE _stderr) +cppbessot_test_assert_success("${_result}" "${_stderr}" "migration backend override reconfigure") +file(READ "${_configure_build}/CMakeCache.txt" _cache_text) +cppbessot_test_assert_contains( + "${_cache_text}" + "CPPBESSOT_GEN_MIGRATION_BACKENDS:STRING=pgsql" + "migration backend override cache") +cppbessot_test_assert_contains( + "${_cache_text}" + "CPPBESSOT_GEN_MIGRATIONS_BACKENDS:STRING=pgsql" + "migration backend alias override cache") + +_cppbessot_migration_policy_fixture(_default_root "default") +_cppbessot_migration_policy_true_tool(_true_tool "${_default_root}/odb.log") +_cppbessot_migration_policy_run("${_default_root}" "${_true_tool}" _result _stdout _stderr) +cppbessot_test_assert_success("${_result}" "${_stderr}" "default migration backend policy") +cppbessot_test_assert_file_exists("${_default_root}/migrations/sqlite") +cppbessot_test_assert_file_exists("${_default_root}/migrations/postgre") +file(READ "${_default_root}/odb.log" _default_log) +cppbessot_test_assert_contains("${_default_log}" "-d sqlite" "default backend log") +cppbessot_test_assert_contains("${_default_log}" "-d pgsql" "default backend log") +if(_default_log MATCHES "AgentPasswordHashType\\.h") + message(FATAL_ERROR "Enum-only headers must not be passed to ODB migration generation.") +endif() + +_cppbessot_migration_policy_fixture(_pgsql_root "pgsql-only") +_cppbessot_migration_policy_true_tool(_true_tool "${_pgsql_root}/odb.log") +_cppbessot_migration_policy_run( + "${_pgsql_root}" + "${_true_tool}" + _result + _stdout + _stderr + "-DCPPBESSOT_GEN_MIGRATION_BACKENDS=pgsql") +cppbessot_test_assert_success("${_result}" "${_stderr}" "pgsql-only migration backend policy") +cppbessot_test_assert_file_exists("${_pgsql_root}/migrations/postgre") +if(EXISTS "${_pgsql_root}/migrations/sqlite") + message(FATAL_ERROR "pgsql-only backend selection unexpectedly created sqlite migration output.") +endif() + +_cppbessot_migration_policy_fixture(_plural_root "plural-alias") +_cppbessot_migration_policy_true_tool(_true_tool "${_plural_root}/odb.log") +_cppbessot_migration_policy_run( + "${_plural_root}" + "${_true_tool}" + _result + _stdout + _stderr + "-DCPPBESSOT_GEN_MIGRATIONS_BACKENDS=sqlite") +cppbessot_test_assert_success("${_result}" "${_stderr}" "legacy plural backend alias policy") +cppbessot_test_assert_file_exists("${_plural_root}/migrations/sqlite") +if(EXISTS "${_plural_root}/migrations/postgre") + message(FATAL_ERROR "plural alias sqlite-only backend selection unexpectedly created postgre migration output.") +endif() + +_cppbessot_migration_policy_fixture(_invalid_root "invalid") +_cppbessot_migration_policy_run( + "${_invalid_root}" + "/bin/true" + _result + _stdout + _stderr + "-DCPPBESSOT_GEN_MIGRATION_BACKENDS=mysql") +cppbessot_test_assert_failure_contains("${_result}" "${_stderr}" "Unsupported migration backend") + +_cppbessot_migration_policy_fixture(_retry_root "sqlite-retry") +file(WRITE "${_retry_root}/from/generated-odb-source/sqlite/Agent.xml" "") +_cppbessot_migration_policy_retry_tool(_retry_tool "${_retry_root}") +_cppbessot_migration_policy_run( + "${_retry_root}" + "${_retry_tool}" + _result + _stdout + _stderr + "-DCPPBESSOT_GEN_MIGRATION_BACKENDS=sqlite") +cppbessot_test_assert_success("${_result}" "${_stderr}" "sqlite drop-column retry policy") +cppbessot_test_assert_contains("${_stderr}" "SQLite incremental migration failed" "sqlite retry warning") + +_cppbessot_migration_policy_fixture(_failure_root "sqlite-unrelated-failure") +file(WRITE "${_failure_root}/from/generated-odb-source/sqlite/Agent.xml" "") +_cppbessot_migration_policy_false_tool(_false_tool "${_failure_root}") +_cppbessot_migration_policy_run( + "${_failure_root}" + "${_false_tool}" + _result + _stdout + _stderr + "-DCPPBESSOT_GEN_MIGRATION_BACKENDS=sqlite") +cppbessot_test_assert_failure_contains("${_result}" "${_stderr}" "Migration generation failed")