mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Introduce aether-data-schema and driver-specific schema generation for Postgres, MySQL, and SQLite. Split data backends, lifecycle, repositories, and gateway runtime integration across database drivers. Verified with cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace.
248 lines
6.8 KiB
Bash
248 lines
6.8 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
schema_root="${root}/schema"
|
|
driver_schema_root="${schema_root}/drivers"
|
|
bootstrap_schema_root="${schema_root}/bootstrap/postgres"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage:
|
|
bash crates/aether-data/schema/compose_schema.sh split
|
|
bash crates/aether-data/schema/compose_schema.sh generate
|
|
bash crates/aether-data/schema/compose_schema.sh compose
|
|
bash crates/aether-data/schema/compose_schema.sh check
|
|
|
|
split Regenerate schema source fragments from the current executable SQL.
|
|
generate Generate SQL fragments from logical schema definitions.
|
|
compose Rebuild executable SQL from schema source manifests.
|
|
check Verify generated SQL is current, bootstrap sources are readable, and executable SQL matches manifests.
|
|
USAGE
|
|
}
|
|
|
|
generate_logical_schema() {
|
|
(cd "${root}/../.." && cargo run -q -p aether-data-schema --bin aether-schema -- generate)
|
|
}
|
|
|
|
check_logical_generated() {
|
|
local args=()
|
|
local path
|
|
args+=(--require-tables-from "${root}/migrations/postgres/20260403000000_baseline.sql")
|
|
for path in "${root}/migrations/mysql/"*.sql "${root}/migrations/sqlite/"*.sql; do
|
|
[[ -f "${path}" ]] || continue
|
|
args+=(--require-tables-from "${path}")
|
|
done
|
|
(cd "${root}/../.." && cargo run -q -p aether-data-schema --bin aether-schema -- check "${args[@]}")
|
|
printf 'ok generated logical schema\n'
|
|
}
|
|
|
|
manifest_path() {
|
|
local target="$1"
|
|
printf '%s/manifest.txt' "$(source_dir_path "${target}")"
|
|
}
|
|
|
|
source_dir_path() {
|
|
local target="$1"
|
|
printf '%s/%s' "${driver_schema_root}" "${target}"
|
|
}
|
|
|
|
output_path() {
|
|
local target="$1"
|
|
case "${target}" in
|
|
postgres/baseline)
|
|
printf '%s/migrations/postgres/20260403000000_baseline.sql' "${root}"
|
|
;;
|
|
mysql/baseline)
|
|
printf '%s/migrations/mysql/20260403000000_baseline.sql' "${root}"
|
|
;;
|
|
sqlite/baseline)
|
|
printf '%s/migrations/sqlite/20260403000000_baseline.sql' "${root}"
|
|
;;
|
|
*)
|
|
printf 'unknown schema target: %s\n' "${target}" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
}
|
|
|
|
write_manifest() {
|
|
local target="$1"
|
|
shift
|
|
local manifest
|
|
manifest="$(manifest_path "${target}")"
|
|
mkdir -p "$(dirname "${manifest}")"
|
|
: > "${manifest}"
|
|
local part
|
|
for part in "$@"; do
|
|
printf '%s\n' "${part}" >> "${manifest}"
|
|
done
|
|
}
|
|
|
|
append_manifest() {
|
|
local target="$1"
|
|
shift
|
|
local manifest
|
|
manifest="$(manifest_path "${target}")"
|
|
local part
|
|
for part in "$@"; do
|
|
printf '%s\n' "${part}" >> "${manifest}"
|
|
done
|
|
}
|
|
|
|
split_fragment() {
|
|
local source="$1"
|
|
local target="$2"
|
|
local filename="$3"
|
|
local start_line="$4"
|
|
local end_line="$5"
|
|
local output
|
|
output="$(source_dir_path "${target}")/${filename}"
|
|
|
|
mkdir -p "$(dirname "${output}")"
|
|
if [[ "${end_line}" == "EOF" ]]; then
|
|
sed -n "${start_line},\$p" "${source}" > "${output}"
|
|
else
|
|
sed -n "${start_line},${end_line}p" "${source}" > "${output}"
|
|
fi
|
|
printf '%s: lines %s-%s\n' "${output#${root}/}" "${start_line}" "${end_line}"
|
|
}
|
|
|
|
compose_target_to_stdout() {
|
|
local target="$1"
|
|
local manifest
|
|
manifest="$(manifest_path "${target}")"
|
|
if [[ ! -f "${manifest}" ]]; then
|
|
printf 'missing schema manifest: %s\n' "${manifest}" >&2
|
|
exit 2
|
|
fi
|
|
|
|
local part
|
|
while IFS= read -r part || [[ -n "${part}" ]]; do
|
|
[[ -z "${part}" || "${part}" == \#* ]] && continue
|
|
cat "$(source_dir_path "${target}")/${part}"
|
|
done < "${manifest}"
|
|
}
|
|
|
|
compose_target() {
|
|
local target="$1"
|
|
local output
|
|
output="$(output_path "${target}")"
|
|
compose_target_to_stdout "${target}" > "${output}"
|
|
printf 'composed %s from %s\n' "${output#${root}/}" "$(manifest_path "${target}")"
|
|
}
|
|
|
|
check_target() {
|
|
local target="$1"
|
|
local output tmp
|
|
output="$(output_path "${target}")"
|
|
tmp="$(mktemp)"
|
|
compose_target_to_stdout "${target}" > "${tmp}"
|
|
if ! diff -u "${output}" "${tmp}"; then
|
|
rm -f "${tmp}"
|
|
printf 'schema source does not match %s\n' "${output#${root}/}" >&2
|
|
exit 1
|
|
fi
|
|
rm -f "${tmp}"
|
|
printf 'ok %s\n' "${target}"
|
|
}
|
|
|
|
split_postgres_baseline() {
|
|
local source="${root}/migrations/postgres/20260403000000_baseline.sql"
|
|
local target="postgres/baseline"
|
|
write_manifest "${target}" \
|
|
"001_types_and_tables.sql" \
|
|
"002_defaults.sql" \
|
|
"003_constraints.sql" \
|
|
"004_indexes.sql" \
|
|
"005_foreign_keys.sql" \
|
|
"006_footer.sql"
|
|
split_fragment "${source}" "${target}" 001_types_and_tables.sql 1 1349
|
|
split_fragment "${source}" "${target}" 002_defaults.sql 1350 1365
|
|
split_fragment "${source}" "${target}" 003_constraints.sql 1366 2490
|
|
split_fragment "${source}" "${target}" 004_indexes.sql 2491 3730
|
|
split_fragment "${source}" "${target}" 005_foreign_keys.sql 3731 4582
|
|
split_fragment "${source}" "${target}" 006_footer.sql 4583 EOF
|
|
}
|
|
|
|
check_bootstrap_sources() {
|
|
local manifest="${bootstrap_schema_root}/manifest.txt"
|
|
local tmp
|
|
tmp="$(mktemp)"
|
|
|
|
local part
|
|
while IFS= read -r part || [[ -n "${part}" ]]; do
|
|
[[ -z "${part}" || "${part}" == \#* ]] && continue
|
|
cat "${bootstrap_schema_root}/${part}" >> "${tmp}"
|
|
done < "${manifest}"
|
|
|
|
rm -f "${tmp}"
|
|
printf 'ok bootstrap/postgres source\n'
|
|
}
|
|
|
|
split_linear_baseline() {
|
|
local driver="$1"
|
|
local source="${root}/migrations/${driver}/20260403000000_baseline.sql"
|
|
local target="${driver}/baseline"
|
|
write_manifest "${target}" \
|
|
"001_identity.sql" \
|
|
"002_provider_catalog.sql" \
|
|
"003_auth_config.sql" \
|
|
"004_proxy_nodes.sql" \
|
|
"005_wallet_billing.sql" \
|
|
"006_usage.sql"
|
|
|
|
if [[ "${driver}" == "mysql" ]]; then
|
|
split_fragment "${source}" "${target}" 001_identity.sql 1 121
|
|
split_fragment "${source}" "${target}" 002_provider_catalog.sql 122 417
|
|
split_fragment "${source}" "${target}" 003_auth_config.sql 418 487
|
|
split_fragment "${source}" "${target}" 004_proxy_nodes.sql 488 527
|
|
split_fragment "${source}" "${target}" 005_wallet_billing.sql 528 711
|
|
split_fragment "${source}" "${target}" 006_usage.sql 712 EOF
|
|
else
|
|
split_fragment "${source}" "${target}" 001_identity.sql 1 117
|
|
split_fragment "${source}" "${target}" 002_provider_catalog.sql 118 417
|
|
split_fragment "${source}" "${target}" 003_auth_config.sql 418 485
|
|
split_fragment "${source}" "${target}" 004_proxy_nodes.sql 486 525
|
|
split_fragment "${source}" "${target}" 005_wallet_billing.sql 526 728
|
|
split_fragment "${source}" "${target}" 006_usage.sql 729 EOF
|
|
fi
|
|
}
|
|
|
|
targets=(
|
|
"postgres/baseline"
|
|
"mysql/baseline"
|
|
"sqlite/baseline"
|
|
)
|
|
|
|
cmd="${1:-}"
|
|
case "${cmd}" in
|
|
split)
|
|
split_postgres_baseline
|
|
split_linear_baseline mysql
|
|
split_linear_baseline sqlite
|
|
;;
|
|
generate)
|
|
generate_logical_schema
|
|
;;
|
|
compose)
|
|
for target in "${targets[@]}"; do
|
|
compose_target "${target}"
|
|
done
|
|
;;
|
|
check)
|
|
check_logical_generated
|
|
check_bootstrap_sources
|
|
for target in "${targets[@]}"; do
|
|
check_target "${target}"
|
|
done
|
|
;;
|
|
-h|--help|help|"")
|
|
usage
|
|
;;
|
|
*)
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|