From 4e43e01e808e10e1b6bffd0d45b48cdb54c72096 Mon Sep 17 00:00:00 2001 From: Julian Date: Fri, 29 Aug 2025 18:21:30 +0200 Subject: [PATCH 01/14] intermeidary --- Cargo.lock | 2 ++ crates/pgt_completions/src/test_helper.rs | 4 +-- crates/pgt_configuration/src/database.rs | 7 +++++ crates/pgt_configuration/src/lib.rs | 1 + crates/pgt_plpgsql_check/src/lib.rs | 2 +- crates/pgt_schema_cache/Cargo.toml | 3 ++ crates/pgt_schema_cache/src/columns.rs | 2 +- crates/pgt_schema_cache/src/functions.rs | 2 +- crates/pgt_schema_cache/src/policies.rs | 2 +- crates/pgt_schema_cache/src/roles.rs | 2 +- crates/pgt_schema_cache/src/schema_cache.rs | 31 +++++++++++++++++-- crates/pgt_schema_cache/src/tables.rs | 4 +-- crates/pgt_schema_cache/src/triggers.rs | 4 +-- crates/pgt_typecheck/src/lib.rs | 11 +++++++ crates/pgt_typecheck/src/typed_identifier.rs | 2 +- crates/pgt_typecheck/tests/diagnostics.rs | 2 +- .../workspace/server/schema_cache_manager.rs | 14 ++++++--- 17 files changed, 76 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be7eacb75..7a8e1507a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3068,6 +3068,8 @@ dependencies = [ "anyhow", "async-std", "futures-util", + "globset", + "itertools 0.14.0", "pgt_console", "pgt_diagnostics", "pgt_test_utils", diff --git a/crates/pgt_completions/src/test_helper.rs b/crates/pgt_completions/src/test_helper.rs index e6c347614..6c63fa21c 100644 --- a/crates/pgt_completions/src/test_helper.rs +++ b/crates/pgt_completions/src/test_helper.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_test_deps( .expect("Failed to execute setup query"); } - let schema_cache = SchemaCache::load(test_db) + let schema_cache = SchemaCache::load(test_db, vec![]) .await .expect("Failed to load Schema Cache"); @@ -41,7 +41,7 @@ pub(crate) async fn test_against_connection_string( .await .expect("Unable to connect to database."); - let schema_cache = SchemaCache::load(&pool) + let schema_cache = SchemaCache::load(&pool, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_configuration/src/database.rs b/crates/pgt_configuration/src/database.rs index 39efb8d13..3c14dee92 100644 --- a/crates/pgt_configuration/src/database.rs +++ b/crates/pgt_configuration/src/database.rs @@ -38,6 +38,12 @@ pub struct DatabaseConfiguration { #[partial(bpaf(long("conn_timeout_secs"), fallback(Some(10)), debug_fallback))] pub conn_timeout_secs: u16, + /// Default search path schemas for type checking. + /// Can be a list of schema names or glob patterns like ["public", "app_*"]. + /// If not specified, defaults to ["public"]. + #[partial(bpaf(long("search_path")))] + pub search_path: StringSet, + /// Actively disable all database-related features. #[partial(bpaf(long("disable-db"), switch, fallback(Some(false))))] #[partial(cfg_attr(feature = "schema", schemars(skip)))] @@ -55,6 +61,7 @@ impl Default for DatabaseConfiguration { database: "postgres".to_string(), allow_statement_executions_against: Default::default(), conn_timeout_secs: 10, + search_path: ["public".to_string()].into_iter().collect(), } } } diff --git a/crates/pgt_configuration/src/lib.rs b/crates/pgt_configuration/src/lib.rs index b862dce4f..e3d75e0b5 100644 --- a/crates/pgt_configuration/src/lib.rs +++ b/crates/pgt_configuration/src/lib.rs @@ -118,6 +118,7 @@ impl PartialConfiguration { database: Some("postgres".to_string()), allow_statement_executions_against: Default::default(), conn_timeout_secs: Some(10), + search_path: Default::default(), disable_connection: Some(false), }), } diff --git a/crates/pgt_plpgsql_check/src/lib.rs b/crates/pgt_plpgsql_check/src/lib.rs index 05e2f5709..fa44e30ac 100644 --- a/crates/pgt_plpgsql_check/src/lib.rs +++ b/crates/pgt_plpgsql_check/src/lib.rs @@ -247,7 +247,7 @@ mod tests { let ast = pgt_query::parse(create_fn_sql)? .into_root() .ok_or("Failed to parse SQL root")?; - let schema_cache = pgt_schema_cache::SchemaCache::load(test_db).await?; + let schema_cache = pgt_schema_cache::SchemaCache::load(test_db, vec![]).await?; let diagnostics = super::check_plpgsql(super::PlPgSqlCheckParams { conn: test_db, diff --git a/crates/pgt_schema_cache/Cargo.toml b/crates/pgt_schema_cache/Cargo.toml index c5fadb3e2..d8aaad3c1 100644 --- a/crates/pgt_schema_cache/Cargo.toml +++ b/crates/pgt_schema_cache/Cargo.toml @@ -15,6 +15,7 @@ version = "0.0.0" anyhow.workspace = true async-std = { version = "1.12.0" } futures-util = "0.3.31" +globset = "0.4.16" pgt_console.workspace = true pgt_diagnostics.workspace = true serde.workspace = true @@ -22,6 +23,8 @@ serde_json.workspace = true sqlx.workspace = true strum = { workspace = true } tokio.workspace = true +itertools = "0.14.0" + [dev-dependencies] pgt_test_utils.workspace = true diff --git a/crates/pgt_schema_cache/src/columns.rs b/crates/pgt_schema_cache/src/columns.rs index 01f9b41ce..dd4ebeac0 100644 --- a/crates/pgt_schema_cache/src/columns.rs +++ b/crates/pgt_schema_cache/src/columns.rs @@ -119,7 +119,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs index 4afaa76dd..e34e566db 100644 --- a/crates/pgt_schema_cache/src/functions.rs +++ b/crates/pgt_schema_cache/src/functions.rs @@ -203,7 +203,7 @@ mod tests { pool.execute(setup).await.unwrap(); - let cache = SchemaCache::load(&pool).await.unwrap(); + let cache = SchemaCache::load(&pool, vec![]).await.unwrap(); // Find and check the function let foo_fn = cache diff --git a/crates/pgt_schema_cache/src/policies.rs b/crates/pgt_schema_cache/src/policies.rs index 8e2ee4d70..23c5f7151 100644 --- a/crates/pgt_schema_cache/src/policies.rs +++ b/crates/pgt_schema_cache/src/policies.rs @@ -137,7 +137,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/roles.rs b/crates/pgt_schema_cache/src/roles.rs index 7ced66f97..8190ae3f4 100644 --- a/crates/pgt_schema_cache/src/roles.rs +++ b/crates/pgt_schema_cache/src/roles.rs @@ -27,7 +27,7 @@ mod tests { #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] async fn loads_roles(test_db: PgPool) { - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/schema_cache.rs b/crates/pgt_schema_cache/src/schema_cache.rs index 89eddca95..ed2d9a1e9 100644 --- a/crates/pgt_schema_cache/src/schema_cache.rs +++ b/crates/pgt_schema_cache/src/schema_cache.rs @@ -1,3 +1,4 @@ +use globset::Glob; use sqlx::postgres::PgPool; use crate::columns::Column; @@ -9,6 +10,8 @@ use crate::types::PostgresType; use crate::versions::Version; use crate::{Extension, Role, Trigger}; +use itertools::Itertools; + #[derive(Debug, Default)] pub struct SchemaCache { pub schemas: Vec, @@ -21,10 +24,11 @@ pub struct SchemaCache { pub extensions: Vec, pub triggers: Vec, pub roles: Vec, + search_path: Vec, } impl SchemaCache { - pub async fn load(pool: &PgPool) -> Result { + pub async fn load(pool: &PgPool, search_path: Vec) -> Result { let ( schemas, tables, @@ -60,6 +64,7 @@ impl SchemaCache { triggers, roles, extensions, + search_path, }) } @@ -89,6 +94,28 @@ impl SchemaCache { .filter(|t| t.name == name && schema.is_none_or(|s| s == t.schema.as_str())) .collect() } + + pub fn schemas_in_search_path(&self) -> Vec<&Schema> { + self.search_path + .iter() + .filter_map(|pattern| { + if let Ok(glob) = Glob::new(pattern) { + let matcher = glob.compile_matcher(); + + Some( + self.schemas + .iter() + .filter(|schema| matcher.is_match(schema.name.as_str())) + .collect::>(), + ) + } else { + None + } + }) + .flatten() + .unique_by(|s| &s.name) + .collect() + } } pub trait SchemaCacheItem { @@ -105,7 +132,7 @@ mod tests { #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] async fn it_loads(test_db: PgPool) { - SchemaCache::load(&test_db) + SchemaCache::load(&test_db, vec![]) .await .expect("Couldnt' load Schema Cache"); } diff --git a/crates/pgt_schema_cache/src/tables.rs b/crates/pgt_schema_cache/src/tables.rs index 16b86c54a..212d75bbe 100644 --- a/crates/pgt_schema_cache/src/tables.rs +++ b/crates/pgt_schema_cache/src/tables.rs @@ -100,7 +100,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); @@ -131,7 +131,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/triggers.rs b/crates/pgt_schema_cache/src/triggers.rs index d0a4788a0..85d3a6166 100644 --- a/crates/pgt_schema_cache/src/triggers.rs +++ b/crates/pgt_schema_cache/src/triggers.rs @@ -174,7 +174,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); @@ -263,7 +263,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db) + let cache = SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_typecheck/src/lib.rs b/crates/pgt_typecheck/src/lib.rs index ceb36b94e..3f3b475d4 100644 --- a/crates/pgt_typecheck/src/lib.rs +++ b/crates/pgt_typecheck/src/lib.rs @@ -49,6 +49,17 @@ pub async fn check_sql( params.sql, ); + // Build dynamic search_path from schema cache configuration + let search_schemas = params.schema_cache.schemas_in_search_path(); + if !search_schemas.is_empty() { + let mut schema_names: Vec<&str> = search_schemas.iter().map(|s| s.name.as_str()).collect(); + if !schema_names.contains(&"public") { + schema_names.push("public"); + } + let search_path_query = format!("SET search_path TO {};", schema_names.join(", ")); + conn.execute(&*search_path_query).await?; + } + let res = conn.prepare(&prepared).await; match res { diff --git a/crates/pgt_typecheck/src/typed_identifier.rs b/crates/pgt_typecheck/src/typed_identifier.rs index 1ee4095dc..68093e80f 100644 --- a/crates/pgt_typecheck/src/typed_identifier.rs +++ b/crates/pgt_typecheck/src/typed_identifier.rs @@ -319,7 +319,7 @@ mod tests { .set_language(tree_sitter_sql::language()) .expect("Error loading sql language"); - let schema_cache = pgt_schema_cache::SchemaCache::load(&test_db) + let schema_cache = pgt_schema_cache::SchemaCache::load(&test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_typecheck/tests/diagnostics.rs b/crates/pgt_typecheck/tests/diagnostics.rs index f21d9ef9b..5dad89f70 100644 --- a/crates/pgt_typecheck/tests/diagnostics.rs +++ b/crates/pgt_typecheck/tests/diagnostics.rs @@ -19,7 +19,7 @@ async fn test(name: &str, query: &str, setup: Option<&str>, test_db: &PgPool) { .set_language(tree_sitter_sql::language()) .expect("Error loading sql language"); - let schema_cache = pgt_schema_cache::SchemaCache::load(test_db) + let schema_cache = pgt_schema_cache::SchemaCache::load(test_db, vec![]) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs index 007ebb782..c5fe6c4c4 100644 --- a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs +++ b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs @@ -11,16 +11,22 @@ use super::{async_helper::run_async, connection_key::ConnectionKey}; #[derive(Default)] pub struct SchemaCacheManager { schemas: RwLock>>, + default_search_path: Vec, } impl SchemaCacheManager { pub fn new() -> Self { Self { schemas: RwLock::new(HashMap::new()), + default_search_path: vec![], } } - pub fn load(&self, pool: PgPool) -> Result, WorkspaceError> { + pub fn load( + &self, + pool: PgPool, + default_search_path: Vec, + ) -> Result, WorkspaceError> { let key: ConnectionKey = (&pool).into(); // Try read lock first for cache hit @@ -40,9 +46,9 @@ impl SchemaCacheManager { // Load schema cache let pool_clone = pool.clone(); - let schema_cache = Arc::new(run_async( - async move { SchemaCache::load(&pool_clone).await }, - )??); + let schema_cache = Arc::new(run_async(async move { + SchemaCache::load(&pool_clone, default_search_path).await + })??); schemas.insert(key, schema_cache.clone()); Ok(schema_cache) From ead4101ee6073206bebe357e8edddc9b1a5188b2 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 07:48:11 +0200 Subject: [PATCH 02/14] so far --- Cargo.lock | 4 +- crates/pgt_completions/src/test_helper.rs | 4 +- .../src/analyser/linter/mod.rs | 7 +++ crates/pgt_configuration/src/database.rs | 7 --- crates/pgt_configuration/src/lib.rs | 1 - crates/pgt_plpgsql_check/src/lib.rs | 2 +- crates/pgt_schema_cache/Cargo.toml | 2 - crates/pgt_schema_cache/src/columns.rs | 2 +- crates/pgt_schema_cache/src/functions.rs | 2 +- crates/pgt_schema_cache/src/policies.rs | 2 +- crates/pgt_schema_cache/src/roles.rs | 2 +- crates/pgt_schema_cache/src/schema_cache.rs | 30 +--------- crates/pgt_schema_cache/src/tables.rs | 4 +- crates/pgt_schema_cache/src/triggers.rs | 4 +- crates/pgt_typecheck/Cargo.toml | 2 + crates/pgt_typecheck/src/lib.rs | 55 ++++++++++++++++--- crates/pgt_typecheck/src/typed_identifier.rs | 2 +- crates/pgt_typecheck/tests/diagnostics.rs | 3 +- crates/pgt_workspace/src/settings.rs | 27 +++++++++ crates/pgt_workspace/src/workspace/server.rs | 4 ++ .../workspace/server/schema_cache_manager.rs | 10 +--- postgrestools.jsonc | 3 +- test.sql | 51 +++++++---------- 23 files changed, 129 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a8e1507a..c085f8449 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3068,8 +3068,6 @@ dependencies = [ "anyhow", "async-std", "futures-util", - "globset", - "itertools 0.14.0", "pgt_console", "pgt_diagnostics", "pgt_test_utils", @@ -3178,7 +3176,9 @@ dependencies = [ name = "pgt_typecheck" version = "0.0.0" dependencies = [ + "globset", "insta", + "itertools 0.14.0", "pgt_console", "pgt_diagnostics", "pgt_query", diff --git a/crates/pgt_completions/src/test_helper.rs b/crates/pgt_completions/src/test_helper.rs index 6c63fa21c..e6c347614 100644 --- a/crates/pgt_completions/src/test_helper.rs +++ b/crates/pgt_completions/src/test_helper.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_test_deps( .expect("Failed to execute setup query"); } - let schema_cache = SchemaCache::load(test_db, vec![]) + let schema_cache = SchemaCache::load(test_db) .await .expect("Failed to load Schema Cache"); @@ -41,7 +41,7 @@ pub(crate) async fn test_against_connection_string( .await .expect("Unable to connect to database."); - let schema_cache = SchemaCache::load(&pool, vec![]) + let schema_cache = SchemaCache::load(&pool) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_configuration/src/analyser/linter/mod.rs b/crates/pgt_configuration/src/analyser/linter/mod.rs index 20535a2e7..4a3188637 100644 --- a/crates/pgt_configuration/src/analyser/linter/mod.rs +++ b/crates/pgt_configuration/src/analyser/linter/mod.rs @@ -28,6 +28,12 @@ pub struct LinterConfiguration { /// match these patterns. #[partial(bpaf(hide))] pub include: StringSet, + + /// Default search path schemas for type checking. + /// Can be a list of schema names or glob patterns like ["public", "app_*"]. + /// If not specified, defaults to ["public"]. + #[partial(bpaf(long("search_path")))] + pub search_path_patterns: StringSet, } impl LinterConfiguration { @@ -43,6 +49,7 @@ impl Default for LinterConfiguration { rules: Default::default(), ignore: Default::default(), include: Default::default(), + search_path_patterns: ["public".to_string()].into_iter().collect(), } } } diff --git a/crates/pgt_configuration/src/database.rs b/crates/pgt_configuration/src/database.rs index 3c14dee92..39efb8d13 100644 --- a/crates/pgt_configuration/src/database.rs +++ b/crates/pgt_configuration/src/database.rs @@ -38,12 +38,6 @@ pub struct DatabaseConfiguration { #[partial(bpaf(long("conn_timeout_secs"), fallback(Some(10)), debug_fallback))] pub conn_timeout_secs: u16, - /// Default search path schemas for type checking. - /// Can be a list of schema names or glob patterns like ["public", "app_*"]. - /// If not specified, defaults to ["public"]. - #[partial(bpaf(long("search_path")))] - pub search_path: StringSet, - /// Actively disable all database-related features. #[partial(bpaf(long("disable-db"), switch, fallback(Some(false))))] #[partial(cfg_attr(feature = "schema", schemars(skip)))] @@ -61,7 +55,6 @@ impl Default for DatabaseConfiguration { database: "postgres".to_string(), allow_statement_executions_against: Default::default(), conn_timeout_secs: 10, - search_path: ["public".to_string()].into_iter().collect(), } } } diff --git a/crates/pgt_configuration/src/lib.rs b/crates/pgt_configuration/src/lib.rs index e3d75e0b5..b862dce4f 100644 --- a/crates/pgt_configuration/src/lib.rs +++ b/crates/pgt_configuration/src/lib.rs @@ -118,7 +118,6 @@ impl PartialConfiguration { database: Some("postgres".to_string()), allow_statement_executions_against: Default::default(), conn_timeout_secs: Some(10), - search_path: Default::default(), disable_connection: Some(false), }), } diff --git a/crates/pgt_plpgsql_check/src/lib.rs b/crates/pgt_plpgsql_check/src/lib.rs index fa44e30ac..05e2f5709 100644 --- a/crates/pgt_plpgsql_check/src/lib.rs +++ b/crates/pgt_plpgsql_check/src/lib.rs @@ -247,7 +247,7 @@ mod tests { let ast = pgt_query::parse(create_fn_sql)? .into_root() .ok_or("Failed to parse SQL root")?; - let schema_cache = pgt_schema_cache::SchemaCache::load(test_db, vec![]).await?; + let schema_cache = pgt_schema_cache::SchemaCache::load(test_db).await?; let diagnostics = super::check_plpgsql(super::PlPgSqlCheckParams { conn: test_db, diff --git a/crates/pgt_schema_cache/Cargo.toml b/crates/pgt_schema_cache/Cargo.toml index d8aaad3c1..9a05ac439 100644 --- a/crates/pgt_schema_cache/Cargo.toml +++ b/crates/pgt_schema_cache/Cargo.toml @@ -15,7 +15,6 @@ version = "0.0.0" anyhow.workspace = true async-std = { version = "1.12.0" } futures-util = "0.3.31" -globset = "0.4.16" pgt_console.workspace = true pgt_diagnostics.workspace = true serde.workspace = true @@ -23,7 +22,6 @@ serde_json.workspace = true sqlx.workspace = true strum = { workspace = true } tokio.workspace = true -itertools = "0.14.0" [dev-dependencies] diff --git a/crates/pgt_schema_cache/src/columns.rs b/crates/pgt_schema_cache/src/columns.rs index dd4ebeac0..01f9b41ce 100644 --- a/crates/pgt_schema_cache/src/columns.rs +++ b/crates/pgt_schema_cache/src/columns.rs @@ -119,7 +119,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/functions.rs b/crates/pgt_schema_cache/src/functions.rs index e34e566db..4afaa76dd 100644 --- a/crates/pgt_schema_cache/src/functions.rs +++ b/crates/pgt_schema_cache/src/functions.rs @@ -203,7 +203,7 @@ mod tests { pool.execute(setup).await.unwrap(); - let cache = SchemaCache::load(&pool, vec![]).await.unwrap(); + let cache = SchemaCache::load(&pool).await.unwrap(); // Find and check the function let foo_fn = cache diff --git a/crates/pgt_schema_cache/src/policies.rs b/crates/pgt_schema_cache/src/policies.rs index 23c5f7151..8e2ee4d70 100644 --- a/crates/pgt_schema_cache/src/policies.rs +++ b/crates/pgt_schema_cache/src/policies.rs @@ -137,7 +137,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/roles.rs b/crates/pgt_schema_cache/src/roles.rs index 8190ae3f4..7ced66f97 100644 --- a/crates/pgt_schema_cache/src/roles.rs +++ b/crates/pgt_schema_cache/src/roles.rs @@ -27,7 +27,7 @@ mod tests { #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] async fn loads_roles(test_db: PgPool) { - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/schema_cache.rs b/crates/pgt_schema_cache/src/schema_cache.rs index ed2d9a1e9..53ccd755e 100644 --- a/crates/pgt_schema_cache/src/schema_cache.rs +++ b/crates/pgt_schema_cache/src/schema_cache.rs @@ -1,4 +1,3 @@ -use globset::Glob; use sqlx::postgres::PgPool; use crate::columns::Column; @@ -10,8 +9,6 @@ use crate::types::PostgresType; use crate::versions::Version; use crate::{Extension, Role, Trigger}; -use itertools::Itertools; - #[derive(Debug, Default)] pub struct SchemaCache { pub schemas: Vec, @@ -24,11 +21,10 @@ pub struct SchemaCache { pub extensions: Vec, pub triggers: Vec, pub roles: Vec, - search_path: Vec, } impl SchemaCache { - pub async fn load(pool: &PgPool, search_path: Vec) -> Result { + pub async fn load(pool: &PgPool) -> Result { let ( schemas, tables, @@ -64,7 +60,6 @@ impl SchemaCache { triggers, roles, extensions, - search_path, }) } @@ -95,27 +90,6 @@ impl SchemaCache { .collect() } - pub fn schemas_in_search_path(&self) -> Vec<&Schema> { - self.search_path - .iter() - .filter_map(|pattern| { - if let Ok(glob) = Glob::new(pattern) { - let matcher = glob.compile_matcher(); - - Some( - self.schemas - .iter() - .filter(|schema| matcher.is_match(schema.name.as_str())) - .collect::>(), - ) - } else { - None - } - }) - .flatten() - .unique_by(|s| &s.name) - .collect() - } } pub trait SchemaCacheItem { @@ -132,7 +106,7 @@ mod tests { #[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] async fn it_loads(test_db: PgPool) { - SchemaCache::load(&test_db, vec![]) + SchemaCache::load(&test_db) .await .expect("Couldnt' load Schema Cache"); } diff --git a/crates/pgt_schema_cache/src/tables.rs b/crates/pgt_schema_cache/src/tables.rs index 212d75bbe..16b86c54a 100644 --- a/crates/pgt_schema_cache/src/tables.rs +++ b/crates/pgt_schema_cache/src/tables.rs @@ -100,7 +100,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); @@ -131,7 +131,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_schema_cache/src/triggers.rs b/crates/pgt_schema_cache/src/triggers.rs index 85d3a6166..d0a4788a0 100644 --- a/crates/pgt_schema_cache/src/triggers.rs +++ b/crates/pgt_schema_cache/src/triggers.rs @@ -174,7 +174,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); @@ -263,7 +263,7 @@ mod tests { .await .expect("Failed to setup test database"); - let cache = SchemaCache::load(&test_db, vec![]) + let cache = SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_typecheck/Cargo.toml b/crates/pgt_typecheck/Cargo.toml index f61f6a37e..75c76fa35 100644 --- a/crates/pgt_typecheck/Cargo.toml +++ b/crates/pgt_typecheck/Cargo.toml @@ -12,6 +12,7 @@ version = "0.0.0" [dependencies] +globset = "0.4.16" pgt_console.workspace = true pgt_diagnostics.workspace = true pgt_query.workspace = true @@ -22,6 +23,7 @@ sqlx.workspace = true tokio.workspace = true tree-sitter.workspace = true tree_sitter_sql.workspace = true +itertools ={ version = "0.14.0" } [dev-dependencies] insta.workspace = true diff --git a/crates/pgt_typecheck/src/lib.rs b/crates/pgt_typecheck/src/lib.rs index 3f3b475d4..e4fc7e59a 100644 --- a/crates/pgt_typecheck/src/lib.rs +++ b/crates/pgt_typecheck/src/lib.rs @@ -3,6 +3,9 @@ mod typed_identifier; pub use diagnostics::TypecheckDiagnostic; use diagnostics::create_type_error; +use globset::Glob; +use itertools::Itertools; +use pgt_schema_cache::SchemaCache; use sqlx::postgres::PgDatabaseError; pub use sqlx::postgres::PgSeverity; use sqlx::{Executor, PgPool}; @@ -17,6 +20,9 @@ pub struct TypecheckParams<'a> { pub tree: &'a tree_sitter::Tree, pub schema_cache: &'a pgt_schema_cache::SchemaCache, pub identifiers: Vec, + /// Set of glob patterns that will be matched against the schemas in the database. + /// Each matching schema will be added to the search_path for the typecheck. + pub search_path_patterns: Vec, } pub async fn check_sql( @@ -49,14 +55,16 @@ pub async fn check_sql( params.sql, ); - // Build dynamic search_path from schema cache configuration - let search_schemas = params.schema_cache.schemas_in_search_path(); - if !search_schemas.is_empty() { - let mut schema_names: Vec<&str> = search_schemas.iter().map(|s| s.name.as_str()).collect(); - if !schema_names.contains(&"public") { - schema_names.push("public"); + let mut search_path_schemas = + get_schemas_in_search_path(params.schema_cache, params.search_path_patterns); + + if !search_path_schemas.is_empty() { + // Always include public if we have any schemas in search path + if !search_path_schemas.contains(&"public") { + search_path_schemas.push("public"); } - let search_path_query = format!("SET search_path TO {};", schema_names.join(", ")); + + let search_path_query = format!("SET search_path TO {};", search_path_schemas.join(", ")); conn.execute(&*search_path_query).await?; } @@ -75,3 +83,36 @@ pub async fn check_sql( Err(err) => Err(err), } } + +fn get_schemas_in_search_path<'a>( + schema_cache: &'a SchemaCache, + glob_patterns: Vec, +) -> Vec<&'a str> { + // iterate over glob_patterns on the outside to keep the order + glob_patterns + .iter() + .filter_map(|pattern| { + if let Ok(glob) = Glob::new(pattern) { + let matcher = glob.compile_matcher(); + + Some( + schema_cache + .schemas + .iter() + .filter_map(|s| { + if matcher.is_match(s.name.as_str()) { + Some(s.name.as_str()) + } else { + None + } + }) + .collect::>(), + ) + } else { + None + } + }) + .flatten() + .unique() + .collect() +} diff --git a/crates/pgt_typecheck/src/typed_identifier.rs b/crates/pgt_typecheck/src/typed_identifier.rs index 68093e80f..1ee4095dc 100644 --- a/crates/pgt_typecheck/src/typed_identifier.rs +++ b/crates/pgt_typecheck/src/typed_identifier.rs @@ -319,7 +319,7 @@ mod tests { .set_language(tree_sitter_sql::language()) .expect("Error loading sql language"); - let schema_cache = pgt_schema_cache::SchemaCache::load(&test_db, vec![]) + let schema_cache = pgt_schema_cache::SchemaCache::load(&test_db) .await .expect("Failed to load Schema Cache"); diff --git a/crates/pgt_typecheck/tests/diagnostics.rs b/crates/pgt_typecheck/tests/diagnostics.rs index 5dad89f70..fefa4209a 100644 --- a/crates/pgt_typecheck/tests/diagnostics.rs +++ b/crates/pgt_typecheck/tests/diagnostics.rs @@ -19,7 +19,7 @@ async fn test(name: &str, query: &str, setup: Option<&str>, test_db: &PgPool) { .set_language(tree_sitter_sql::language()) .expect("Error loading sql language"); - let schema_cache = pgt_schema_cache::SchemaCache::load(test_db, vec![]) + let schema_cache = pgt_schema_cache::SchemaCache::load(test_db) .await .expect("Failed to load Schema Cache"); @@ -36,6 +36,7 @@ async fn test(name: &str, query: &str, setup: Option<&str>, test_db: &PgPool) { ast: &root, tree: &tree, schema_cache: &schema_cache, + search_path_patterns: vec![], identifiers: vec![], }) .await; diff --git a/crates/pgt_workspace/src/settings.rs b/crates/pgt_workspace/src/settings.rs index 40db2c1e6..80be80e8f 100644 --- a/crates/pgt_workspace/src/settings.rs +++ b/crates/pgt_workspace/src/settings.rs @@ -291,6 +291,7 @@ fn to_linter_settings( rules: Some(conf.rules), ignored_files: to_matcher(working_directory.clone(), Some(&conf.ignore))?, included_files: to_matcher(working_directory.clone(), Some(&conf.include))?, + search_path_patterns: conf.search_path_patterns.into_iter().collect(), }) } @@ -388,6 +389,31 @@ pub struct LinterSettings { /// List of included paths/files to match pub included_files: Matcher, + + /// Glob patterns for additional schemas to check when typechecking + pub search_path_patterns: Vec, +} + +impl LinterSettings { + /// Returns schema names that match the configured search path patterns. + /// Supports glob patterns like "app_*" or exact matches. + pub fn get_matching_schemas<'a>(&self, schema_names: &'a [&str]) -> Vec<&'a str> { + schema_names + .iter() + .filter(|&&schema_name| { + self.search_path_patterns.iter().any(|pattern| { + if let Ok(glob) = Glob::new(pattern) { + let matcher = glob.compile_matcher(); + matcher.is_match(schema_name) + } else { + // fallback to exact match if glob pattern is invalid + pattern == schema_name + } + }) + }) + .copied() + .collect() + } } impl Default for LinterSettings { @@ -397,6 +423,7 @@ impl Default for LinterSettings { rules: Some(pgt_configuration::analyser::linter::Rules::default()), ignored_files: Matcher::empty(), included_files: Matcher::empty(), + search_path_patterns: vec!["public".to_string()], } } } diff --git a/crates/pgt_workspace/src/workspace/server.rs b/crates/pgt_workspace/src/workspace/server.rs index ea9039ce1..fd0880ad3 100644 --- a/crates/pgt_workspace/src/workspace/server.rs +++ b/crates/pgt_workspace/src/workspace/server.rs @@ -455,6 +455,7 @@ impl Workspace for WorkspaceServer { let path_clone = params.path.clone(); let schema_cache = self.schema_cache.load(pool.clone())?; let input = doc.iter(TypecheckDiagnosticsMapper).collect::>(); + let search_path_patterns = settings.linter.search_path_patterns.clone(); // Combined async context for both typecheck and plpgsql_check let async_results = run_async(async move { @@ -463,6 +464,8 @@ impl Workspace for WorkspaceServer { let pool = pool.clone(); let path = path_clone.clone(); let schema_cache = Arc::clone(&schema_cache); + let search_path_patterns = search_path_patterns.clone(); + async move { let mut diagnostics = Vec::new(); @@ -474,6 +477,7 @@ impl Workspace for WorkspaceServer { ast: &ast, tree: &cst, schema_cache: schema_cache.as_ref(), + search_path_patterns, identifiers: sign .map(|s| { s.args diff --git a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs index c5fe6c4c4..7335e3fb6 100644 --- a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs +++ b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs @@ -11,22 +11,16 @@ use super::{async_helper::run_async, connection_key::ConnectionKey}; #[derive(Default)] pub struct SchemaCacheManager { schemas: RwLock>>, - default_search_path: Vec, } impl SchemaCacheManager { pub fn new() -> Self { Self { schemas: RwLock::new(HashMap::new()), - default_search_path: vec![], } } - pub fn load( - &self, - pool: PgPool, - default_search_path: Vec, - ) -> Result, WorkspaceError> { + pub fn load(&self, pool: PgPool) -> Result, WorkspaceError> { let key: ConnectionKey = (&pool).into(); // Try read lock first for cache hit @@ -47,7 +41,7 @@ impl SchemaCacheManager { // Load schema cache let pool_clone = pool.clone(); let schema_cache = Arc::new(run_async(async move { - SchemaCache::load(&pool_clone, default_search_path).await + SchemaCache::load(&pool_clone).await })??); schemas.insert(key, schema_cache.clone()); diff --git a/postgrestools.jsonc b/postgrestools.jsonc index 47d08c729..3f9a33f5b 100644 --- a/postgrestools.jsonc +++ b/postgrestools.jsonc @@ -12,7 +12,8 @@ "enabled": true, "rules": { "recommended": true - } + }, + "search_path_patterns": ["private", "public"] }, // YOU CAN COMMENT ME OUT :) "db": { diff --git a/test.sql b/test.sql index b21a2e8dc..f45362e77 100644 --- a/test.sql +++ b/test.sql @@ -1,34 +1,21 @@ -create table - unknown_users (id serial primary key, address text, email text); - -drop table unknown_users; - -select - * -from - unknown_users; - -sel 1; - - - -create function test_organisation_id () - returns setof text - language plpgsql - security invoker - as $$ - declre - v_organisation_id uuid; -begin - return next is(private.organisation_id(), v_organisation_id, 'should return organisation_id of token'); -end -$$; - - -create function f1() -returns void as $$ -declare b constant int; -begin - call p1(10, b); +-- create schema private; + +create table if not exists private.something ( + id serial primary key, + arr double precision[] +); + +create or replace function private.head( + arr double precision[] +) returns double precision as $$ +begin + if cardinality(arr) = 0 then + raise exception 'Empty array!'; + else + return arr[0]; + end if; end; $$ language plpgsql; + + +select head (arr) from private.something; \ No newline at end of file From 8151d995dc6a05a19c1e4eb1806953e78b3d5754 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 07:50:09 +0200 Subject: [PATCH 03/14] readied --- docs/schema.json | 11 +++++++++++ .../@postgrestools/backend-jsonrpc/src/workspace.ts | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/docs/schema.json b/docs/schema.json index 1c56618ed..af2b2ac2c 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -223,6 +223,17 @@ "type": "null" } ] + }, + "searchPathPatterns": { + "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"public\", \"app_*\"]. If not specified, defaults to [\"public\"].", + "anyOf": [ + { + "$ref": "#/definitions/StringSet" + }, + { + "type": "null" + } + ] } }, "additionalProperties": false diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index 60680b8ad..ef0480079 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -326,6 +326,10 @@ export interface PartialLinterConfiguration { * List of rules */ rules?: Rules; + /** + * Default search path schemas for type checking. Can be a list of schema names or glob patterns like ["public", "app_*"]. If not specified, defaults to ["public"]. + */ + searchPathPatterns?: StringSet; } /** * The configuration of the filesystem From c0e843031536fa4201deb5a5d650e79e770dd4c8 Mon Sep 17 00:00:00 2001 From: Julian Domke <68325451+juleswritescode@users.noreply.github.com> Date: Sat, 30 Aug 2025 07:56:26 +0200 Subject: [PATCH 04/14] Update crates/pgt_schema_cache/Cargo.toml --- crates/pgt_schema_cache/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/pgt_schema_cache/Cargo.toml b/crates/pgt_schema_cache/Cargo.toml index 9a05ac439..c5fadb3e2 100644 --- a/crates/pgt_schema_cache/Cargo.toml +++ b/crates/pgt_schema_cache/Cargo.toml @@ -23,7 +23,6 @@ sqlx.workspace = true strum = { workspace = true } tokio.workspace = true - [dev-dependencies] pgt_test_utils.workspace = true From 4b6484ac954995d5001b2b52ad87d38a777cb34f Mon Sep 17 00:00:00 2001 From: Julian Domke <68325451+juleswritescode@users.noreply.github.com> Date: Sat, 30 Aug 2025 07:56:38 +0200 Subject: [PATCH 05/14] Update crates/pgt_schema_cache/src/schema_cache.rs --- crates/pgt_schema_cache/src/schema_cache.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/pgt_schema_cache/src/schema_cache.rs b/crates/pgt_schema_cache/src/schema_cache.rs index 53ccd755e..89eddca95 100644 --- a/crates/pgt_schema_cache/src/schema_cache.rs +++ b/crates/pgt_schema_cache/src/schema_cache.rs @@ -89,7 +89,6 @@ impl SchemaCache { .filter(|t| t.name == name && schema.is_none_or(|s| s == t.schema.as_str())) .collect() } - } pub trait SchemaCacheItem { From 693f47c174c2f6f4e6249895c0781b2371c50db1 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 07:59:10 +0200 Subject: [PATCH 06/14] adjusties --- .../src/analyser/linter/mod.rs | 4 +- crates/pgt_schema_cache/src/schema_cache.rs | 1 - crates/pgt_typecheck/Cargo.toml | 2 +- crates/pgt_workspace/src/settings.rs | 22 -------- .../workspace/server/schema_cache_manager.rs | 6 +-- postgrestools.jsonc | 2 +- test.sql | 51 ++++++++++++------- 7 files changed, 39 insertions(+), 49 deletions(-) diff --git a/crates/pgt_configuration/src/analyser/linter/mod.rs b/crates/pgt_configuration/src/analyser/linter/mod.rs index 4a3188637..811e584d8 100644 --- a/crates/pgt_configuration/src/analyser/linter/mod.rs +++ b/crates/pgt_configuration/src/analyser/linter/mod.rs @@ -30,8 +30,8 @@ pub struct LinterConfiguration { pub include: StringSet, /// Default search path schemas for type checking. - /// Can be a list of schema names or glob patterns like ["public", "app_*"]. - /// If not specified, defaults to ["public"]. + /// Can be a list of schema names or glob patterns like ["private", "app_*"]. + /// "public" will always be searched, and it will be searched last. #[partial(bpaf(long("search_path")))] pub search_path_patterns: StringSet, } diff --git a/crates/pgt_schema_cache/src/schema_cache.rs b/crates/pgt_schema_cache/src/schema_cache.rs index 53ccd755e..89eddca95 100644 --- a/crates/pgt_schema_cache/src/schema_cache.rs +++ b/crates/pgt_schema_cache/src/schema_cache.rs @@ -89,7 +89,6 @@ impl SchemaCache { .filter(|t| t.name == name && schema.is_none_or(|s| s == t.schema.as_str())) .collect() } - } pub trait SchemaCacheItem { diff --git a/crates/pgt_typecheck/Cargo.toml b/crates/pgt_typecheck/Cargo.toml index 75c76fa35..16a250aa2 100644 --- a/crates/pgt_typecheck/Cargo.toml +++ b/crates/pgt_typecheck/Cargo.toml @@ -13,6 +13,7 @@ version = "0.0.0" [dependencies] globset = "0.4.16" +itertools = { version = "0.14.0" } pgt_console.workspace = true pgt_diagnostics.workspace = true pgt_query.workspace = true @@ -23,7 +24,6 @@ sqlx.workspace = true tokio.workspace = true tree-sitter.workspace = true tree_sitter_sql.workspace = true -itertools ={ version = "0.14.0" } [dev-dependencies] insta.workspace = true diff --git a/crates/pgt_workspace/src/settings.rs b/crates/pgt_workspace/src/settings.rs index 80be80e8f..38608f012 100644 --- a/crates/pgt_workspace/src/settings.rs +++ b/crates/pgt_workspace/src/settings.rs @@ -394,28 +394,6 @@ pub struct LinterSettings { pub search_path_patterns: Vec, } -impl LinterSettings { - /// Returns schema names that match the configured search path patterns. - /// Supports glob patterns like "app_*" or exact matches. - pub fn get_matching_schemas<'a>(&self, schema_names: &'a [&str]) -> Vec<&'a str> { - schema_names - .iter() - .filter(|&&schema_name| { - self.search_path_patterns.iter().any(|pattern| { - if let Ok(glob) = Glob::new(pattern) { - let matcher = glob.compile_matcher(); - matcher.is_match(schema_name) - } else { - // fallback to exact match if glob pattern is invalid - pattern == schema_name - } - }) - }) - .copied() - .collect() - } -} - impl Default for LinterSettings { fn default() -> Self { Self { diff --git a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs index 7335e3fb6..007ebb782 100644 --- a/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs +++ b/crates/pgt_workspace/src/workspace/server/schema_cache_manager.rs @@ -40,9 +40,9 @@ impl SchemaCacheManager { // Load schema cache let pool_clone = pool.clone(); - let schema_cache = Arc::new(run_async(async move { - SchemaCache::load(&pool_clone).await - })??); + let schema_cache = Arc::new(run_async( + async move { SchemaCache::load(&pool_clone).await }, + )??); schemas.insert(key, schema_cache.clone()); Ok(schema_cache) diff --git a/postgrestools.jsonc b/postgrestools.jsonc index 3f9a33f5b..34062cd4f 100644 --- a/postgrestools.jsonc +++ b/postgrestools.jsonc @@ -13,7 +13,7 @@ "rules": { "recommended": true }, - "search_path_patterns": ["private", "public"] + "searchPathPatterns": ["pr*"] }, // YOU CAN COMMENT ME OUT :) "db": { diff --git a/test.sql b/test.sql index f45362e77..b21a2e8dc 100644 --- a/test.sql +++ b/test.sql @@ -1,21 +1,34 @@ --- create schema private; - -create table if not exists private.something ( - id serial primary key, - arr double precision[] -); - -create or replace function private.head( - arr double precision[] -) returns double precision as $$ -begin - if cardinality(arr) = 0 then - raise exception 'Empty array!'; - else - return arr[0]; - end if; -end; -$$ language plpgsql; +create table + unknown_users (id serial primary key, address text, email text); + +drop table unknown_users; + +select + * +from + unknown_users; + +sel 1; -select head (arr) from private.something; \ No newline at end of file + +create function test_organisation_id () + returns setof text + language plpgsql + security invoker + as $$ + declre + v_organisation_id uuid; +begin + return next is(private.organisation_id(), v_organisation_id, 'should return organisation_id of token'); +end +$$; + + +create function f1() +returns void as $$ +declare b constant int; +begin + call p1(10, b); +end; +$$ language plpgsql; From 343e1fc4305a3dfca1fff30e489ddb9d95115ee7 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 07:59:53 +0200 Subject: [PATCH 07/14] ok --- docs/schema.json | 2 +- packages/@postgrestools/backend-jsonrpc/src/workspace.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/schema.json b/docs/schema.json index af2b2ac2c..9f75c5859 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -225,7 +225,7 @@ ] }, "searchPathPatterns": { - "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"public\", \"app_*\"]. If not specified, defaults to [\"public\"].", + "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"private\", \"app_*\"]. \"public\" will always be searched, and it will be searched last.", "anyOf": [ { "$ref": "#/definitions/StringSet" diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index ef0480079..3873a380a 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -327,7 +327,7 @@ export interface PartialLinterConfiguration { */ rules?: Rules; /** - * Default search path schemas for type checking. Can be a list of schema names or glob patterns like ["public", "app_*"]. If not specified, defaults to ["public"]. + * Default search path schemas for type checking. Can be a list of schema names or glob patterns like ["private", "app_*"]. "public" will always be searched, and it will be searched last. */ searchPathPatterns?: StringSet; } From da29662e0122feed72fd160e21996bbe5dcf07f1 Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 08:01:40 +0200 Subject: [PATCH 08/14] format --- crates/pgt_typecheck/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/pgt_typecheck/src/lib.rs b/crates/pgt_typecheck/src/lib.rs index e4fc7e59a..854cdfadc 100644 --- a/crates/pgt_typecheck/src/lib.rs +++ b/crates/pgt_typecheck/src/lib.rs @@ -84,10 +84,7 @@ pub async fn check_sql( } } -fn get_schemas_in_search_path<'a>( - schema_cache: &'a SchemaCache, - glob_patterns: Vec, -) -> Vec<&'a str> { +fn get_schemas_in_search_path(schema_cache: &SchemaCache, glob_patterns: Vec) -> Vec<&str> { // iterate over glob_patterns on the outside to keep the order glob_patterns .iter() From 2d4257482afbd4cf4e0fd2fd7b8baddb6329753b Mon Sep 17 00:00:00 2001 From: Julian Date: Sat, 30 Aug 2025 08:12:41 +0200 Subject: [PATCH 09/14] add a test like a grown up --- .../src/workspace/server.tests.rs | 114 +++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/crates/pgt_workspace/src/workspace/server.tests.rs b/crates/pgt_workspace/src/workspace/server.tests.rs index 894d10426..df4f7fe5a 100644 --- a/crates/pgt_workspace/src/workspace/server.tests.rs +++ b/crates/pgt_workspace/src/workspace/server.tests.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use biome_deserialize::{Merge, StringSet}; use pgt_analyse::RuleCategories; use pgt_configuration::{ - PartialConfiguration, database::PartialDatabaseConfiguration, files::PartialFilesConfiguration, + PartialConfiguration, PartialLinterConfiguration, database::PartialDatabaseConfiguration, + files::PartialFilesConfiguration, }; use pgt_diagnostics::Diagnostic; use pgt_fs::PgTPath; @@ -331,3 +332,114 @@ async fn test_positional_params(test_db: PgPool) { assert_eq!(diagnostics.len(), 0, "Expected no diagnostic"); } + +#[sqlx::test(migrator = "pgt_test_utils::MIGRATIONS")] +async fn test_search_path_configuration(test_db: PgPool) { + // Setup test schemas and functions + let setup_sql = r#" + create schema if not exists private; + + create or replace function private.get_user_id() returns integer as $$ + select 1; + $$ language sql; + "#; + test_db.execute(setup_sql).await.expect("setup sql failed"); + + let path_glob = PgTPath::new("test_glob.sql"); + let file_content = r#" + select get_user_id(); -- on private schema + "#; + + // first check that the we get a valid typecheck + let mut glob_conf = PartialConfiguration::init(); + glob_conf.merge_with(PartialConfiguration { + db: Some(PartialDatabaseConfiguration { + database: Some( + test_db + .connect_options() + .get_database() + .unwrap() + .to_string(), + ), + ..Default::default() + }), + ..Default::default() + }); + + // without glob + { + let workspace = + get_test_workspace(Some(glob_conf.clone())).expect("Unable to create test workspace"); + + workspace + .open_file(OpenFileParams { + path: path_glob.clone(), + content: file_content.into(), + version: 1, + }) + .expect("Unable to open test file"); + + let diagnostics_glob = workspace + .pull_diagnostics(crate::workspace::PullDiagnosticsParams { + path: path_glob.clone(), + categories: RuleCategories::all(), + max_diagnostics: 100, + only: vec![], + skip: vec![], + }) + .expect("Unable to pull diagnostics") + .diagnostics; + + assert_eq!( + diagnostics_glob.len(), + 1, + "get_user_id() should not be found in search_path" + ); + + // yep, type error! + assert_eq!( + diagnostics_glob[0].category().map(|c| c.name()), + Some("typecheck") + ); + } + + // adding the glob + glob_conf.merge_with(PartialConfiguration { + linter: Some(PartialLinterConfiguration { + // Adding glob pattern to match the "private" schema + search_path_patterns: Some(StringSet::from_iter(vec!["pr*".to_string()])), + ..Default::default() + }), + ..Default::default() + }); // checking with the pattern should yield no diagnostics + + { + let workspace = + get_test_workspace(Some(glob_conf.clone())).expect("Unable to create test workspace"); + + workspace + .open_file(OpenFileParams { + path: path_glob.clone(), + content: file_content.into(), + version: 1, + }) + .expect("Unable to open test file"); + + let diagnostics_glob = workspace + .pull_diagnostics(crate::workspace::PullDiagnosticsParams { + path: path_glob.clone(), + categories: RuleCategories::all(), + max_diagnostics: 100, + only: vec![], + skip: vec![], + }) + .expect("Unable to pull diagnostics") + .diagnostics; + + assert_eq!( + diagnostics_glob.len(), + 0, + "Glob pattern should put private schema in search path" + ); + } +} From ccde6e7ebd111c97497947c1661cb13b5b447566 Mon Sep 17 00:00:00 2001 From: Julian Domke <68325451+juleswritescode@users.noreply.github.com> Date: Sat, 30 Aug 2025 08:16:31 +0200 Subject: [PATCH 10/14] Update postgrestools.jsonc --- postgrestools.jsonc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/postgrestools.jsonc b/postgrestools.jsonc index 34062cd4f..47d08c729 100644 --- a/postgrestools.jsonc +++ b/postgrestools.jsonc @@ -12,8 +12,7 @@ "enabled": true, "rules": { "recommended": true - }, - "searchPathPatterns": ["pr*"] + } }, // YOU CAN COMMENT ME OUT :) "db": { From 34640032f2568ced2e266e710649e11e99d4a21d Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 31 Aug 2025 14:39:29 +0200 Subject: [PATCH 11/14] move to typecheck --- .../src/analyser/linter/mod.rs | 7 ---- crates/pgt_configuration/src/lib.rs | 14 ++++++++ crates/pgt_configuration/src/typecheck.rs | 31 ++++++++++++++++ crates/pgt_workspace/src/settings.rs | 36 +++++++++++++++---- crates/pgt_workspace/src/workspace/server.rs | 2 +- .../src/workspace/server.tests.rs | 6 ++-- docs/schema.json | 24 +++++++++++-- 7 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 crates/pgt_configuration/src/typecheck.rs diff --git a/crates/pgt_configuration/src/analyser/linter/mod.rs b/crates/pgt_configuration/src/analyser/linter/mod.rs index 811e584d8..20535a2e7 100644 --- a/crates/pgt_configuration/src/analyser/linter/mod.rs +++ b/crates/pgt_configuration/src/analyser/linter/mod.rs @@ -28,12 +28,6 @@ pub struct LinterConfiguration { /// match these patterns. #[partial(bpaf(hide))] pub include: StringSet, - - /// Default search path schemas for type checking. - /// Can be a list of schema names or glob patterns like ["private", "app_*"]. - /// "public" will always be searched, and it will be searched last. - #[partial(bpaf(long("search_path")))] - pub search_path_patterns: StringSet, } impl LinterConfiguration { @@ -49,7 +43,6 @@ impl Default for LinterConfiguration { rules: Default::default(), ignore: Default::default(), include: Default::default(), - search_path_patterns: ["public".to_string()].into_iter().collect(), } } } diff --git a/crates/pgt_configuration/src/lib.rs b/crates/pgt_configuration/src/lib.rs index b862dce4f..cce9e5331 100644 --- a/crates/pgt_configuration/src/lib.rs +++ b/crates/pgt_configuration/src/lib.rs @@ -9,6 +9,7 @@ pub mod diagnostics; pub mod files; pub mod generated; pub mod migrations; +pub mod typecheck; pub mod vcs; pub use crate::diagnostics::ConfigurationDiagnostic; @@ -22,6 +23,9 @@ pub use analyser::{ RulePlainConfiguration, RuleSelector, RuleWithFixOptions, RuleWithOptions, Rules, partial_linter_configuration, }; +pub use typecheck::{ + TypecheckConfiguration, PartialTypecheckConfiguration, partial_typecheck_configuration, +}; use biome_deserialize::StringSet; use biome_deserialize_macros::{Merge, Partial}; use bpaf::Bpaf; @@ -33,6 +37,9 @@ use migrations::{ MigrationsConfiguration, PartialMigrationsConfiguration, partial_migrations_configuration, }; use serde::{Deserialize, Serialize}; +use typecheck::{ + TypecheckConfiguration, PartialTypecheckConfiguration, partial_typecheck_configuration, +}; use vcs::VcsClientKind; pub const VERSION: &str = match option_env!("PGT_VERSION") { @@ -77,6 +84,10 @@ pub struct Configuration { #[partial(type, bpaf(external(partial_linter_configuration), optional))] pub linter: LinterConfiguration, + /// The configuration for type checking + #[partial(type, bpaf(external(partial_typecheck_configuration), optional))] + pub typecheck: TypecheckConfiguration, + /// The configuration of the database connection #[partial( type, @@ -110,6 +121,9 @@ impl PartialConfiguration { }), ..Default::default() }), + typecheck: Some(PartialTypecheckConfiguration { + ..Default::default() + }), db: Some(PartialDatabaseConfiguration { host: Some("127.0.0.1".to_string()), port: Some(5432), diff --git a/crates/pgt_configuration/src/typecheck.rs b/crates/pgt_configuration/src/typecheck.rs new file mode 100644 index 000000000..70d4c168e --- /dev/null +++ b/crates/pgt_configuration/src/typecheck.rs @@ -0,0 +1,31 @@ +use biome_deserialize::StringSet; +use biome_deserialize_macros::{Merge, Partial}; +use bpaf::Bpaf; +use serde::{Deserialize, Serialize}; + +/// The configuration for type checking. +#[derive(Clone, Debug, Deserialize, Eq, Partial, PartialEq, Serialize)] +#[partial(derive(Bpaf, Clone, Eq, PartialEq, Merge))] +#[partial(cfg_attr(feature = "schema", derive(schemars::JsonSchema)))] +#[partial(serde(rename_all = "camelCase", default, deny_unknown_fields))] +pub struct TypecheckConfiguration { + /// Default search path schemas for type checking. + /// Can be a list of schema names or glob patterns like ["public", "app_*"]. + /// If not specified, defaults to ["public"]. + #[partial(bpaf(long("search_path")))] + pub search_path: StringSet, +} + +impl Default for TypecheckConfiguration { + fn default() -> Self { + Self { + search_path: ["public".to_string()].into_iter().collect(), + } + } +} + +pub const fn partial_typecheck_configuration() -> PartialTypecheckConfiguration { + PartialTypecheckConfiguration { + search_path: None, + } +} \ No newline at end of file diff --git a/crates/pgt_workspace/src/settings.rs b/crates/pgt_workspace/src/settings.rs index 38608f012..5561625d4 100644 --- a/crates/pgt_workspace/src/settings.rs +++ b/crates/pgt_workspace/src/settings.rs @@ -12,7 +12,7 @@ use tracing::trace; use ignore::gitignore::{Gitignore, GitignoreBuilder}; use pgt_configuration::{ - ConfigurationDiagnostic, LinterConfiguration, PartialConfiguration, + ConfigurationDiagnostic, LinterConfiguration, PartialConfiguration, TypecheckConfiguration, database::PartialDatabaseConfiguration, diagnostics::InvalidIgnorePattern, files::FilesConfiguration, @@ -210,6 +210,9 @@ pub struct Settings { /// Linter settings applied to all files in the workspace pub linter: LinterSettings, + /// Type checking settings for the workspace + pub typecheck: TypecheckSettings, + /// Migrations settings pub migrations: Option, } @@ -245,6 +248,11 @@ impl Settings { to_linter_settings(working_directory.clone(), LinterConfiguration::from(linter))?; } + // typecheck part + if let Some(typecheck) = configuration.typecheck { + self.typecheck = to_typecheck_settings(TypecheckConfiguration::from(typecheck)); + } + // Migrations settings if let Some(migrations) = configuration.migrations { self.migrations = to_migration_settings( @@ -291,10 +299,15 @@ fn to_linter_settings( rules: Some(conf.rules), ignored_files: to_matcher(working_directory.clone(), Some(&conf.ignore))?, included_files: to_matcher(working_directory.clone(), Some(&conf.include))?, - search_path_patterns: conf.search_path_patterns.into_iter().collect(), }) } +fn to_typecheck_settings(conf: TypecheckConfiguration) -> TypecheckSettings { + TypecheckSettings { + search_path: conf.search_path.into_iter().collect(), + } +} + fn to_file_settings( working_directory: Option, config: Option, @@ -389,9 +402,6 @@ pub struct LinterSettings { /// List of included paths/files to match pub included_files: Matcher, - - /// Glob patterns for additional schemas to check when typechecking - pub search_path_patterns: Vec, } impl Default for LinterSettings { @@ -401,7 +411,21 @@ impl Default for LinterSettings { rules: Some(pgt_configuration::analyser::linter::Rules::default()), ignored_files: Matcher::empty(), included_files: Matcher::empty(), - search_path_patterns: vec!["public".to_string()], + } + } +} + +/// Type checking settings for the entire workspace +#[derive(Debug)] +pub struct TypecheckSettings { + /// Default search path schemas for type checking + pub search_path: Vec, +} + +impl Default for TypecheckSettings { + fn default() -> Self { + Self { + search_path: vec!["public".to_string()], } } } diff --git a/crates/pgt_workspace/src/workspace/server.rs b/crates/pgt_workspace/src/workspace/server.rs index fd0880ad3..7a4abbdfb 100644 --- a/crates/pgt_workspace/src/workspace/server.rs +++ b/crates/pgt_workspace/src/workspace/server.rs @@ -455,7 +455,7 @@ impl Workspace for WorkspaceServer { let path_clone = params.path.clone(); let schema_cache = self.schema_cache.load(pool.clone())?; let input = doc.iter(TypecheckDiagnosticsMapper).collect::>(); - let search_path_patterns = settings.linter.search_path_patterns.clone(); + let search_path_patterns = settings.typecheck.search_path.clone(); // Combined async context for both typecheck and plpgsql_check let async_results = run_async(async move { diff --git a/crates/pgt_workspace/src/workspace/server.tests.rs b/crates/pgt_workspace/src/workspace/server.tests.rs index df4f7fe5a..d881df15a 100644 --- a/crates/pgt_workspace/src/workspace/server.tests.rs +++ b/crates/pgt_workspace/src/workspace/server.tests.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use biome_deserialize::{Merge, StringSet}; use pgt_analyse::RuleCategories; use pgt_configuration::{ - PartialConfiguration, PartialLinterConfiguration, database::PartialDatabaseConfiguration, + PartialConfiguration, PartialLinterConfiguration, PartialTypecheckConfiguration, database::PartialDatabaseConfiguration, files::PartialFilesConfiguration, }; use pgt_diagnostics::Diagnostic; @@ -405,9 +405,9 @@ async fn test_search_path_configuration(test_db: PgPool) { // adding the glob glob_conf.merge_with(PartialConfiguration { - linter: Some(PartialLinterConfiguration { + typecheck: Some(PartialTypecheckConfiguration { // Adding glob pattern to match the "private" schema - search_path_patterns: Some(StringSet::from_iter(vec!["pr*".to_string()])), + search_path: Some(StringSet::from_iter(vec!["pr*".to_string()])), ..Default::default() }), ..Default::default() diff --git a/docs/schema.json b/docs/schema.json index 9f75c5859..dec41197a 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -55,6 +55,17 @@ } ] }, + "typecheck": { + "description": "The configuration for type checking", + "anyOf": [ + { + "$ref": "#/definitions/TypecheckConfiguration" + }, + { + "type": "null" + } + ] + }, "migrations": { "description": "Configure migrations", "anyOf": [ @@ -223,9 +234,16 @@ "type": "null" } ] - }, - "searchPathPatterns": { - "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"private\", \"app_*\"]. \"public\" will always be searched, and it will be searched last.", + } + }, + "additionalProperties": false + }, + "TypecheckConfiguration": { + "description": "The configuration for type checking.", + "type": "object", + "properties": { + "searchPath": { + "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"public\", \"app_*\"]. If not specified, defaults to [\"public\"].", "anyOf": [ { "$ref": "#/definitions/StringSet" From 7064fed269cc39b4b88eadeed9e24e823ae1c049 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 31 Aug 2025 14:44:28 +0200 Subject: [PATCH 12/14] progress --- crates/pgt_configuration/src/lib.rs | 7 ++----- crates/pgt_configuration/src/typecheck.rs | 6 ------ crates/pgt_workspace/src/workspace/server.tests.rs | 4 ++-- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/crates/pgt_configuration/src/lib.rs b/crates/pgt_configuration/src/lib.rs index cce9e5331..2b8db6528 100644 --- a/crates/pgt_configuration/src/lib.rs +++ b/crates/pgt_configuration/src/lib.rs @@ -23,9 +23,6 @@ pub use analyser::{ RulePlainConfiguration, RuleSelector, RuleWithFixOptions, RuleWithOptions, Rules, partial_linter_configuration, }; -pub use typecheck::{ - TypecheckConfiguration, PartialTypecheckConfiguration, partial_typecheck_configuration, -}; use biome_deserialize::StringSet; use biome_deserialize_macros::{Merge, Partial}; use bpaf::Bpaf; @@ -37,8 +34,8 @@ use migrations::{ MigrationsConfiguration, PartialMigrationsConfiguration, partial_migrations_configuration, }; use serde::{Deserialize, Serialize}; -use typecheck::{ - TypecheckConfiguration, PartialTypecheckConfiguration, partial_typecheck_configuration, +pub use typecheck::{ + PartialTypecheckConfiguration, TypecheckConfiguration, partial_typecheck_configuration, }; use vcs::VcsClientKind; diff --git a/crates/pgt_configuration/src/typecheck.rs b/crates/pgt_configuration/src/typecheck.rs index 70d4c168e..32c39377d 100644 --- a/crates/pgt_configuration/src/typecheck.rs +++ b/crates/pgt_configuration/src/typecheck.rs @@ -23,9 +23,3 @@ impl Default for TypecheckConfiguration { } } } - -pub const fn partial_typecheck_configuration() -> PartialTypecheckConfiguration { - PartialTypecheckConfiguration { - search_path: None, - } -} \ No newline at end of file diff --git a/crates/pgt_workspace/src/workspace/server.tests.rs b/crates/pgt_workspace/src/workspace/server.tests.rs index d881df15a..d90a987fe 100644 --- a/crates/pgt_workspace/src/workspace/server.tests.rs +++ b/crates/pgt_workspace/src/workspace/server.tests.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use biome_deserialize::{Merge, StringSet}; use pgt_analyse::RuleCategories; use pgt_configuration::{ - PartialConfiguration, PartialLinterConfiguration, PartialTypecheckConfiguration, database::PartialDatabaseConfiguration, - files::PartialFilesConfiguration, + PartialConfiguration, PartialLinterConfiguration, PartialTypecheckConfiguration, + database::PartialDatabaseConfiguration, files::PartialFilesConfiguration, }; use pgt_diagnostics::Diagnostic; use pgt_fs::PgTPath; From c47436de818d68a2dc7949f46219715e9ae21111 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 31 Aug 2025 14:44:55 +0200 Subject: [PATCH 13/14] just readied --- docs/schema.json | 48 +++++++++---------- .../backend-jsonrpc/src/workspace.ts | 17 +++++-- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/docs/schema.json b/docs/schema.json index dec41197a..e0abf20aa 100644 --- a/docs/schema.json +++ b/docs/schema.json @@ -55,22 +55,22 @@ } ] }, - "typecheck": { - "description": "The configuration for type checking", + "migrations": { + "description": "Configure migrations", "anyOf": [ { - "$ref": "#/definitions/TypecheckConfiguration" + "$ref": "#/definitions/MigrationsConfiguration" }, { "type": "null" } ] }, - "migrations": { - "description": "Configure migrations", + "typecheck": { + "description": "The configuration for type checking", "anyOf": [ { - "$ref": "#/definitions/MigrationsConfiguration" + "$ref": "#/definitions/TypecheckConfiguration" }, { "type": "null" @@ -238,24 +238,6 @@ }, "additionalProperties": false }, - "TypecheckConfiguration": { - "description": "The configuration for type checking.", - "type": "object", - "properties": { - "searchPath": { - "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"public\", \"app_*\"]. If not specified, defaults to [\"public\"].", - "anyOf": [ - { - "$ref": "#/definitions/StringSet" - }, - { - "type": "null" - } - ] - } - }, - "additionalProperties": false - }, "MigrationsConfiguration": { "description": "The configuration of the filesystem", "type": "object", @@ -439,6 +421,24 @@ }, "uniqueItems": true }, + "TypecheckConfiguration": { + "description": "The configuration for type checking.", + "type": "object", + "properties": { + "searchPath": { + "description": "Default search path schemas for type checking. Can be a list of schema names or glob patterns like [\"public\", \"app_*\"]. If not specified, defaults to [\"public\"].", + "anyOf": [ + { + "$ref": "#/definitions/StringSet" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, "VcsClientKind": { "oneOf": [ { diff --git a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts index 3873a380a..a8ea3e9f8 100644 --- a/packages/@postgrestools/backend-jsonrpc/src/workspace.ts +++ b/packages/@postgrestools/backend-jsonrpc/src/workspace.ts @@ -256,6 +256,10 @@ export interface PartialConfiguration { * Configure migrations */ migrations?: PartialMigrationsConfiguration; + /** + * The configuration for type checking + */ + typecheck?: PartialTypecheckConfiguration; /** * The configuration of the VCS integration */ @@ -326,10 +330,6 @@ export interface PartialLinterConfiguration { * List of rules */ rules?: Rules; - /** - * Default search path schemas for type checking. Can be a list of schema names or glob patterns like ["private", "app_*"]. "public" will always be searched, and it will be searched last. - */ - searchPathPatterns?: StringSet; } /** * The configuration of the filesystem @@ -344,6 +344,15 @@ export interface PartialMigrationsConfiguration { */ migrationsDir?: string; } +/** + * The configuration for type checking. + */ +export interface PartialTypecheckConfiguration { + /** + * Default search path schemas for type checking. Can be a list of schema names or glob patterns like ["public", "app_*"]. If not specified, defaults to ["public"]. + */ + searchPath?: StringSet; +} /** * Set of properties to integrate with a VCS software. */ From 4c8be334808e326157f4eb85d85fbcccbd981f01 Mon Sep 17 00:00:00 2001 From: Julian Date: Sun, 31 Aug 2025 14:45:54 +0200 Subject: [PATCH 14/14] remove unnecessary --- crates/pgt_workspace/src/workspace/server.tests.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/pgt_workspace/src/workspace/server.tests.rs b/crates/pgt_workspace/src/workspace/server.tests.rs index d90a987fe..f1b3810cc 100644 --- a/crates/pgt_workspace/src/workspace/server.tests.rs +++ b/crates/pgt_workspace/src/workspace/server.tests.rs @@ -3,8 +3,8 @@ use std::sync::Arc; use biome_deserialize::{Merge, StringSet}; use pgt_analyse::RuleCategories; use pgt_configuration::{ - PartialConfiguration, PartialLinterConfiguration, PartialTypecheckConfiguration, - database::PartialDatabaseConfiguration, files::PartialFilesConfiguration, + PartialConfiguration, PartialTypecheckConfiguration, database::PartialDatabaseConfiguration, + files::PartialFilesConfiguration, }; use pgt_diagnostics::Diagnostic; use pgt_fs::PgTPath; @@ -408,7 +408,6 @@ async fn test_search_path_configuration(test_db: PgPool) { typecheck: Some(PartialTypecheckConfiguration { // Adding glob pattern to match the "private" schema search_path: Some(StringSet::from_iter(vec!["pr*".to_string()])), - ..Default::default() }), ..Default::default() }); // checking with the pattern should yield no diagnostics