Add migration commands for SQLite; not PGSql

This commit is contained in:
2026-04-29 23:19:50 -04:00
parent e12ad0ecac
commit 68724dff8f
34 changed files with 1289 additions and 13 deletions
+42
View File
@@ -9,6 +9,9 @@ include("${CMAKE_CURRENT_LIST_DIR}/dbGenCpp.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbGenODB.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbGenSqlDDL.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbGenMigrations.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbActionCommon.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbActionCreateFrom.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbActionMigrate.cmake")
if(NOT DEFINED CPPBESSOT_WORKDIR)
set(CPPBESSOT_WORKDIR "db" CACHE STRING "CppBeSSOT schema root folder")
@@ -32,6 +35,41 @@ if(NOT DEFINED DB_SCHEMA_CHANGES_ARE_ERROR)
option(DB_SCHEMA_CHANGES_ARE_ERROR "Treat dirty schema changes as hard CMake error" OFF)
endif()
if(NOT DEFINED DB_TARGET)
set(DB_TARGET "dev" CACHE STRING "Live DB target to act on: prod, proddev, or dev")
endif()
if(NOT DEFINED DB_CREATEFROM_SCHEMA_DIR)
set(DB_CREATEFROM_SCHEMA_DIR "${DB_SCHEMA_DIR_TO_GENERATE}" CACHE STRING
"Schema directory basename under CPPBESSOT_WORKDIR to create a live DB from")
endif()
if(NOT DEFINED DB_MIGRATE_WITH)
set(DB_MIGRATE_WITH "" CACHE STRING
"Migration directory basename under CPPBESSOT_WORKDIR/migrations to apply to the selected DB target")
endif()
if(NOT DEFINED DB_MIGRATE_PRODDEV_USE_STALE)
option(DB_MIGRATE_PRODDEV_USE_STALE "Reuse an existing stale proddev clone instead of recloning from prod" OFF)
endif()
set(CPPBESSOT_DB_SQLITE_PROD_PATH "${CPPBESSOT_DB_SQLITE_PROD_PATH}" CACHE STRING
"Parent-supplied SQLite DB path for DB_TARGET=prod")
set(CPPBESSOT_DB_SQLITE_DEV_PATH "${CPPBESSOT_DB_SQLITE_DEV_PATH}" CACHE STRING
"Parent-supplied SQLite DB path for DB_TARGET=dev")
set(CPPBESSOT_DB_SQLITE_PRODDEV_PATH "${CPPBESSOT_DB_SQLITE_PRODDEV_PATH}" CACHE STRING
"Parent-supplied SQLite DB path for DB_TARGET=proddev")
set(CPPBESSOT_DB_PGSQL_PROD_CONNSTR "${CPPBESSOT_DB_PGSQL_PROD_CONNSTR}" CACHE STRING
"Parent-supplied PostgreSQL connection string for DB_TARGET=prod")
set(CPPBESSOT_DB_PGSQL_DEV_CONNSTR "${CPPBESSOT_DB_PGSQL_DEV_CONNSTR}" CACHE STRING
"Parent-supplied PostgreSQL connection string for DB_TARGET=dev")
set(CPPBESSOT_DB_PGSQL_PRODDEV_CONNSTR "${CPPBESSOT_DB_PGSQL_PRODDEV_CONNSTR}" CACHE STRING
"Parent-supplied PostgreSQL connection string for DB_TARGET=proddev")
set(CPPBESSOT_DB_SQLITE_CLONE_PROD_TO_PRODDEV_COMMAND "${CPPBESSOT_DB_SQLITE_CLONE_PROD_TO_PRODDEV_COMMAND}" CACHE STRING
"Parent-supplied command string that clones the prod SQLite DB into proddev")
set(CPPBESSOT_DB_PGSQL_CLONE_PROD_TO_PRODDEV_COMMAND "${CPPBESSOT_DB_PGSQL_CLONE_PROD_TO_PRODDEV_COMMAND}" CACHE STRING
"Parent-supplied command string that clones the prod PostgreSQL DB into proddev")
if(NOT DEFINED CPPBESSOT_AUTO_ENABLE)
option(CPPBESSOT_AUTO_ENABLE "Auto-register CppBeSSOT targets when this file is included" ON)
endif()
@@ -218,6 +256,8 @@ function(cppbessot_enable)
# - db_gen_sql_ddl
# - db_gen_migrations
# - db_gen_orm_serdes_and_zod
# - db_createfrom
# - db_migrate
# - Generated library targets for selected schema version.
cppbessot_initialize_paths()
@@ -261,6 +301,8 @@ VERBATIM
db_gen_sql_ddl)
set_target_properties(db_gen_orm_serdes_and_zod PROPERTIES EXCLUDE_FROM_ALL TRUE)
cppbessot_add_db_createfrom_target()
cppbessot_add_db_migrate_target()
cppbessot_add_generated_libraries()
endfunction()
+53
View File
@@ -0,0 +1,53 @@
include_guard(GLOBAL)
include("${CMAKE_CURRENT_LIST_DIR}/dbGenerationCommon.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/dbActionShared.cmake")
function(cppbessot_validate_db_target db_target)
_cppbessot_db_action_validate_db_target_impl("${db_target}")
endfunction()
function(cppbessot_validate_migration_dir_name migration_dir)
_cppbessot_db_action_validate_basename(
"${migration_dir}"
"Migration directory name"
"CPPBESSOT_WORKDIR/migrations")
endfunction()
function(cppbessot_get_migration_dir_path out_var migration_dir)
cppbessot_validate_migration_dir_name("${migration_dir}")
cppbessot_abs_path(_workdir "${CPPBESSOT_WORKDIR}")
set(${out_var} "${_workdir}/migrations/${migration_dir}" PARENT_SCOPE)
endfunction()
function(cppbessot_assert_migration_dir_exists migration_dir)
cppbessot_get_migration_dir_path(_migration_dir_path "${migration_dir}")
if(NOT IS_DIRECTORY "${_migration_dir_path}")
message(FATAL_ERROR "Migration directory does not exist: ${_migration_dir_path}")
endif()
endfunction()
function(_cppbessot_db_action_common_cache_args out_var)
set(_args
"-DCPPBESSOT_PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}"
"-DCPPBESSOT_WORKDIR=${CPPBESSOT_WORKDIR}"
"-DDB_SCHEMA_DIR_TO_GENERATE=${DB_SCHEMA_DIR_TO_GENERATE}"
"-DDB_CREATEFROM_SCHEMA_DIR=${DB_CREATEFROM_SCHEMA_DIR}"
"-DDB_TARGET=${DB_TARGET}"
"-DCPPBESSOT_DB_SQLITE_PROD_PATH=${CPPBESSOT_DB_SQLITE_PROD_PATH}"
"-DCPPBESSOT_DB_SQLITE_DEV_PATH=${CPPBESSOT_DB_SQLITE_DEV_PATH}"
"-DCPPBESSOT_DB_SQLITE_PRODDEV_PATH=${CPPBESSOT_DB_SQLITE_PRODDEV_PATH}"
"-DCPPBESSOT_DB_PGSQL_PROD_CONNSTR=${CPPBESSOT_DB_PGSQL_PROD_CONNSTR}"
"-DCPPBESSOT_DB_PGSQL_DEV_CONNSTR=${CPPBESSOT_DB_PGSQL_DEV_CONNSTR}"
"-DCPPBESSOT_DB_PGSQL_PRODDEV_CONNSTR=${CPPBESSOT_DB_PGSQL_PRODDEV_CONNSTR}")
set(${out_var} "${_args}" PARENT_SCOPE)
endfunction()
function(_cppbessot_add_db_action_target target_name script_path comment_text)
add_custom_target(${target_name}
COMMAND "${CMAKE_COMMAND}" ${ARGN} -P "${script_path}"
COMMENT "${comment_text}"
VERBATIM
)
set_target_properties(${target_name} PROPERTIES EXCLUDE_FROM_ALL TRUE)
endfunction()
+13
View File
@@ -0,0 +1,13 @@
include_guard(GLOBAL)
include("${CMAKE_CURRENT_LIST_DIR}/dbActionCommon.cmake")
set(_CPPBESSOT_DB_ACTION_CREATEFROM_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(cppbessot_add_db_createfrom_target)
_cppbessot_db_action_common_cache_args(_common_args)
_cppbessot_add_db_action_target(
db_createfrom
"${_CPPBESSOT_DB_ACTION_CREATEFROM_DIR}/scripts/run_db_createfrom.cmake"
"Creating live DB target `${DB_TARGET}` from schema `${DB_CREATEFROM_SCHEMA_DIR}`"
${_common_args})
endfunction()
+17
View File
@@ -0,0 +1,17 @@
include_guard(GLOBAL)
include("${CMAKE_CURRENT_LIST_DIR}/dbActionCommon.cmake")
set(_CPPBESSOT_DB_ACTION_MIGRATE_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(cppbessot_add_db_migrate_target)
_cppbessot_db_action_common_cache_args(_common_args)
_cppbessot_add_db_action_target(
db_migrate
"${_CPPBESSOT_DB_ACTION_MIGRATE_DIR}/scripts/run_db_migrate.cmake"
"Migrating live DB target `${DB_TARGET}` using migration `${DB_MIGRATE_WITH}`"
${_common_args}
"-DDB_MIGRATE_WITH=${DB_MIGRATE_WITH}"
"-DDB_MIGRATE_PRODDEV_USE_STALE=${DB_MIGRATE_PRODDEV_USE_STALE}"
"-DCPPBESSOT_DB_SQLITE_CLONE_PROD_TO_PRODDEV_COMMAND=${CPPBESSOT_DB_SQLITE_CLONE_PROD_TO_PRODDEV_COMMAND}"
"-DCPPBESSOT_DB_PGSQL_CLONE_PROD_TO_PRODDEV_COMMAND=${CPPBESSOT_DB_PGSQL_CLONE_PROD_TO_PRODDEV_COMMAND}")
endfunction()
+20
View File
@@ -0,0 +1,20 @@
include_guard(GLOBAL)
function(_cppbessot_db_action_validate_basename value kind relative_root)
if("${value}" STREQUAL "")
message(FATAL_ERROR "${kind} must not be empty.")
endif()
if("${value}" MATCHES "[/\\\\]")
message(FATAL_ERROR
"${kind} `${value}` must be a basename under ${relative_root}, not a path.")
endif()
endfunction()
function(_cppbessot_db_action_validate_db_target_impl db_target)
if(NOT "${db_target}" STREQUAL "prod"
AND NOT "${db_target}" STREQUAL "proddev"
AND NOT "${db_target}" STREQUAL "dev")
message(FATAL_ERROR "DB_TARGET must be one of: prod, proddev, dev.")
endif()
endfunction()
+32 -13
View File
@@ -4,6 +4,24 @@ include("${CMAKE_CURRENT_LIST_DIR}/dbGenerationCommon.cmake")
include(CheckIncludeFileCXX)
include(CMakePushCheckState)
function(_cppbessot_publish_dependency_outputs)
set(CPPBESSOT_ODB_EXECUTABLE "${CPPBESSOT_ODB_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_NPX_EXECUTABLE "${CPPBESSOT_NPX_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_NPM_EXECUTABLE "${CPPBESSOT_NPM_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_JAVA_EXECUTABLE "${CPPBESSOT_JAVA_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_GIT_EXECUTABLE "${CPPBESSOT_GIT_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_SQLITE3_EXECUTABLE "${CPPBESSOT_SQLITE3_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_PSQL_EXECUTABLE "${CPPBESSOT_PSQL_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_ODB_RUNTIME_LIB "${CPPBESSOT_ODB_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_ODB_SQLITE_RUNTIME_LIB "${CPPBESSOT_ODB_SQLITE_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_ODB_PGSQL_RUNTIME_LIB "${CPPBESSOT_ODB_PGSQL_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_SQLITE_INCLUDE_DIR "${CPPBESSOT_SQLITE_INCLUDE_DIR}" PARENT_SCOPE)
set(CPPBESSOT_PGSQL_INCLUDE_DIR "${CPPBESSOT_PGSQL_INCLUDE_DIR}" PARENT_SCOPE)
set(CPPBESSOT_SQLITE_CLIENT_LIB "${CPPBESSOT_SQLITE_CLIENT_LIB}" PARENT_SCOPE)
set(CPPBESSOT_PGSQL_CLIENT_LIB "${CPPBESSOT_PGSQL_CLIENT_LIB}" PARENT_SCOPE)
set(CPPBESSOT_OPENAPI_ZOD_AVAILABLE TRUE PARENT_SCOPE)
endfunction()
function(_cppbessot_require_program var_name program_name hint)
# Purpose: Locate an executable and fail with a clear install hint if missing.
# Inputs:
@@ -64,6 +82,7 @@ function(_cppbessot_require_npx_package_executable npx_executable package_execut
# - No return value; raises FATAL_ERROR if execution fails.
execute_process(
COMMAND "${npx_executable}" --no-install "${package_executable}" --help
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
RESULT_VARIABLE _help_result
OUTPUT_QUIET
ERROR_VARIABLE _help_stderr
@@ -76,6 +95,7 @@ function(_cppbessot_require_npx_package_executable npx_executable package_execut
# Some CLIs return non-zero for --help; verify with version as fallback.
execute_process(
COMMAND "${npx_executable}" --no-install "${package_executable}" version
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
RESULT_VARIABLE _version_result
OUTPUT_QUIET
ERROR_VARIABLE _version_stderr
@@ -101,6 +121,12 @@ function(cppbessot_check_dependencies)
# - CPPBESSOT_GIT_EXECUTABLE (PARENT_SCOPE)
# - CPPBESSOT_OPENAPI_ZOD_AVAILABLE (PARENT_SCOPE)
# - No return value; raises FATAL_ERROR on missing dependencies.
get_property(_cppbessot_dependencies_checked GLOBAL PROPERTY CPPBESSOT_DEPENDENCIES_CHECKED)
if(_cppbessot_dependencies_checked)
_cppbessot_publish_dependency_outputs()
return()
endif()
_cppbessot_require_program(CPPBESSOT_ODB_EXECUTABLE odb
"Install ODB compiler and ensure `odb` is in PATH.")
_cppbessot_require_program(CPPBESSOT_NPX_EXECUTABLE npx
@@ -111,6 +137,10 @@ function(cppbessot_check_dependencies)
"Install a Java runtime (OpenAPI generator uses Java).")
_cppbessot_require_program(CPPBESSOT_GIT_EXECUTABLE git
"Install Git and ensure it is available in PATH.")
_cppbessot_require_program(CPPBESSOT_SQLITE3_EXECUTABLE sqlite3
"Install the SQLite CLI so live SQLite DB actions can apply SQL files.")
_cppbessot_require_program(CPPBESSOT_PSQL_EXECUTABLE psql
"Install the PostgreSQL client CLI so live PostgreSQL DB actions can run.")
_cppbessot_require_npm_package("${CPPBESSOT_NPM_EXECUTABLE}" "@openapitools/openapi-generator-cli")
_cppbessot_require_npx_package_executable("${CPPBESSOT_NPX_EXECUTABLE}" "@openapitools/openapi-generator-cli")
@@ -187,17 +217,6 @@ function(cppbessot_check_dependencies)
"PostgreSQL client library was not found. On Ubuntu/Debian install package `libpq-dev`.")
endif()
set(CPPBESSOT_ODB_EXECUTABLE "${CPPBESSOT_ODB_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_NPX_EXECUTABLE "${CPPBESSOT_NPX_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_NPM_EXECUTABLE "${CPPBESSOT_NPM_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_JAVA_EXECUTABLE "${CPPBESSOT_JAVA_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_GIT_EXECUTABLE "${CPPBESSOT_GIT_EXECUTABLE}" PARENT_SCOPE)
set(CPPBESSOT_ODB_RUNTIME_LIB "${CPPBESSOT_ODB_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_ODB_SQLITE_RUNTIME_LIB "${CPPBESSOT_ODB_SQLITE_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_ODB_PGSQL_RUNTIME_LIB "${CPPBESSOT_ODB_PGSQL_RUNTIME_LIB}" PARENT_SCOPE)
set(CPPBESSOT_SQLITE_INCLUDE_DIR "${CPPBESSOT_SQLITE_INCLUDE_DIR}" PARENT_SCOPE)
set(CPPBESSOT_PGSQL_INCLUDE_DIR "${CPPBESSOT_PGSQL_INCLUDE_DIR}" PARENT_SCOPE)
set(CPPBESSOT_SQLITE_CLIENT_LIB "${CPPBESSOT_SQLITE_CLIENT_LIB}" PARENT_SCOPE)
set(CPPBESSOT_PGSQL_CLIENT_LIB "${CPPBESSOT_PGSQL_CLIENT_LIB}" PARENT_SCOPE)
set(CPPBESSOT_OPENAPI_ZOD_AVAILABLE TRUE PARENT_SCOPE)
set_property(GLOBAL PROPERTY CPPBESSOT_DEPENDENCIES_CHECKED TRUE)
_cppbessot_publish_dependency_outputs()
endfunction()
@@ -0,0 +1,48 @@
cmake_minimum_required(VERSION 3.16)
function(cppbessot_db_action_get_hook_path out_var migration_dir hook_name)
set(_hook_path "${migration_dir}/${hook_name}")
if(EXISTS "${_hook_path}")
set(${out_var} "${_hook_path}" PARENT_SCOPE)
else()
set(${out_var} "" PARENT_SCOPE)
endif()
endfunction()
function(cppbessot_db_action_run_hook
hook_path
db_target
backend
migration_dir
migrate_with
schema_dir_to_generate
createfrom_schema_dir
sqlite_path
pgsql_connstr)
if("${hook_path}" STREQUAL "")
return()
endif()
set(_env_args
"CPPBESSOT_DB_TARGET=${db_target}"
"CPPBESSOT_DB_BACKEND=${backend}"
"CPPBESSOT_DB_MIGRATION_DIR=${migration_dir}"
"CPPBESSOT_DB_MIGRATE_WITH=${migrate_with}"
"CPPBESSOT_DB_SCHEMA_DIR_TO_GENERATE=${schema_dir_to_generate}"
"CPPBESSOT_DB_CREATEFROM_SCHEMA_DIR=${createfrom_schema_dir}"
"CPPBESSOT_DB_SQLITE_PATH=${sqlite_path}"
"CPPBESSOT_DB_PGSQL_CONNSTR=${pgsql_connstr}")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E env ${_env_args} sh "${hook_path}"
WORKING_DIRECTORY "${migration_dir}"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR
"Backfill hook failed: ${hook_path}\n${_stdout}\n${_stderr}")
endif()
endfunction()
@@ -0,0 +1,77 @@
cmake_minimum_required(VERSION 3.16)
function(cppbessot_db_action_target_exists out_var backend sqlite_path pgsql_connstr)
if("${backend}" STREQUAL "sqlite")
if(EXISTS "${sqlite_path}")
set(${out_var} TRUE PARENT_SCOPE)
else()
set(${out_var} FALSE PARENT_SCOPE)
endif()
return()
endif()
cppbessot_db_action_find_program_or_fail(_psql psql
"PostgreSQL live actions require `psql` to be available in PATH.")
execute_process(
COMMAND "${_psql}" "${pgsql_connstr}" -v ON_ERROR_STOP=1 -c "SELECT 1;"
RESULT_VARIABLE _result
OUTPUT_QUIET
ERROR_QUIET
)
if(_result EQUAL 0)
set(${out_var} TRUE PARENT_SCOPE)
else()
set(${out_var} FALSE PARENT_SCOPE)
endif()
endfunction()
function(cppbessot_db_action_get_clone_command out_var backend)
if("${backend}" STREQUAL "sqlite")
set(_command "${CPPBESSOT_DB_SQLITE_CLONE_PROD_TO_PRODDEV_COMMAND}")
else()
set(_command "${CPPBESSOT_DB_PGSQL_CLONE_PROD_TO_PRODDEV_COMMAND}")
endif()
set(${out_var} "${_command}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_invoke_clone_hook backend)
cppbessot_db_action_get_clone_command(_clone_command "${backend}")
if("${_clone_command}" STREQUAL "")
message(FATAL_ERROR
"No clone command is configured for backend `${backend}` while preparing proddev.")
endif()
execute_process(
COMMAND sh -c "${_clone_command}"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR
"Proddev clone command failed for backend `${backend}`.\n${_stdout}\n${_stderr}")
endif()
endfunction()
function(cppbessot_db_action_prepare_proddev target backend use_stale sqlite_path pgsql_connstr)
if(NOT "${target}" STREQUAL "proddev")
return()
endif()
if(use_stale)
cppbessot_db_action_target_exists(_exists "${backend}" "${sqlite_path}" "${pgsql_connstr}")
if(NOT _exists)
message(FATAL_ERROR
"DB_MIGRATE_PRODDEV_USE_STALE is ON, but no current stale proddev target exists.")
endif()
return()
endif()
cppbessot_db_action_invoke_clone_hook("${backend}")
cppbessot_db_action_target_exists(_exists "${backend}" "${sqlite_path}" "${pgsql_connstr}")
if(NOT _exists)
message(FATAL_ERROR
"Proddev clone command completed, but the proddev target still does not appear to exist.")
endif()
endfunction()
+120
View File
@@ -0,0 +1,120 @@
cmake_minimum_required(VERSION 3.16)
include("${CMAKE_CURRENT_LIST_DIR}/../dbActionShared.cmake")
function(cppbessot_db_action_require_var var_name)
if(NOT DEFINED ${var_name} OR "${${var_name}}" STREQUAL "")
message(FATAL_ERROR "Required variable `${var_name}` is missing.")
endif()
endfunction()
function(cppbessot_db_action_resolve_project_path out_var input_path)
cppbessot_db_action_require_var(CPPBESSOT_PROJECT_SOURCE_DIR)
if(IS_ABSOLUTE "${input_path}")
set(_resolved "${input_path}")
else()
set(_resolved "${CPPBESSOT_PROJECT_SOURCE_DIR}/${input_path}")
endif()
get_filename_component(_resolved "${_resolved}" ABSOLUTE)
set(${out_var} "${_resolved}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_validate_schema_dir_name schema_dir)
_cppbessot_db_action_validate_basename(
"${schema_dir}"
"Schema directory name"
"CPPBESSOT_WORKDIR")
endfunction()
function(cppbessot_db_action_get_schema_dir_path out_var schema_dir)
cppbessot_db_action_validate_schema_dir_name("${schema_dir}")
cppbessot_db_action_resolve_project_path(_workdir "${CPPBESSOT_WORKDIR}")
set(${out_var} "${_workdir}/${schema_dir}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_assert_schema_dir_ready schema_dir)
cppbessot_db_action_get_schema_dir_path(_schema_dir_path "${schema_dir}")
if(NOT IS_DIRECTORY "${_schema_dir_path}")
message(FATAL_ERROR "Schema directory does not exist: ${_schema_dir_path}")
endif()
set(_openapi_file "${_schema_dir_path}/openapi/openapi.yaml")
if(NOT EXISTS "${_openapi_file}")
message(FATAL_ERROR "OpenAPI file does not exist: ${_openapi_file}")
endif()
endfunction()
function(cppbessot_db_action_validate_migration_dir_name migration_dir)
_cppbessot_db_action_validate_basename(
"${migration_dir}"
"Migration directory name"
"CPPBESSOT_WORKDIR/migrations")
endfunction()
function(cppbessot_db_action_get_migration_dir_path out_var migration_dir)
cppbessot_db_action_validate_migration_dir_name("${migration_dir}")
cppbessot_db_action_resolve_project_path(_workdir "${CPPBESSOT_WORKDIR}")
set(${out_var} "${_workdir}/migrations/${migration_dir}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_assert_migration_dir_exists migration_dir)
cppbessot_db_action_get_migration_dir_path(_migration_dir_path "${migration_dir}")
if(NOT IS_DIRECTORY "${_migration_dir_path}")
message(FATAL_ERROR "Migration directory does not exist: ${_migration_dir_path}")
endif()
endfunction()
function(cppbessot_db_action_validate_db_target db_target)
_cppbessot_db_action_validate_db_target_impl("${db_target}")
endfunction()
function(cppbessot_db_action_backend_subdir out_var backend)
if("${backend}" STREQUAL "sqlite")
set(${out_var} "sqlite" PARENT_SCOPE)
return()
endif()
if("${backend}" STREQUAL "postgre")
set(${out_var} "postgre" PARENT_SCOPE)
return()
endif()
message(FATAL_ERROR "Unsupported backend `${backend}`.")
endfunction()
function(cppbessot_db_action_collect_nonempty_sql_files out_var sql_dir)
if(NOT IS_DIRECTORY "${sql_dir}")
set(${out_var} "" PARENT_SCOPE)
return()
endif()
file(GLOB _candidate_files "${sql_dir}/*.sql")
list(SORT _candidate_files)
set(_sql_files)
foreach(_candidate IN LISTS _candidate_files)
file(READ "${_candidate}" _contents)
string(STRIP "${_contents}" _trimmed)
if(NOT "${_trimmed}" STREQUAL "")
list(APPEND _sql_files "${_candidate}")
endif()
endforeach()
set(${out_var} "${_sql_files}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_require_nonempty_sql_dir sql_dir failure_prefix)
cppbessot_db_action_collect_nonempty_sql_files(_sql_files "${sql_dir}")
if(NOT _sql_files)
message(FATAL_ERROR "${failure_prefix}: no non-empty SQL files found under ${sql_dir}")
endif()
endfunction()
function(cppbessot_db_action_find_program_or_fail out_var program_name hint)
find_program(_program "${program_name}")
if(NOT _program)
message(FATAL_ERROR "Missing required program `${program_name}`. ${hint}")
endif()
set(${out_var} "${_program}" PARENT_SCOPE)
endfunction()
@@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.16)
function(cppbessot_db_action_reset_sqlite_db sqlite_path)
if(EXISTS "${sqlite_path}")
file(REMOVE "${sqlite_path}")
endif()
get_filename_component(_sqlite_parent "${sqlite_path}" DIRECTORY)
if(NOT "${_sqlite_parent}" STREQUAL "")
file(MAKE_DIRECTORY "${_sqlite_parent}")
endif()
endfunction()
function(cppbessot_db_action_apply_sqlite_files sqlite_path)
set(_sql_files "${ARGN}")
if(NOT _sql_files)
return()
endif()
cppbessot_db_action_find_program_or_fail(_sqlite3 sqlite3
"SQLite live actions require the `sqlite3` CLI to be available in PATH.")
foreach(_sql_file IN LISTS _sql_files)
string(REPLACE "\"" "\\\"" _sqlite_read_file "${_sql_file}")
execute_process(
COMMAND "${_sqlite3}" "${sqlite_path}" ".read \"${_sqlite_read_file}\""
RESULT_VARIABLE _result
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR
"SQLite SQL apply failed for `${_sql_file}` against `${sqlite_path}`.\n${_stdout}\n${_stderr}")
endif()
endforeach()
endfunction()
function(cppbessot_db_action_reset_pgsql_schema pgsql_connstr)
cppbessot_db_action_find_program_or_fail(_psql psql
"PostgreSQL live actions require `psql` to be available in PATH.")
execute_process(
COMMAND "${_psql}" "${pgsql_connstr}" -v ON_ERROR_STOP=1
-c "DROP SCHEMA IF EXISTS public CASCADE; CREATE SCHEMA public;"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR
"PostgreSQL schema reset failed.\n${_stdout}\n${_stderr}")
endif()
endfunction()
function(cppbessot_db_action_apply_pgsql_files pgsql_connstr)
set(_sql_files "${ARGN}")
if(NOT _sql_files)
return()
endif()
cppbessot_db_action_find_program_or_fail(_psql psql
"PostgreSQL live actions require `psql` to be available in PATH.")
foreach(_sql_file IN LISTS _sql_files)
execute_process(
COMMAND "${_psql}" "${pgsql_connstr}" -v ON_ERROR_STOP=1 -f "${_sql_file}"
RESULT_VARIABLE _result
OUTPUT_VARIABLE _stdout
ERROR_VARIABLE _stderr
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR
"PostgreSQL SQL apply failed for `${_sql_file}`.\n${_stdout}\n${_stderr}")
endif()
endforeach()
endfunction()
@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.16)
function(cppbessot_db_action_target_upper out_var db_target)
string(TOUPPER "${db_target}" _upper)
set(${out_var} "${_upper}" PARENT_SCOPE)
endfunction()
function(cppbessot_db_action_resolve_backend_for_target
out_backend
out_sqlite_path
out_pgsql_connstr
db_target)
cppbessot_db_action_validate_db_target("${db_target}")
cppbessot_db_action_target_upper(_target_upper "${db_target}")
set(_sqlite_var "CPPBESSOT_DB_SQLITE_${_target_upper}_PATH")
set(_pgsql_var "CPPBESSOT_DB_PGSQL_${_target_upper}_CONNSTR")
set(_has_sqlite FALSE)
set(_has_pgsql FALSE)
if(DEFINED ${_sqlite_var} AND NOT "${${_sqlite_var}}" STREQUAL "")
set(_has_sqlite TRUE)
endif()
if(DEFINED ${_pgsql_var} AND NOT "${${_pgsql_var}}" STREQUAL "")
set(_has_pgsql TRUE)
endif()
if(_has_sqlite AND _has_pgsql)
message(FATAL_ERROR
"DB target `${db_target}` is ambiguous: both `${_sqlite_var}` and `${_pgsql_var}` are set.")
endif()
if(NOT _has_sqlite AND NOT _has_pgsql)
message(FATAL_ERROR
"DB target `${db_target}` is not mapped: set exactly one of `${_sqlite_var}` or `${_pgsql_var}`.")
endif()
if(_has_sqlite)
set(${out_backend} "sqlite" PARENT_SCOPE)
set(${out_sqlite_path} "${${_sqlite_var}}" PARENT_SCOPE)
set(${out_pgsql_connstr} "" PARENT_SCOPE)
return()
endif()
set(${out_backend} "postgre" PARENT_SCOPE)
set(${out_sqlite_path} "" PARENT_SCOPE)
set(${out_pgsql_connstr} "${${_pgsql_var}}" PARENT_SCOPE)
endfunction()
+38
View File
@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.16)
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionCommon.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionTargetResolution.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionSqlApply.cmake")
cppbessot_db_action_require_var(CPPBESSOT_PROJECT_SOURCE_DIR)
cppbessot_db_action_require_var(CPPBESSOT_WORKDIR)
cppbessot_db_action_require_var(DB_CREATEFROM_SCHEMA_DIR)
cppbessot_db_action_require_var(DB_TARGET)
cppbessot_db_action_validate_db_target("${DB_TARGET}")
if("${DB_TARGET}" STREQUAL "proddev")
message(FATAL_ERROR "db_createfrom does not support DB_TARGET=proddev.")
endif()
cppbessot_db_action_assert_schema_dir_ready("${DB_CREATEFROM_SCHEMA_DIR}")
cppbessot_db_action_resolve_backend_for_target(
_backend
_sqlite_path
_pgsql_connstr
"${DB_TARGET}")
cppbessot_db_action_backend_subdir(_backend_subdir "${_backend}")
cppbessot_db_action_get_schema_dir_path(_schema_dir "${DB_CREATEFROM_SCHEMA_DIR}")
set(_ddl_dir "${_schema_dir}/generated-sql-ddl/${_backend_subdir}")
cppbessot_db_action_require_nonempty_sql_dir(
"${_ddl_dir}"
"db_createfrom cannot continue")
cppbessot_db_action_collect_nonempty_sql_files(_sql_files "${_ddl_dir}")
if("${_backend}" STREQUAL "sqlite")
cppbessot_db_action_reset_sqlite_db("${_sqlite_path}")
cppbessot_db_action_apply_sqlite_files("${_sqlite_path}" ${_sql_files})
return()
endif()
cppbessot_db_action_reset_pgsql_schema("${_pgsql_connstr}")
cppbessot_db_action_apply_pgsql_files("${_pgsql_connstr}" ${_sql_files})
+64
View File
@@ -0,0 +1,64 @@
cmake_minimum_required(VERSION 3.16)
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionCommon.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionTargetResolution.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionBackfill.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionSqlApply.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/cppbessotDbActionClone.cmake")
cppbessot_db_action_require_var(CPPBESSOT_PROJECT_SOURCE_DIR)
cppbessot_db_action_require_var(CPPBESSOT_WORKDIR)
cppbessot_db_action_require_var(DB_MIGRATE_WITH)
cppbessot_db_action_require_var(DB_TARGET)
cppbessot_db_action_require_var(DB_SCHEMA_DIR_TO_GENERATE)
cppbessot_db_action_require_var(DB_CREATEFROM_SCHEMA_DIR)
cppbessot_db_action_validate_db_target("${DB_TARGET}")
cppbessot_db_action_assert_migration_dir_exists("${DB_MIGRATE_WITH}")
cppbessot_db_action_resolve_backend_for_target(
_backend
_sqlite_path
_pgsql_connstr
"${DB_TARGET}")
cppbessot_db_action_prepare_proddev(
"${DB_TARGET}"
"${_backend}"
"${DB_MIGRATE_PRODDEV_USE_STALE}"
"${_sqlite_path}"
"${_pgsql_connstr}")
cppbessot_db_action_backend_subdir(_backend_subdir "${_backend}")
cppbessot_db_action_get_migration_dir_path(_migration_dir "${DB_MIGRATE_WITH}")
set(_sql_dir "${_migration_dir}/${_backend_subdir}")
cppbessot_db_action_collect_nonempty_sql_files(_sql_files "${_sql_dir}")
cppbessot_db_action_get_hook_path(_pre_hook "${_migration_dir}" "pre-structural-backfill.sh")
cppbessot_db_action_get_hook_path(_post_hook "${_migration_dir}" "post-structural-backfill.sh")
cppbessot_db_action_run_hook(
"${_pre_hook}"
"${DB_TARGET}"
"${_backend}"
"${_migration_dir}"
"${DB_MIGRATE_WITH}"
"${DB_SCHEMA_DIR_TO_GENERATE}"
"${DB_CREATEFROM_SCHEMA_DIR}"
"${_sqlite_path}"
"${_pgsql_connstr}")
if(_sql_files)
if("${_backend}" STREQUAL "sqlite")
cppbessot_db_action_apply_sqlite_files("${_sqlite_path}" ${_sql_files})
else()
cppbessot_db_action_apply_pgsql_files("${_pgsql_connstr}" ${_sql_files})
endif()
endif()
cppbessot_db_action_run_hook(
"${_post_hook}"
"${DB_TARGET}"
"${_backend}"
"${_migration_dir}"
"${DB_MIGRATE_WITH}"
"${DB_SCHEMA_DIR_TO_GENERATE}"
"${DB_CREATEFROM_SCHEMA_DIR}"
"${_sqlite_path}"
"${_pgsql_connstr}")