Skip to content

Commit 404a683

Browse files
committed
refactor: move env var config to ServerFactory/Session lifecycle
Env config is computed once at ServerFactory creation and threaded through to Session, which merges it as the highest-priority layer during config loading. Tests use ServerFactory::default() which provides None, avoiding DATABASE_URL interference from sqlx::test.
1 parent 0012818 commit 404a683

2 files changed

Lines changed: 24 additions & 7 deletions

File tree

crates/pgls_lsp/src/server.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::session::{
66
use crate::utils::{into_lsp_error, panic_to_lsp_error};
77
use futures::FutureExt;
88
use futures::future::ready;
9+
use pgls_configuration::database::PartialDatabaseConfiguration;
910
use pgls_fs::{ConfigName, FileSystem, OsFileSystem};
1011
use pgls_workspace::workspace::{RegisterProjectFolderParams, UnregisterProjectFolderParams};
1112
use pgls_workspace::{DynRef, Workspace, workspace};
@@ -92,6 +93,7 @@ impl LSPServer {
9293

9394
self.session.register_capabilities(capabilities).await;
9495
}
96+
9597
}
9698

9799
#[tower_lsp::async_trait]
@@ -162,8 +164,10 @@ impl LanguageServer for LSPServer {
162164

163165
#[tracing::instrument(level = "info", skip_all)]
164166
async fn did_change_configuration(&self, params: DidChangeConfigurationParams) {
167+
let extra_config: Option<pgls_configuration::PartialConfiguration> =
168+
serde_json::from_value(params.settings).ok();
165169
self.session
166-
.load_workspace_settings(serde_json::from_value(params.settings).ok())
170+
.load_workspace_settings(extra_config)
167171
.await;
168172
self.setup_capabilities().await;
169173
self.session.update_all_diagnostics().await;
@@ -410,17 +414,26 @@ pub struct ServerFactory {
410414
/// This shared flag is set to true once at least one sessions has been
411415
/// initialized on this server instance
412416
is_initialized: Arc<AtomicBool>,
417+
/// Configuration from environment variables (DATABASE_URL, PGHOST, etc.).
418+
/// Computed once at factory creation and passed to each session.
419+
env_config: Option<pgls_configuration::PartialConfiguration>,
413420
}
414421

415422
impl ServerFactory {
416423
pub fn new(stop_on_disconnect: bool) -> Self {
424+
let env_config =
425+
PartialDatabaseConfiguration::from_env().map(|db| pgls_configuration::PartialConfiguration {
426+
db: Some(db),
427+
..Default::default()
428+
});
417429
Self {
418430
cancellation: Arc::default(),
419431
workspace: None,
420432
sessions: Sessions::default(),
421433
next_session_key: AtomicU64::new(0),
422434
stop_on_disconnect,
423435
is_initialized: Arc::default(),
436+
env_config,
424437
}
425438
}
426439

@@ -441,13 +454,15 @@ impl ServerFactory {
441454

442455
let session_key = SessionKey(self.next_session_key.fetch_add(1, Ordering::Relaxed));
443456

457+
let env_config = self.env_config.clone();
444458
let mut builder = LspService::build(move |client| {
445459
let mut session = Session::new(
446460
session_key,
447461
client,
448462
workspace,
449463
self.cancellation.clone(),
450464
fs,
465+
env_config,
451466
);
452467
if let Some(path) = config_path {
453468
session.set_config_path(path);

crates/pgls_lsp/src/session.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use biome_deserialize::Merge;
77
use futures::StreamExt;
88
use futures::stream::FuturesUnordered;
99
use pgls_analyse::RuleCategoriesBuilder;
10-
use pgls_configuration::database::PartialDatabaseConfiguration;
1110
use pgls_configuration::{ConfigurationPathHint, PartialConfiguration};
1211
use pgls_diagnostics::{DiagnosticExt, Error};
1312
use pgls_fs::{ConfigName, FileSystem, PgLSPath};
@@ -76,6 +75,9 @@ pub(crate) struct Session {
7675
pub(crate) cancellation: Arc<Notify>,
7776

7877
pub(crate) config_path: Option<PathBuf>,
78+
79+
/// Extra configuration from environment variables, applied on every config load.
80+
env_config: Option<PartialConfiguration>,
7981
}
8082

8183
/// The parameters provided by the client in the "initialize" request
@@ -156,6 +158,7 @@ impl Session {
156158
workspace: Arc<dyn Workspace>,
157159
cancellation: Arc<Notify>,
158160
fs: DynRef<'static, dyn FileSystem>,
161+
env_config: Option<PartialConfiguration>,
159162
) -> Self {
160163
let documents = Default::default();
161164
Self {
@@ -170,6 +173,7 @@ impl Session {
170173
config_path: None,
171174
notified_broken_configuration: AtomicBool::new(false),
172175
notified_deprecated_config: AtomicBool::new(false),
176+
env_config,
173177
}
174178
}
175179

@@ -500,11 +504,9 @@ impl Session {
500504
fs_configuration.merge_with(ws_configuration);
501505
}
502506

503-
if let Some(env_db) = PartialDatabaseConfiguration::from_env() {
504-
match &mut fs_configuration.db {
505-
Some(db) => db.merge_with(env_db),
506-
None => fs_configuration.db = Some(env_db),
507-
}
507+
// Env vars take highest priority — merge last so they override everything.
508+
if let Some(env_config) = &self.env_config {
509+
fs_configuration.merge_with(env_config.clone());
508510
}
509511

510512
let result = fs_configuration

0 commit comments

Comments
 (0)