diff --git a/server/src/table_definition/handlers/post_table_definition.rs b/server/src/table_definition/handlers/post_table_definition.rs index d4d1b48..cd1ff41 100644 --- a/server/src/table_definition/handlers/post_table_definition.rs +++ b/server/src/table_definition/handlers/post_table_definition.rs @@ -312,7 +312,8 @@ async fn generate_table_sql( indexes: &[String], links: &[(i64, bool)], ) -> Result<(String, Vec), Status> { - let qualified_table = format!("{}.\"{}\"", profile_name, table_name); + // CHANGE: Quote the schema name + let qualified_table = format!("\"{}\".\"{}\"", profile_name, table_name); let mut system_columns = vec![ "id BIGSERIAL PRIMARY KEY".to_string(), @@ -321,7 +322,8 @@ async fn generate_table_sql( for (linked_id, required) in links { let linked_table = get_table_name_by_id(tx, *linked_id).await?; - let qualified_linked_table = format!("{}.\"{}\"", profile_name, linked_table); + // CHANGE: Quote the schema name here too + let qualified_linked_table = format!("\"{}\".\"{}\"", profile_name, linked_table); let base_name = linked_table.split_once('_') .map(|(_, rest)| rest) .unwrap_or(&linked_table) diff --git a/server/tests/common/mod.rs b/server/tests/common/mod.rs index 78c13a8..cb085bd 100644 --- a/server/tests/common/mod.rs +++ b/server/tests/common/mod.rs @@ -41,12 +41,18 @@ pub async fn setup_isolated_db() -> PgPool { .await .unwrap_or_else(|_| panic!("Failed to create schema: {}", schema_name)); + root_conn + .execute("CREATE SCHEMA IF NOT EXISTS \"default\"") + .await + .unwrap(); + let pool = PgPoolOptions::new() .max_connections(5) .after_connect(move |conn, _meta| { let schema_name = schema_name.clone(); Box::pin(async move { - conn.execute(format!("SET search_path TO \"{}\"", schema_name).as_str()) + conn.execute(format!("SET search_path TO \"{}\", \"default\", \"public\"", schema_name).as_str()) + .await?; Ok(()) }) diff --git a/server/tests/table_definition/post_table_definition_test.rs b/server/tests/table_definition/post_table_definition_test.rs index 2c700ab..ebfecff 100644 --- a/server/tests/table_definition/post_table_definition_test.rs +++ b/server/tests/table_definition/post_table_definition_test.rs @@ -15,16 +15,10 @@ use std::env; use dotenvy; use std::path::Path; -// =================================================================== -// SPECIALIZED SETUP FOR `table_definition` TESTS -// This setup logic is now local to this file and will not affect other tests. -// =================================================================== async fn setup_isolated_gen_schema_db() -> PgPool { - // ---- ADD THIS BLOCK TO LOAD THE .env_test FILE ---- let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set"); let env_path = Path::new(&manifest_dir).join(".env_test"); dotenvy::from_path(env_path).ok(); - // ---------------------------------------------------- let database_url = env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set"); @@ -38,17 +32,37 @@ async fn setup_isolated_gen_schema_db() -> PgPool { ); let mut root_conn = PgConnection::connect(&database_url).await.unwrap(); + + // Create the test schema root_conn .execute(format!("CREATE SCHEMA \"{}\"", unique_schema_name).as_str()) .await .unwrap(); + // Create schemas A and B for cross-profile tests + root_conn + .execute("CREATE SCHEMA IF NOT EXISTS \"A\"") + .await + .unwrap(); + + root_conn + .execute("CREATE SCHEMA IF NOT EXISTS \"B\"") + .await + .unwrap(); + + // IMPORTANT: Create the "default" schema if it doesn't exist + root_conn + .execute("CREATE SCHEMA IF NOT EXISTS \"default\"") + .await + .unwrap(); + let pool = PgPoolOptions::new() .max_connections(5) .after_connect(move |conn, _meta| { let schema = unique_schema_name.clone(); Box::pin(async move { - conn.execute(format!("SET search_path = '{}'", schema).as_str()) + // Set search path to include test schema, default, A, B, and public + conn.execute(format!("SET search_path = '{}', 'default', 'A', 'B', 'public'", schema).as_str()) .await?; Ok(()) }) @@ -62,10 +76,13 @@ async fn setup_isolated_gen_schema_db() -> PgPool { .await .expect("Migrations failed in isolated schema"); - sqlx::query!("INSERT INTO schemas (name) VALUES ('default') ON CONFLICT (name) DO NOTHING") - .execute(&pool) - .await - .expect("Failed to insert test schema in isolated schema"); + // Insert into the schemas table - use INSERT ... ON CONFLICT to avoid duplicates + sqlx::query!( + "INSERT INTO schemas (name) VALUES ('default'), ('A'), ('B') ON CONFLICT (name) DO NOTHING" + ) + .execute(&pool) + .await + .expect("Failed to insert test schemas"); pool } diff --git a/server/tests/table_definition/post_table_definition_test3.rs b/server/tests/table_definition/post_table_definition_test3.rs index 8cd1b19..c61c895 100644 --- a/server/tests/table_definition/post_table_definition_test3.rs +++ b/server/tests/table_definition/post_table_definition_test3.rs @@ -107,7 +107,7 @@ async fn test_link_to_sanitized_table_name(#[future] pool: PgPool) { ..Default::default() }; let resp = post_table_definition(&pool, create_req).await.unwrap(); - assert!(resp.sql.contains(&format!("gen.\"{}\"", sanitized_name))); + assert!(resp.sql.contains(&format!("\"default\".\"{}\"", sanitized_name))); // 2. Attempt to link to the *original* name, which should fail. let link_req_fail = PostTableDefinitionRequest { @@ -139,7 +139,8 @@ async fn test_link_to_sanitized_table_name(#[future] pool: PgPool) { assert!(success_resp.success); assert!(success_resp .sql - .contains(&format!("REFERENCES gen.\"{}\"(id)", sanitized_name))); + .contains(&format!("REFERENCES \"default\".\"{}\"(id)", sanitized_name))); + } // ========= Category 3: Complex Link and Profile Logic =========