1 parent
2c98b8f925
commit
e4aa787e06
27 files changed
+179
-110
No files matched your search
+2
-35
@@ -20,8 +20,6 @@ const SQLITE_SCHEMA: &str = include_str!("../../migrations/sqlite/schema.sql");
|
||||
const MYSQL_SCHEMA: &str = include_str!("../../migrations/mysql/schema.sql");
|
||||
const PGSQL_SCHEMA: &str = include_str!("../../migrations/pgsql/schema.sql");
|
||||
|
||||
// The squashed legacy baseline is V046. Runtime migrations start at V047 and
|
||||
// are stored as real files for every supported SQL engine.
|
||||
const SQLITE_MIGRATIONS: &[(u32, &str)] = &[(
|
||||
47,
|
||||
include_str!("../../migrations/sqlite/V047__blob_keys_and_search_outbox.sql"),
|
||||
@@ -65,7 +63,6 @@ const TENANT_TABLES: &[&str] = &[
|
||||
"user_meta",
|
||||
];
|
||||
|
||||
// Parent tables precede children so legacy SQLite data can be copied with foreign keys enabled.
|
||||
const IMPORT_TABLES: &[&str] = &[
|
||||
"calendar_events",
|
||||
"calendar_settings",
|
||||
@@ -229,12 +226,6 @@ pub async fn configure(config: &AppConfig) -> Result<(), String> {
|
||||
conn.execute_batch(&global_schema(SQLITE_SCHEMA)?)
|
||||
.map_err(|e| format!("SQLite global schema initialization failed: {e}"))?;
|
||||
|
||||
// Unit tests create many independent temporary data directories in one
|
||||
// process. Pinning the first SQLite path in the process-wide OnceLock
|
||||
// makes later tests reuse a TempDir that may already have been deleted,
|
||||
// causing a cascade of "unable to open database file" failures.
|
||||
// Initialize the requested test database, but let open_user_db() resolve
|
||||
// each test's own data_dir instead of publishing this path globally.
|
||||
#[cfg(test)]
|
||||
{
|
||||
return Ok(());
|
||||
@@ -287,9 +278,6 @@ pub async fn configure(config: &AppConfig) -> Result<(), String> {
|
||||
let schema = global_schema(PGSQL_SCHEMA)?;
|
||||
let init_pool = pool.clone();
|
||||
runtime_wait(&runtime, async move {
|
||||
// PostgreSQL emits NOTICE for every CREATE ... IF NOT EXISTS that
|
||||
// already exists. Keep expected idempotent startup DDL quiet without
|
||||
// changing application-wide logging or server settings.
|
||||
let mut tx = init_pool
|
||||
.begin()
|
||||
.await
|
||||
@@ -298,11 +286,6 @@ pub async fn configure(config: &AppConfig) -> Result<(), String> {
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(|e| format!("failed to quiet PostgreSQL schema notices: {e}"))?;
|
||||
// `raw_sql(...).execute(&mut PgConnection)` can trigger SQLx's
|
||||
// "Executor is not general enough" lifetime error when this
|
||||
// future is spawned onto the dedicated database runtime. Execute
|
||||
// the unprepared multi-statement DDL directly through `Executor`
|
||||
// instead; this is SQLx's supported path for raw DDL batches.
|
||||
(&mut *tx)
|
||||
.execute(schema.as_str())
|
||||
.await
|
||||
@@ -460,7 +443,6 @@ pub trait ToDbValue {
|
||||
}
|
||||
}
|
||||
|
||||
// Kept explicit rather than clever: the macro above intentionally stays simple for rustfmt/parser compatibility.
|
||||
impl ToDbValue for i64 {
|
||||
fn to_db_value(&self) -> DbValue {
|
||||
DbValue::I64(Some(*self))
|
||||
@@ -601,10 +583,6 @@ impl IntoDbParams for [(); 0] {
|
||||
}
|
||||
}
|
||||
|
||||
// Do not use a const-generic array implementation here. For an empty array (`[]`)
|
||||
// Rust cannot infer the element type and sees both `[(); 0]` and `[T; 0]` as valid
|
||||
// `IntoDbParams` candidates. Implement only non-empty array lengths explicitly so
|
||||
// legacy/rusqlite-style `[]` call sites remain unambiguous.
|
||||
macro_rules! impl_into_db_params_array {
|
||||
($($n:expr),+ $(,)?) => {
|
||||
$(
|
||||
@@ -1457,8 +1435,6 @@ fn adapt_sql_params(
|
||||
return (sql, params);
|
||||
}
|
||||
|
||||
// Dynamic query builders in the application use SQLite-style ?N placeholders.
|
||||
// Normalize them here so the same higher-level logic can target all engines.
|
||||
let chars: Vec<char> = sql.chars().collect();
|
||||
let mut output = String::with_capacity(sql.len() + 16);
|
||||
let mut reordered = Vec::new();
|
||||
@@ -1522,8 +1498,6 @@ fn adapt_sql_params(
|
||||
|
||||
sql = output;
|
||||
if backend == DatabaseBackend::Mysql && !reordered.is_empty() {
|
||||
// If numbered placeholders were expanded, bind in occurrence order.
|
||||
// Plain MySQL catalog queries already use '?' and are handled the same way.
|
||||
return (adapt_dialect_sql(backend, sql), reordered);
|
||||
}
|
||||
(adapt_dialect_sql(backend, sql), params)
|
||||
@@ -1855,9 +1829,6 @@ fn tenant_prefix(user_hash: &str) -> Result<String, String> {
|
||||
return Err("empty user hash for database isolation".to_string());
|
||||
}
|
||||
|
||||
// Production user hashes are SHA-256 hex strings. Tests and legacy callers may
|
||||
// use symbolic identifiers; hash those first so table prefixes remain safe,
|
||||
// deterministic and restricted to ASCII hex without weakening isolation.
|
||||
let normalized = if user_hash.len() >= 24 && user_hash.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
user_hash.to_ascii_lowercase()
|
||||
} else {
|
||||
@@ -2060,8 +2031,6 @@ fn ensure_server_tenant(
|
||||
let tenant = tenant_schema(MYSQL_SCHEMA, &prefix)?;
|
||||
let legacy_path = legacy_path.clone();
|
||||
runtime_wait(runtime, async move {
|
||||
// Serialize first-time provisioning per account across cluster nodes.
|
||||
// MySQL named locks are session-scoped and are released automatically if the connection dies.
|
||||
let lock_name = format!("rustbox:{prefix}");
|
||||
let mut lock_conn = pool
|
||||
.acquire()
|
||||
@@ -2210,10 +2179,8 @@ fn ensure_server_tenant(
|
||||
ConfiguredDatabase::Sqlite { .. } => false,
|
||||
};
|
||||
|
||||
if imported_legacy {
|
||||
if let Some(path) = legacy_path.as_ref() {
|
||||
backup_legacy_sqlite(path);
|
||||
}
|
||||
if imported_legacy && let Some(path) = legacy_path.as_ref() {
|
||||
backup_legacy_sqlite(path);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user