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
@@ -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}")