mirror of
https://github.com/latentPrion/cppbessot.git
synced 2026-06-23 15:18:37 +00:00
Compare commits
3 Commits
6bb451dd94
...
f56b6b8989
| Author | SHA1 | Date | |
|---|---|---|---|
| f56b6b8989 | |||
| 9487dd4778 | |||
| b656569fc0 |
@@ -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`
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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/<from>-<to>/{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
|
||||
|
||||
+12
-2
@@ -13,16 +13,26 @@ function(cppbessot_add_db_gen_odb_target schema_dir)
|
||||
# - Files under `<schema_dir>/generated-odb-source/{sqlite,postgre}`.
|
||||
cppbessot_validate_schema_dir_name("${schema_dir}")
|
||||
cppbessot_get_schema_dir_path(_version_dir "${schema_dir}")
|
||||
cppbessot_get_expected_odb_generation_artifacts(
|
||||
_expected_odb_model_headers
|
||||
_expected_odb_sources
|
||||
"${schema_dir}")
|
||||
_cppbessot_get_openapi_file_path(_openapi_file "${schema_dir}")
|
||||
|
||||
add_custom_target(db_gen_odb_logic
|
||||
add_custom_command(
|
||||
OUTPUT ${_expected_odb_sources}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCPPBESSOT_ODB_EXECUTABLE=${CPPBESSOT_ODB_EXECUTABLE}
|
||||
-DCPPBESSOT_VERSION_DIR=${_version_dir}
|
||||
-P "${_CPPBESSOT_DB_GEN_ODB_DIR}/scripts/run_odb_logic.cmake"
|
||||
DEPENDS db_gen_cpp_headers
|
||||
DEPENDS "${_openapi_file}" ${_expected_odb_model_headers}
|
||||
COMMENT "Generating ODB ORM sources for ${schema_dir} (sqlite + postgre)"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_custom_target(db_gen_odb_logic
|
||||
DEPENDS ${_expected_odb_sources})
|
||||
add_dependencies(db_gen_odb_logic db_gen_cpp_headers)
|
||||
|
||||
set_target_properties(db_gen_odb_logic PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
endfunction()
|
||||
|
||||
@@ -20,7 +20,7 @@ function(cppbessot_add_db_gen_zod_target schema_dir)
|
||||
|
||||
add_custom_target(db_gen_zod
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${_output_dir}"
|
||||
COMMAND "${CPPBESSOT_NPX_EXECUTABLE}" --no-install openapi-zod-client
|
||||
COMMAND "${CPPBESSOT_NPX_EXECUTABLE}" --yes openapi-zod-client
|
||||
"${_openapi_file}"
|
||||
--output "${_output_file}"
|
||||
--export-schemas
|
||||
|
||||
+166
-24
@@ -116,19 +116,22 @@ function(cppbessot_get_model_headers_glob out_var schema_dir)
|
||||
set(${out_var} "${_schema_dir_path}/generated-cpp-source/include/*/model/*.h" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_openapi_schema_names out_var schema_dir)
|
||||
# Purpose: Parse top-level component schema names from a schema directory's OpenAPI file.
|
||||
function(_cppbessot_collect_openapi_schema_names out_var openapi_file filter_mode)
|
||||
# Purpose: Shared OpenAPI components.schemas walker.
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive the schema names.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# - out_var: Parent-scope variable for collected schema names.
|
||||
# - openapi_file: Absolute path to openapi.yaml.
|
||||
# - filter_mode: ALL (every top-level schema) or ODB_TABLE (x-odbTable only).
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): List of top-level component schema names.
|
||||
cppbessot_get_schema_dir_path(_schema_dir_path "${schema_dir}")
|
||||
cppbessot_assert_openapi_exists("${schema_dir}")
|
||||
set(_openapi_file "${_schema_dir_path}/openapi/openapi.yaml")
|
||||
# - <out_var> (PARENT_SCOPE): Collected schema names.
|
||||
if(NOT "${filter_mode}" STREQUAL "ALL" AND NOT "${filter_mode}" STREQUAL "ODB_TABLE")
|
||||
message(FATAL_ERROR
|
||||
"Unsupported OpenAPI schema filter `${filter_mode}`; expected ALL or ODB_TABLE.")
|
||||
endif()
|
||||
|
||||
file(STRINGS "${_openapi_file}" _openapi_lines)
|
||||
file(STRINGS "${openapi_file}" _openapi_lines)
|
||||
set(_schema_names)
|
||||
set(_current_schema_name)
|
||||
set(_in_components FALSE)
|
||||
set(_in_schemas FALSE)
|
||||
|
||||
@@ -136,8 +139,16 @@ function(cppbessot_get_openapi_schema_names out_var schema_dir)
|
||||
if(_in_schemas)
|
||||
if(_line MATCHES "^[^ ]" OR _line MATCHES "^ [^ ]")
|
||||
set(_in_schemas FALSE)
|
||||
unset(_current_schema_name)
|
||||
elseif(_line MATCHES "^ ([A-Za-z_][A-Za-z0-9_]*)[ \t]*:[ \t]*$")
|
||||
list(APPEND _schema_names "${CMAKE_MATCH_1}")
|
||||
set(_current_schema_name "${CMAKE_MATCH_1}")
|
||||
if("${filter_mode}" STREQUAL "ALL")
|
||||
list(APPEND _schema_names "${_current_schema_name}")
|
||||
endif()
|
||||
elseif("${filter_mode}" STREQUAL "ODB_TABLE"
|
||||
AND _current_schema_name
|
||||
AND _line MATCHES "^ x-odbTable:[ \t]*")
|
||||
list(APPEND _schema_names "${_current_schema_name}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -155,10 +166,52 @@ function(cppbessot_get_openapi_schema_names out_var schema_dir)
|
||||
endforeach()
|
||||
|
||||
if(NOT _schema_names)
|
||||
message(FATAL_ERROR
|
||||
"No component schema names were found in ${_openapi_file}.")
|
||||
if("${filter_mode}" STREQUAL "ODB_TABLE")
|
||||
message(FATAL_ERROR
|
||||
"No x-odbTable schema names were found in ${openapi_file}.")
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"No component schema names were found in ${openapi_file}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(REMOVE_DUPLICATES _schema_names)
|
||||
set(${out_var} "${_schema_names}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_cppbessot_get_openapi_file_path out_var schema_dir)
|
||||
# Purpose: Resolve and validate a schema directory's SSOT OpenAPI file path.
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive the absolute OpenAPI path.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): Absolute path to openapi.yaml.
|
||||
cppbessot_get_schema_dir_path(_schema_dir_path "${schema_dir}")
|
||||
cppbessot_assert_openapi_exists("${schema_dir}")
|
||||
set(${out_var} "${_schema_dir_path}/openapi/openapi.yaml" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_openapi_schema_names out_var schema_dir)
|
||||
# Purpose: Parse top-level component schema names from a schema directory's OpenAPI file.
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive the schema names.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): List of top-level component schema names.
|
||||
_cppbessot_get_openapi_file_path(_openapi_file "${schema_dir}")
|
||||
_cppbessot_collect_openapi_schema_names(_schema_names "${_openapi_file}" "ALL")
|
||||
set(${out_var} "${_schema_names}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_openapi_odb_table_schema_names out_var schema_dir)
|
||||
# Purpose: Parse OpenAPI schema names that declare x-odbTable (ODB object models).
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive the schema names.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): Schema names with x-odbTable in the OpenAPI file.
|
||||
_cppbessot_get_openapi_file_path(_openapi_file "${schema_dir}")
|
||||
_cppbessot_collect_openapi_schema_names(_schema_names "${_openapi_file}" "ODB_TABLE")
|
||||
set(${out_var} "${_schema_names}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -187,8 +240,41 @@ function(cppbessot_get_expected_cpp_model_outputs out_headers_var out_sources_va
|
||||
set(${out_sources_var} "${_sources}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(_cppbessot_build_odb_table_artifact_paths
|
||||
schema_dir
|
||||
schema_names
|
||||
out_model_headers_var
|
||||
out_sqlite_sources_var
|
||||
out_pgsql_sources_var)
|
||||
# Purpose: Build expected ODB model-header and backend source paths from schema names.
|
||||
# Inputs:
|
||||
# - schema_dir: Schema directory basename.
|
||||
# - schema_names: x-odbTable schema names.
|
||||
# Outputs:
|
||||
# - <out_model_headers_var> (PARENT_SCOPE): Expected generated ODB model headers.
|
||||
# - <out_sqlite_sources_var> (PARENT_SCOPE): Expected sqlite `*-odb.cxx` sources.
|
||||
# - <out_pgsql_sources_var> (PARENT_SCOPE): Expected postgre `*-odb.cxx` sources.
|
||||
cppbessot_get_schema_dir_path(_schema_dir_path "${schema_dir}")
|
||||
|
||||
set(_headers)
|
||||
set(_sqlite_sources)
|
||||
set(_pgsql_sources)
|
||||
foreach(_schema_name IN LISTS schema_names)
|
||||
list(APPEND _headers
|
||||
"${_schema_dir_path}/generated-cpp-source/include/cppbessot/model/${_schema_name}.h")
|
||||
list(APPEND _sqlite_sources
|
||||
"${_schema_dir_path}/generated-odb-source/sqlite/${_schema_name}-odb.cxx")
|
||||
list(APPEND _pgsql_sources
|
||||
"${_schema_dir_path}/generated-odb-source/postgre/${_schema_name}-odb.cxx")
|
||||
endforeach()
|
||||
|
||||
set(${out_model_headers_var} "${_headers}" PARENT_SCOPE)
|
||||
set(${out_sqlite_sources_var} "${_sqlite_sources}" PARENT_SCOPE)
|
||||
set(${out_pgsql_sources_var} "${_pgsql_sources}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_expected_odb_outputs out_sqlite_sources_var out_pgsql_sources_var schema_dir)
|
||||
# Purpose: Infer generated ODB backend source files from OpenAPI schema names.
|
||||
# Purpose: Infer generated ODB backend source files from x-odbTable OpenAPI schemas.
|
||||
# Inputs:
|
||||
# - out_sqlite_sources_var: Parent-scope variable for sqlite `*-odb.cxx`.
|
||||
# - out_pgsql_sources_var: Parent-scope variable for postgre `*-odb.cxx`.
|
||||
@@ -196,18 +282,74 @@ function(cppbessot_get_expected_odb_outputs out_sqlite_sources_var out_pgsql_sou
|
||||
# Outputs:
|
||||
# - <out_sqlite_sources_var> (PARENT_SCOPE): Expected sqlite ODB sources.
|
||||
# - <out_pgsql_sources_var> (PARENT_SCOPE): Expected postgre ODB sources.
|
||||
cppbessot_get_schema_dir_path(_schema_dir_path "${schema_dir}")
|
||||
cppbessot_get_openapi_schema_names(_schema_names "${schema_dir}")
|
||||
|
||||
set(_sqlite_sources)
|
||||
set(_pgsql_sources)
|
||||
foreach(_schema_name IN LISTS _schema_names)
|
||||
list(APPEND _sqlite_sources
|
||||
"${_schema_dir_path}/generated-odb-source/sqlite/${_schema_name}-odb.cxx")
|
||||
list(APPEND _pgsql_sources
|
||||
"${_schema_dir_path}/generated-odb-source/postgre/${_schema_name}-odb.cxx")
|
||||
endforeach()
|
||||
cppbessot_get_openapi_odb_table_schema_names(_schema_names "${schema_dir}")
|
||||
_cppbessot_build_odb_table_artifact_paths(
|
||||
"${schema_dir}"
|
||||
"${_schema_names}"
|
||||
_expected_model_headers
|
||||
_sqlite_sources
|
||||
_pgsql_sources)
|
||||
|
||||
set(${out_sqlite_sources_var} "${_sqlite_sources}" PARENT_SCOPE)
|
||||
set(${out_pgsql_sources_var} "${_pgsql_sources}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_expected_odb_model_headers out_var schema_dir)
|
||||
# Purpose: Infer generated C++ model headers for x-odbTable OpenAPI schemas.
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive expected ODB model headers.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): Expected generated model headers for ODB objects.
|
||||
cppbessot_get_openapi_odb_table_schema_names(_schema_names "${schema_dir}")
|
||||
_cppbessot_build_odb_table_artifact_paths(
|
||||
"${schema_dir}"
|
||||
"${_schema_names}"
|
||||
_headers
|
||||
_sqlite_sources
|
||||
_pgsql_sources)
|
||||
|
||||
set(${out_var} "${_headers}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_expected_odb_outputs_all out_var schema_dir)
|
||||
# Purpose: Infer all generated ODB backend `*-odb.cxx` files for both backends.
|
||||
# Inputs:
|
||||
# - out_var: Parent-scope variable name to receive expected ODB sources.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_var> (PARENT_SCOPE): Expected sqlite + postgre ODB sources.
|
||||
cppbessot_get_expected_odb_outputs(
|
||||
_expected_sqlite_odb_sources
|
||||
_expected_pgsql_odb_sources
|
||||
"${schema_dir}")
|
||||
set(_combined
|
||||
${_expected_sqlite_odb_sources}
|
||||
${_expected_pgsql_odb_sources})
|
||||
set(${out_var} "${_combined}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(cppbessot_get_expected_odb_generation_artifacts
|
||||
out_model_headers_var
|
||||
out_all_sources_var
|
||||
schema_dir)
|
||||
# Purpose: Infer ODB generation dependencies and outputs in a single OpenAPI pass.
|
||||
# Inputs:
|
||||
# - out_model_headers_var: Parent-scope variable for expected ODB model headers.
|
||||
# - out_all_sources_var: Parent-scope variable for expected sqlite + postgre sources.
|
||||
# - schema_dir: Schema directory basename.
|
||||
# Outputs:
|
||||
# - <out_model_headers_var> (PARENT_SCOPE): Expected generated ODB model headers.
|
||||
# - <out_all_sources_var> (PARENT_SCOPE): Expected sqlite + postgre `*-odb.cxx` sources.
|
||||
cppbessot_get_openapi_odb_table_schema_names(_schema_names "${schema_dir}")
|
||||
_cppbessot_build_odb_table_artifact_paths(
|
||||
"${schema_dir}"
|
||||
"${_schema_names}"
|
||||
_headers
|
||||
_sqlite_sources
|
||||
_pgsql_sources)
|
||||
set(_combined ${_sqlite_sources} ${_pgsql_sources})
|
||||
|
||||
set(${out_model_headers_var} "${_headers}" PARENT_SCOPE)
|
||||
set(${out_all_sources_var} "${_combined}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
function(cppbessot_odb_find_object_headers out_var include_dir)
|
||||
file(GLOB _headers "${include_dir}/*/model/*.h")
|
||||
if(NOT _headers)
|
||||
message(FATAL_ERROR "No model headers found under ${include_dir}")
|
||||
endif()
|
||||
|
||||
set(_object_headers "")
|
||||
foreach(_header IN LISTS _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 ${include_dir}")
|
||||
endif()
|
||||
|
||||
set(${out_var} "${_object_headers}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotOdbHeaderDiscovery.cmake")
|
||||
|
||||
if(NOT DEFINED CPPBESSOT_ODB_EXECUTABLE OR CPPBESSOT_ODB_EXECUTABLE STREQUAL "")
|
||||
message(FATAL_ERROR "CPPBESSOT_ODB_EXECUTABLE is required")
|
||||
@@ -8,10 +9,7 @@ if(NOT DEFINED CPPBESSOT_VERSION_DIR OR CPPBESSOT_VERSION_DIR STREQUAL "")
|
||||
endif()
|
||||
|
||||
set(_include_dir "${CPPBESSOT_VERSION_DIR}/generated-cpp-source/include")
|
||||
file(GLOB _headers "${_include_dir}/*/model/*.h")
|
||||
if(NOT _headers)
|
||||
message(FATAL_ERROR "No model headers found under ${_include_dir}")
|
||||
endif()
|
||||
cppbessot_odb_find_object_headers(_object_headers "${_include_dir}")
|
||||
|
||||
foreach(_backend IN ITEMS sqlite pgsql)
|
||||
if(_backend STREQUAL "sqlite")
|
||||
@@ -25,7 +23,7 @@ foreach(_backend IN ITEMS sqlite pgsql)
|
||||
|
||||
execute_process(
|
||||
COMMAND "${CPPBESSOT_ODB_EXECUTABLE}" -I "${_include_dir}" --std c++11 -d "${_backend}" -q
|
||||
-o "${_out_dir}" --changelog-dir "${_out_dir}" ${_headers}
|
||||
-o "${_out_dir}" --changelog-dir "${_out_dir}" ${_object_headers}
|
||||
RESULT_VARIABLE _result
|
||||
OUTPUT_VARIABLE _stdout
|
||||
ERROR_VARIABLE _stderr
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotOdbHeaderDiscovery.cmake")
|
||||
|
||||
if(NOT DEFINED CPPBESSOT_ODB_EXECUTABLE OR CPPBESSOT_ODB_EXECUTABLE STREQUAL "")
|
||||
message(FATAL_ERROR "CPPBESSOT_ODB_EXECUTABLE is required")
|
||||
@@ -13,36 +14,115 @@ if(NOT DEFINED CPPBESSOT_MIGRATION_DIR OR CPPBESSOT_MIGRATION_DIR STREQUAL "")
|
||||
message(FATAL_ERROR "CPPBESSOT_MIGRATION_DIR is required")
|
||||
endif()
|
||||
|
||||
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)
|
||||
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(_subdir postgre)
|
||||
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}"
|
||||
"<changelog xmlns=\"http://www.codesynthesis.com/xmlns/odb/changelog\" database=\"${database_attr}\" version=\"1\">\n"
|
||||
" <model version=\"1\">\n"
|
||||
" </model>\n"
|
||||
"</changelog>\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")
|
||||
cppbessot_odb_find_object_headers(_object_headers "${_to_include_dir}")
|
||||
|
||||
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 +130,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}")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotOdbHeaderDiscovery.cmake")
|
||||
|
||||
if(NOT DEFINED CPPBESSOT_ODB_EXECUTABLE OR CPPBESSOT_ODB_EXECUTABLE STREQUAL "")
|
||||
message(FATAL_ERROR "CPPBESSOT_ODB_EXECUTABLE is required")
|
||||
@@ -8,10 +9,7 @@ if(NOT DEFINED CPPBESSOT_VERSION_DIR OR CPPBESSOT_VERSION_DIR STREQUAL "")
|
||||
endif()
|
||||
|
||||
set(_include_dir "${CPPBESSOT_VERSION_DIR}/generated-cpp-source/include")
|
||||
file(GLOB _headers "${_include_dir}/*/model/*.h")
|
||||
if(NOT _headers)
|
||||
message(FATAL_ERROR "No model headers found under ${_include_dir}")
|
||||
endif()
|
||||
cppbessot_odb_find_object_headers(_object_headers "${_include_dir}")
|
||||
|
||||
foreach(_backend IN ITEMS sqlite pgsql)
|
||||
if(_backend STREQUAL "sqlite")
|
||||
@@ -28,7 +26,7 @@ foreach(_backend IN ITEMS sqlite pgsql)
|
||||
execute_process(
|
||||
COMMAND "${CPPBESSOT_ODB_EXECUTABLE}" -I "${_include_dir}" --std c++11 -d "${_backend}"
|
||||
--generate-schema --schema-format sql -q
|
||||
-o "${_ddl_dir}" --changelog-dir "${_changelog_dir}" ${_headers}
|
||||
-o "${_ddl_dir}" --changelog-dir "${_changelog_dir}" ${_object_headers}
|
||||
RESULT_VARIABLE _result
|
||||
OUTPUT_VARIABLE _stdout
|
||||
ERROR_VARIABLE _stderr
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <odb/core.hxx>
|
||||
|
||||
{{#vars}}
|
||||
{{#vendorExtensions.x-cppType}}
|
||||
#include <cppbessot/model/{{vendorExtensions.x-cppType}}.h>
|
||||
{{/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}})
|
||||
|
||||
@@ -68,6 +68,8 @@ 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_db_action_test(cppbessot_openapi_odb_table_filter openapi_odb_table_filter.cmake)
|
||||
cppbessot_add_real_pgsql_db_action_test(
|
||||
cppbessot_db_action_pgsql_createfrom_real
|
||||
pgsql_createfrom_real.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")
|
||||
@@ -0,0 +1,131 @@
|
||||
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)
|
||||
|
||||
cppbessot_test_case_dir(_case_dir)
|
||||
set(_fixture_root "${_case_dir}/openapi-filter")
|
||||
cppbessot_test_reset_dir("${_fixture_root}")
|
||||
file(MAKE_DIRECTORY "${_fixture_root}/db/v1.test/openapi")
|
||||
cppbessot_test_write_file(
|
||||
"${_fixture_root}/db/v1.test/openapi/openapi.yaml"
|
||||
"openapi: 3.0.3\n"
|
||||
"info:\n"
|
||||
" title: cppbessot-openapi-filter-test\n"
|
||||
" version: \"1.0.0\"\n"
|
||||
"paths: {}\n"
|
||||
"components:\n"
|
||||
" schemas:\n"
|
||||
" AgentPasswordHashType:\n"
|
||||
" type: integer\n"
|
||||
" format: int32\n"
|
||||
" enum:\n"
|
||||
" - 0\n"
|
||||
" CredentialType:\n"
|
||||
" type: integer\n"
|
||||
" format: int32\n"
|
||||
" enum:\n"
|
||||
" - 0\n"
|
||||
" Agents:\n"
|
||||
" type: object\n"
|
||||
" x-odbTable: Agents\n"
|
||||
" properties:\n"
|
||||
" id:\n"
|
||||
" type: string\n"
|
||||
" Roles:\n"
|
||||
" type: object\n"
|
||||
" x-odbTable: Roles\n"
|
||||
" properties:\n"
|
||||
" id:\n"
|
||||
" type: string\n")
|
||||
|
||||
set(_module_cmake_dir "${CPPBESSOT_TEST_MODULE_SOURCE_DIR}/cmake")
|
||||
set(PROJECT_SOURCE_DIR "${_fixture_root}")
|
||||
set(CPPBESSOT_WORKDIR "db")
|
||||
include("${_module_cmake_dir}/dbGenerationCommon.cmake")
|
||||
|
||||
cppbessot_get_openapi_schema_names(_all_schema_names "v1.test")
|
||||
cppbessot_get_openapi_odb_table_schema_names(_odb_table_schema_names "v1.test")
|
||||
cppbessot_get_expected_odb_outputs(
|
||||
_sqlite_odb_sources
|
||||
_pgsql_odb_sources
|
||||
"v1.test")
|
||||
cppbessot_get_expected_odb_model_headers(_odb_model_headers "v1.test")
|
||||
cppbessot_get_expected_odb_outputs_all(_all_odb_sources "v1.test")
|
||||
cppbessot_get_expected_odb_generation_artifacts(
|
||||
_generation_model_headers
|
||||
_generation_all_odb_sources
|
||||
"v1.test")
|
||||
|
||||
set(_expected_all_schema_names
|
||||
AgentPasswordHashType
|
||||
CredentialType
|
||||
Agents
|
||||
Roles)
|
||||
set(_expected_odb_table_schema_names
|
||||
Agents
|
||||
Roles)
|
||||
|
||||
function(_cppbessot_assert_same_list label actual expected)
|
||||
list(SORT actual)
|
||||
list(SORT expected)
|
||||
if(NOT "${actual}" STREQUAL "${expected}")
|
||||
message(FATAL_ERROR
|
||||
"${label} mismatch.\n"
|
||||
" expected: ${expected}\n"
|
||||
" actual: ${actual}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
_cppbessot_assert_same_list(
|
||||
"all schema names"
|
||||
"${_all_schema_names}"
|
||||
"${_expected_all_schema_names}")
|
||||
_cppbessot_assert_same_list(
|
||||
"x-odbTable schema names"
|
||||
"${_odb_table_schema_names}"
|
||||
"${_expected_odb_table_schema_names}")
|
||||
_cppbessot_assert_same_list(
|
||||
"generation artifact model headers"
|
||||
"${_generation_model_headers}"
|
||||
"${_odb_model_headers}")
|
||||
_cppbessot_assert_same_list(
|
||||
"generation artifact ODB sources"
|
||||
"${_generation_all_odb_sources}"
|
||||
"${_all_odb_sources}")
|
||||
|
||||
list(LENGTH _sqlite_odb_sources _sqlite_count)
|
||||
list(LENGTH _pgsql_odb_sources _pgsql_count)
|
||||
list(LENGTH _odb_model_headers _header_count)
|
||||
list(LENGTH _all_odb_sources _all_odb_count)
|
||||
|
||||
if(NOT _sqlite_count EQUAL 2)
|
||||
message(FATAL_ERROR
|
||||
"Expected 2 sqlite ODB sources, got ${_sqlite_count}: ${_sqlite_odb_sources}")
|
||||
endif()
|
||||
if(NOT _pgsql_count EQUAL 2)
|
||||
message(FATAL_ERROR
|
||||
"Expected 2 postgre ODB sources, got ${_pgsql_count}: ${_pgsql_odb_sources}")
|
||||
endif()
|
||||
if(NOT _header_count EQUAL 2)
|
||||
message(FATAL_ERROR
|
||||
"Expected 2 ODB model headers, got ${_header_count}: ${_odb_model_headers}")
|
||||
endif()
|
||||
if(NOT _all_odb_count EQUAL 4)
|
||||
message(FATAL_ERROR
|
||||
"Expected 4 combined ODB sources, got ${_all_odb_count}: ${_all_odb_sources}")
|
||||
endif()
|
||||
|
||||
foreach(_forbidden IN ITEMS
|
||||
AgentPasswordHashType
|
||||
CredentialType)
|
||||
foreach(_backend IN ITEMS sqlite postgre)
|
||||
set(_forbidden_source
|
||||
"${_fixture_root}/db/v1.test/generated-odb-source/${_backend}/${_forbidden}-odb.cxx")
|
||||
list(FIND _all_odb_sources "${_forbidden_source}" _forbidden_index)
|
||||
if(NOT _forbidden_index EQUAL -1)
|
||||
message(FATAL_ERROR
|
||||
"Enum schema `${_forbidden}` must not produce `${_forbidden_source}`.")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
@@ -30,5 +30,39 @@ execute_process(
|
||||
cppbessot_test_assert_success("${_cfg_result}" "${_cfg_stderr}" "fixture configure")
|
||||
cppbessot_test_build_target_dry_run("${_build_dir}" "cppBeSsotOpenAiModelGen" _model_result _model_stdout _model_stderr)
|
||||
cppbessot_test_assert_success("${_model_result}" "${_model_stderr}" "dry-run openai model lib build")
|
||||
cppbessot_test_build_target_dry_run("${_build_dir}" "cppBeSsotOdbSqlite" _odb_sqlite_result _odb_sqlite_stdout _odb_sqlite_stderr)
|
||||
cppbessot_test_assert_success("${_odb_sqlite_result}" "${_odb_sqlite_stderr}" "dry-run sqlite ODB lib build")
|
||||
cppbessot_test_build_target_dry_run("${_build_dir}" "cppBeSsotOdbPgSql" _odb_pgsql_result _odb_pgsql_stdout _odb_pgsql_stderr)
|
||||
cppbessot_test_assert_success("${_odb_pgsql_result}" "${_odb_pgsql_stderr}" "dry-run postgre ODB lib build")
|
||||
cppbessot_test_build_target_dry_run("${_build_dir}" "db_gen_migrations" _mig_result _mig_stdout _mig_stderr)
|
||||
cppbessot_test_assert_success("${_mig_result}" "${_mig_stderr}" "dry-run migration generation build")
|
||||
|
||||
# v1.3 includes enum-only schemas that must not become ODB library sources.
|
||||
set(_v13_build_dir "${CPPBESSOT_TEST_BINARY_DIR}/regression-build-v1.3")
|
||||
cppbessot_test_reset_dir("${_v13_build_dir}")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-S "${_repo_root}"
|
||||
-B "${_v13_build_dir}"
|
||||
-DDB_SCHEMA_DIR_TO_GENERATE=v1.3
|
||||
-DDB_SCHEMA_DIR_MIGRATION_FROM=v1.2
|
||||
-DDB_SCHEMA_DIR_MIGRATION_TO=v1.3
|
||||
-DCPPBESSOT_AUTO_ENABLE=ON
|
||||
-DCOURESILIENT_USE_LOCAL_CPPBESSOT_ENV=OFF
|
||||
-DCPPBESSOT_DB_PGSQL_PROD_CONNSTR=
|
||||
-DCPPBESSOT_DB_PGSQL_DEV_CONNSTR=
|
||||
-DCPPBESSOT_DB_PGSQL_PRODDEV_CONNSTR=
|
||||
-DCPPBESSOT_DB_PGSQL_TESTS_CONNSTR=
|
||||
-DCPPBESSOT_DB_SQLITE_PROD_PATH=
|
||||
-DCPPBESSOT_DB_SQLITE_DEV_PATH=
|
||||
-DCPPBESSOT_DB_SQLITE_PRODDEV_PATH=
|
||||
-DCPPBESSOT_DB_SQLITE_TESTS_PATH=
|
||||
RESULT_VARIABLE _v13_cfg_result
|
||||
OUTPUT_VARIABLE _v13_cfg_stdout
|
||||
ERROR_VARIABLE _v13_cfg_stderr
|
||||
)
|
||||
cppbessot_test_assert_success("${_v13_cfg_result}" "${_v13_cfg_stderr}" "v1.3 fixture configure")
|
||||
cppbessot_test_build_target_dry_run("${_v13_build_dir}" "cppBeSsotOdbSqlite" _v13_sqlite_result _v13_sqlite_stdout _v13_sqlite_stderr)
|
||||
cppbessot_test_assert_success("${_v13_sqlite_result}" "${_v13_sqlite_stderr}" "v1.3 dry-run sqlite ODB lib build")
|
||||
cppbessot_test_build_target_dry_run("${_v13_build_dir}" "cppBeSsotOdbPgSql" _v13_pgsql_result _v13_pgsql_stdout _v13_pgsql_stderr)
|
||||
cppbessot_test_assert_success("${_v13_pgsql_result}" "${_v13_pgsql_stderr}" "v1.3 dry-run postgre ODB lib build")
|
||||
|
||||
Reference in New Issue
Block a user