refactor: remove all dev.* and public.* schema hardcodes from runtime code

14 files updated to use schema::table_name() instead of hardcoded schema
prefixes. Only src/bin/release.rs intentionally retains dev.* references.
This commit is contained in:
Accusys
2026-05-14 14:40:14 +08:00
parent 261d134fee
commit 301a95e2bc
14 changed files with 184 additions and 139 deletions

View File

@@ -10,6 +10,7 @@ use sqlx::Row;
use std::path::PathBuf;
use crate::api::server::AppState;
use crate::core::db::schema;
use crate::core::db::PostgresDb;
pub fn identity_agent_routes() -> Router<AppState> {
@@ -204,7 +205,7 @@ async fn analyze_identity(
});
let _ = sqlx::query(
"INSERT INTO dev.identities (name, identity_type, source, metadata, status) VALUES ($1, 'people', 'auto', $2::jsonb, 'pending') ON CONFLICT DO NOTHING"
&format!("INSERT INTO {} (name, identity_type, source, metadata, status) VALUES ($1, 'people', 'auto', $2::jsonb, 'pending') ON CONFLICT DO NOTHING", schema::table_name("identities"))
)
.bind(&identity_name)
.bind(&metadata)
@@ -473,21 +474,21 @@ async fn suggest_clustering(
None => String::new(),
};
let fd_table = schema::table_name("face_detections");
let identities_table = schema::table_name("identities");
let query = format!(
r#"
SELECT trace_id, file_uuid, COUNT(*) as face_count
FROM dev.face_detections fd
WHERE fd.trace_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM dev.identities i
WHERE i.metadata->>'trace_id' = fd.trace_id::text
)
{}
GROUP BY trace_id, file_uuid
HAVING COUNT(*) >= $1
ORDER BY face_count DESC
"#,
file_filter
"SELECT trace_id, file_uuid, COUNT(*) as face_count \
FROM {} fd \
WHERE fd.trace_id IS NOT NULL \
AND NOT EXISTS ( \
SELECT 1 FROM {} i \
WHERE i.metadata->>'trace_id' = fd.trace_id::text \
) \
{} \
GROUP BY trace_id, file_uuid \
HAVING COUNT(*) >= $1 \
ORDER BY face_count DESC",
fd_table, identities_table, file_filter
);
let pool = state.db.pool();
@@ -660,8 +661,9 @@ fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
/// Round 2+: 用已匹配 trace 的所有 face 作為 seed傳播到未匹配 trace
async fn match_faces_iterative(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::Result<usize> {
// Step 1: 載入 TMDb identities (source='tmdb' 且有 face_embedding)
let identities_table = schema::table_name("identities");
let tmdb_rows = sqlx::query_as::<_, (i32, String, Vec<f32>)>(
"SELECT id, name, face_embedding::real[] FROM dev.identities WHERE source='tmdb' AND face_embedding IS NOT NULL"
&format!("SELECT id, name, face_embedding::real[] FROM {} WHERE source='tmdb' AND face_embedding IS NOT NULL", identities_table)
)
.fetch_all(pool).await?;
@@ -675,10 +677,11 @@ async fn match_faces_iterative(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::
);
// Step 2: 載入所有 face_detections按 trace_id 分組
let fd_table = schema::table_name("face_detections");
let fd_rows = sqlx::query_as::<_, (i32, Vec<f32>)>(
"SELECT trace_id, embedding FROM dev.face_detections \
&format!("SELECT trace_id, embedding FROM {} \
WHERE file_uuid=$1 AND trace_id IS NOT NULL AND embedding IS NOT NULL \
ORDER BY trace_id",
ORDER BY trace_id", fd_table),
)
.bind(file_uuid)
.fetch_all(pool)
@@ -797,17 +800,19 @@ async fn match_faces_iterative(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::
}
// Step 5: 寫入 DB
let identities_table = schema::table_name("identities");
let fd_table = schema::table_name("face_detections");
let mut updated = 0usize;
for (tid, name) in &matched {
let id_opt = sqlx::query_scalar::<_, Option<i32>>(
"SELECT id FROM dev.identities WHERE name=$1 AND source='tmdb'",
&format!("SELECT id FROM {} WHERE name=$1 AND source='tmdb'", identities_table),
)
.bind(name)
.fetch_optional(pool)
.await?;
if let Some(identity_id) = id_opt {
let _ = sqlx::query(
"UPDATE dev.face_detections SET identity_id=$1 WHERE file_uuid=$2 AND trace_id=$3",
&format!("UPDATE {} SET identity_id=$1 WHERE file_uuid=$2 AND trace_id=$3", fd_table),
)
.bind(identity_id)
.bind(file_uuid)
@@ -833,10 +838,11 @@ async fn match_faces_iterative(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::
/// and stores bindings in identity_bindings table.
pub async fn bind_speakers(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::Result<usize> {
// Load face traces with identity_id and frame numbers
let fd_table = schema::table_name("face_detections");
let traces = sqlx::query_as::<_, (i32, Vec<i32>)>(
"SELECT trace_id, array_agg(frame_number ORDER BY frame_number) \
FROM dev.face_detections WHERE file_uuid=$1 AND trace_id IS NOT NULL AND identity_id IS NOT NULL \
GROUP BY trace_id"
&format!("SELECT trace_id, array_agg(frame_number ORDER BY frame_number) \
FROM {} WHERE file_uuid=$1 AND trace_id IS NOT NULL AND identity_id IS NOT NULL \
GROUP BY trace_id", fd_table)
)
.bind(file_uuid)
.fetch_all(pool).await?;
@@ -903,8 +909,9 @@ pub async fn bind_speakers(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::Resu
}
// Get identity_id for this trace
let fd_table = schema::table_name("face_detections");
let identity_id: Option<i32> = sqlx::query_scalar(
"SELECT identity_id FROM dev.face_detections WHERE file_uuid=$1 AND trace_id=$2 AND identity_id IS NOT NULL LIMIT 1"
&format!("SELECT identity_id FROM {} WHERE file_uuid=$1 AND trace_id=$2 AND identity_id IS NOT NULL LIMIT 1", fd_table)
)
.bind(file_uuid).bind(trace_id)
.fetch_optional(pool).await?.flatten();
@@ -945,10 +952,11 @@ pub async fn bind_speakers(pool: &sqlx::PgPool, file_uuid: &str) -> anyhow::Resu
"overlap_ratio": overlap_ratio,
});
let ib_table = schema::table_name("identity_bindings");
let _ = sqlx::query(
"INSERT INTO dev.identity_bindings (identity_id, identity_type, identity_value, confidence, metadata) \
&format!("INSERT INTO {} (identity_id, identity_type, identity_value, confidence, metadata) \
VALUES ($1, 'speaker', $2, $3, $4::jsonb) \
ON CONFLICT (identity_id, identity_type, identity_value) DO UPDATE SET confidence = EXCLUDED.confidence, metadata = EXCLUDED.metadata"
ON CONFLICT (identity_id, identity_type, identity_value) DO UPDATE SET confidence = EXCLUDED.confidence, metadata = EXCLUDED.metadata", ib_table)
)
.bind(identity_id)
.bind(&best_speaker)
@@ -1025,7 +1033,7 @@ pub async fn run_identity_agent(db: &PostgresDb, file_uuid: &str) -> anyhow::Res
"reasoning": id_result.reasoning,
});
let _ = sqlx::query(
"INSERT INTO dev.identities (name, identity_type, source, metadata, status) VALUES ($1, 'people', 'auto', $2::jsonb, 'pending') ON CONFLICT DO NOTHING"
&format!("INSERT INTO {} (name, identity_type, source, metadata, status) VALUES ($1, 'people', 'auto', $2::jsonb, 'pending') ON CONFLICT DO NOTHING", schema::table_name("identities"))
)
.bind(&identity_name)
.bind(&metadata)