refactor(data): remove MySQL and SQLite support

Use PostgreSQL as the only database backend across runtime, schema tooling, installation, Compose, and CI. Update regression tests and reject removed drivers explicitly.
This commit is contained in:
elky
2026-09-07 00:09:42 +08:00
parent b5ed802277
commit 2281f2b754
298 changed files with 793 additions and 134804 deletions
@@ -137,11 +137,7 @@ fn postgres_provider_cleanup_preserves_usage_history() {
#[test]
fn provider_cleanup_keeps_common_backends_in_sync() {
for path in [
"crates/aether-data/adapters/postgres/src/provider_catalog.rs",
"crates/aether-data/adapters/mysql/src/provider_catalog.rs",
"crates/aether-data/adapters/sqlite/src/provider_catalog.rs",
] {
for path in ["crates/aether-data/adapters/postgres/src/provider_catalog.rs"] {
let source = read_workspace_file(path);
for required in [
"UPDATE user_preferences SET default_provider_id = NULL WHERE default_provider_id =",
@@ -36,7 +36,7 @@ pub(super) fn assert_no_sqlx_queries(root_relative_path: &str) {
let source = fs::read_to_string(&path).expect("source file should be readable");
let hits = patterns
.iter()
.filter(|pattern| source.contains(**pattern))
.filter(|pattern| source_contains_sql_pattern(&source, pattern))
.copied()
.collect::<Vec<_>>();
if hits.is_empty() {
@@ -54,6 +54,32 @@ pub(super) fn assert_no_sqlx_queries(root_relative_path: &str) {
);
}
fn source_contains_sql_pattern(source: &str, pattern: &str) -> bool {
if pattern == "PostgresPool" {
source
.split(|character: char| !character.is_ascii_alphanumeric() && character != '_')
.any(|identifier| identifier == pattern)
} else {
source.contains(pattern)
}
}
#[test]
fn sql_pool_scan_distinguishes_pool_types_from_repository_names() {
assert!(source_contains_sql_pattern(
"pool: PostgresPool",
"PostgresPool"
));
assert!(source_contains_sql_pattern(
"PostgresPool::connect(url)",
"PostgresPool"
));
assert!(!source_contains_sql_pattern(
"PostgresPoolMemberScoreRepository::new(pool)",
"PostgresPool"
));
}
pub(super) fn assert_no_sensitive_log_patterns(root_relative_path: &str, patterns: &[&str]) {
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join(root_relative_path);
let mut files = Vec::new();
File diff suppressed because it is too large Load Diff
@@ -40,58 +40,18 @@ fn pure_policy_crates_do_not_depend_on_runtime_adapters() {
#[test]
fn database_adapters_are_independent_driver_boundaries() {
let adapters = [
(
"crates/aether-data/adapters/postgres/Cargo.toml",
"features = [\"postgres\"",
["features = [\"mysql\"", "features = [\"sqlite\""],
),
(
"crates/aether-data/adapters/mysql/Cargo.toml",
"features = [\"mysql\"",
["features = [\"postgres\"", "features = [\"sqlite\""],
),
(
"crates/aether-data/adapters/sqlite/Cargo.toml",
"features = [\"sqlite\"",
["features = [\"postgres\"", "features = [\"mysql\""],
),
];
for (manifest_path, expected_driver, other_drivers) in adapters {
let manifest = read_workspace_file(manifest_path);
assert!(manifest.contains("aether-data-contracts.workspace = true"));
assert!(manifest.contains(expected_driver));
assert_manifest_excludes(
manifest_path,
&[other_drivers[0], other_drivers[1], "aether-gateway", "axum"],
);
}
let path = "crates/aether-data/adapters/postgres/Cargo.toml";
let manifest = read_workspace_file(path);
assert!(manifest.contains("aether-data-contracts.workspace = true"));
assert!(manifest.contains("features = [\"postgres\""));
assert_manifest_excludes(path, &["aether-gateway", "axum"]);
}
#[test]
fn data_facade_preserves_legacy_driver_paths_without_owning_driver_code() {
for (path, adapter) in [
(
"crates/aether-data/runtime/src/driver/postgres.rs",
"aether_data_postgres",
),
(
"crates/aether-data/runtime/src/driver/mysql.rs",
"aether_data_mysql",
),
(
"crates/aether-data/runtime/src/driver/sqlite.rs",
"aether_data_sqlite",
),
] {
let source = read_workspace_file(path);
assert!(
source.contains(&format!("pub use {adapter}::*;")),
"{path} should remain a thin compatibility facade"
);
assert!(!source.contains("sqlx::"));
}
let source = read_workspace_file("crates/aether-data/runtime/src/driver/postgres.rs");
assert!(source.contains("pub use aether_data_postgres::*;"));
assert!(!source.contains("sqlx::"));
}
#[test]
@@ -183,32 +143,16 @@ fn tunnel_binary_uses_shared_tunnel_boundary_without_gateway_runtime_dependency(
fn data_facade_defaults_to_postgres_and_gateway_selects_all_drivers_explicitly() {
let data_manifest = read_workspace_file("crates/aether-data/runtime/Cargo.toml");
assert!(data_manifest.contains("default = [\"postgres\"]"));
for dependency in [
"aether-data-postgres = { workspace = true, optional = true }",
"aether-data-mysql = { workspace = true, optional = true }",
"aether-data-sqlite = { workspace = true, optional = true }",
] {
assert!(
data_manifest.contains(dependency),
"aether-data should keep {dependency} optional"
);
}
assert!(
!data_manifest.contains("features = [\"postgres\", \"mysql\", \"sqlite\"\"]"),
"aether-data must not unconditionally enable every sqlx driver"
);
assert!(data_manifest.contains("aether-data-postgres = { workspace = true, optional = true }"));
assert!(data_manifest.contains("postgres = [\"dep:aether-data-postgres\", \"sqlx/postgres\"]"));
assert!(data_manifest.contains("all-drivers = [\"postgres\"]"));
let gateway_manifest = read_workspace_file("apps/aether-gateway/Cargo.toml");
assert!(gateway_manifest
.contains("aether-data = { workspace = true, features = [\"all-drivers\"] }"));
let data_lib = read_workspace_file("crates/aether-data/runtime/src/lib.rs");
for backend in ["PostgresBackend", "MysqlBackend", "SqliteBackend"] {
assert!(
data_lib.contains(&format!("pub use backend::{backend};")),
"aether-data should expose enabled backends symmetrically at its facade root"
);
}
assert!(data_lib.contains("pub use backend::PostgresBackend;"));
}
#[test]
@@ -219,58 +163,11 @@ fn data_query_helpers_belong_to_adapters_not_the_runtime_facade() {
"aether-data should not keep a direct query-helper dependency after SQL repositories move to adapters"
);
for adapter_manifest in [
"crates/aether-data/adapters/postgres/Cargo.toml",
"crates/aether-data/adapters/mysql/Cargo.toml",
"crates/aether-data/adapters/sqlite/Cargo.toml",
] {
let manifest = read_workspace_file(adapter_manifest);
assert!(
manifest.contains("aether-data-query.workspace = true"),
"{adapter_manifest} should own its query-helper dependency"
);
}
let manifest = read_workspace_file("crates/aether-data/adapters/postgres/Cargo.toml");
assert!(manifest.contains("aether-data-query.workspace = true"));
let query_helpers = read_workspace_file("crates/aether-data/query/src/lib.rs");
for dialect in ["Postgres", "MySql", "Sqlite"] {
assert!(
query_helpers.contains(dialect),
"aether-data-query should render the {dialect} dialect"
);
}
}
#[test]
fn sql_adapters_centralize_error_mapping_boilerplate() {
for (adapter, driver) in [
("aether-data-mysql", "mysql"),
("aether-data-sqlite", "sqlite"),
] {
let root = format!("crates/aether-data/adapters/{driver}/src");
let files = collect_workspace_rust_files(&root);
let trait_owners = files
.iter()
.filter(|path| {
std::fs::read_to_string(path)
.expect("adapter source should be readable")
.contains("trait SqlResultExt<T>")
})
.collect::<Vec<_>>();
assert_eq!(
trait_owners.len(),
1,
"{adapter} should have exactly one SqlResultExt owner, found: {trait_owners:?}"
);
assert_eq!(
trait_owners[0].file_name().and_then(|name| name.to_str()),
Some("error.rs"),
"{adapter} should keep SQL error mapping in src/error.rs"
);
let lib = read_workspace_file(&format!("crates/aether-data/adapters/{driver}/src/lib.rs"));
assert!(lib.contains("mod error;"));
}
assert!(query_helpers.contains("Postgres"));
}
#[test]