Skip to content

Commit d994149

Browse files
authored
Merge pull request #148 from juleswritescode/pglsp/workspace-configuration
2 parents ab3712d + d17f1da commit d994149

File tree

6 files changed

+106
-73
lines changed

6 files changed

+106
-73
lines changed
Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
use serde::Deserialize;
22

3-
// TODO: Check that the Opts are correct (existed in server.rs)
4-
#[derive(Deserialize)]
3+
#[derive(Deserialize, Debug)]
54
pub struct ClientConfigurationOptions {
6-
pub db_connection_string: Option<String>,
5+
#[serde(rename(deserialize = "databaseUrl"))]
6+
pub(crate) db_connection_string: Option<String>,
7+
}
8+
9+
#[cfg(test)]
10+
mod tests {
11+
use serde_json::json;
12+
13+
use crate::client::client_config_opts::ClientConfigurationOptions;
14+
15+
#[test]
16+
fn test_json_parsing() {
17+
let config = json!({
18+
"databaseUrl": "cool-shit"
19+
});
20+
21+
let parsed: ClientConfigurationOptions = serde_json::from_value(config).unwrap();
22+
23+
assert_eq!(parsed.db_connection_string, Some("cool-shit".into()));
24+
}
725
}

crates/pg_lsp/src/db_connection.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,20 @@ pub(crate) struct DbConnection {
1313
}
1414

1515
impl DbConnection {
16+
#[tracing::instrument(name = "Setting up new Database Connection…", skip(ide))]
1617
pub(crate) async fn new(
1718
connection_string: String,
1819
ide: Arc<RwLock<Workspace>>,
1920
) -> Result<Self, sqlx::Error> {
21+
tracing::info!("Trying to connect to pool…");
2022
let pool = PgPool::connect(&connection_string).await?;
23+
tracing::info!("Connected to Pool.");
2124

2225
let mut listener = PgListener::connect_with(&pool).await?;
26+
tracing::info!("Connected to Listener.");
27+
2328
listener.listen_all(["postgres_lsp", "pgrst"]).await?;
29+
tracing::info!("Listening!");
2430

2531
let (close_tx, close_rx) = tokio::sync::oneshot::channel::<()>();
2632

@@ -52,6 +58,7 @@ impl DbConnection {
5258
}
5359
}
5460
});
61+
tracing::info!("Set up schema update handle.");
5562

5663
Ok(Self {
5764
pool,

crates/pg_lsp/src/server.rs

Lines changed: 66 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -66,40 +66,72 @@ impl LspServer {
6666
}
6767
}
6868

69-
#[tracing::instrument(name = "Requesting Configuration from Client", skip(self))]
70-
async fn request_config_from_client(&self) -> Option<ClientConfigurationOptions> {
71-
let params = ConfigurationParams {
72-
items: vec![ConfigurationItem {
73-
section: Some("pglsp".to_string()),
74-
scope_uri: None,
75-
}],
69+
#[tracing::instrument(name = "Processing Config", skip(self))]
70+
async fn process_config(&self, opts: Option<ClientConfigurationOptions>) -> anyhow::Result<()> {
71+
if opts
72+
.as_ref()
73+
.is_some_and(|o| o.db_connection_string.is_some())
74+
{
75+
let conn_str = opts.unwrap().db_connection_string.unwrap();
76+
self.session.change_db(conn_str).await
77+
} else {
78+
Ok(())
79+
}
80+
}
81+
82+
async fn parse_and_handle_config_from_client(&self, value: serde_json::Value) {
83+
let parsed = self.parse_config_from_client(value).await;
84+
match self.process_config(parsed).await {
85+
Ok(_) => {}
86+
Err(e) => {
87+
self.client
88+
.show_message(
89+
MessageType::ERROR,
90+
format!("Unable to parse received config: {e:?}"),
91+
)
92+
.await;
93+
}
7694
};
95+
}
96+
97+
#[tracing::instrument(name = "Requesting & Handling Configuration from Client", skip(self))]
98+
async fn request_and_handle_config_from_client(&self) {
99+
let config_items = vec![ConfigurationItem {
100+
section: Some("pglsp".to_string()),
101+
scope_uri: None,
102+
}];
77103

78104
tracing::info!("sending workspace/configuration request");
79-
match self
80-
.client
81-
.send_request::<request::WorkspaceConfiguration>(params)
82-
.await
83-
{
105+
let config = match self.client.configuration(config_items).await {
84106
Ok(json) => {
85107
// The client reponse fits the requested `ConfigurationParams.items`,
86108
// so the first value is what we're looking for.
87-
let relevant = json
88-
.into_iter()
109+
json.into_iter()
89110
.next()
90-
.expect("workspace/configuration request did not yield expected response.");
91-
92-
self.parse_config_from_client(relevant).await
111+
.expect("workspace/configuration request did not yield expected response.")
93112
}
94113
Err(why) => {
95114
let message = format!(
96115
"Unable to pull client options via workspace/configuration request: {}",
97116
why
98117
);
99118
self.client.log_message(MessageType::ERROR, message).await;
100-
None
119+
return;
101120
}
102-
}
121+
};
122+
123+
let parsed = self.parse_config_from_client(config).await;
124+
match self.process_config(parsed).await {
125+
Ok(()) => {}
126+
Err(e) => {
127+
self.client
128+
.log_message(
129+
MessageType::ERROR,
130+
format!("Unable to process config from client: {e:?}"),
131+
)
132+
.await
133+
}
134+
};
103135
}
104136

105137
#[tracing::instrument(
@@ -185,7 +217,11 @@ impl LanguageServer for LspServer {
185217
self.client
186218
.show_message(MessageType::INFO, "Initialize Request received")
187219
.await;
220+
188221
let flags = ClientFlags::from_initialize_request_params(&params);
222+
223+
tracing::info!("flags: {:?}", flags);
224+
189225
self.client_capabilities.write().await.replace(flags);
190226

191227
Ok(InitializeResult {
@@ -220,6 +256,12 @@ impl LanguageServer for LspServer {
220256

221257
#[tracing::instrument(name = "initialized", skip(self, _params))]
222258
async fn initialized(&self, _params: InitializedParams) {
259+
let capabilities = self.client_capabilities.read().await;
260+
261+
if capabilities.as_ref().unwrap().supports_pull_opts {
262+
self.request_and_handle_config_from_client().await;
263+
}
264+
223265
self.client
224266
.log_message(MessageType::INFO, "Postgres LSP Connected!")
225267
.await;
@@ -245,51 +287,11 @@ impl LanguageServer for LspServer {
245287
let capabilities = self.client_capabilities.read().await;
246288

247289
if capabilities.as_ref().unwrap().supports_pull_opts {
248-
let opts = self.request_config_from_client().await;
249-
if opts
250-
.as_ref()
251-
.is_some_and(|o| o.db_connection_string.is_some())
252-
{
253-
let conn_str = opts.unwrap().db_connection_string.unwrap();
254-
match self.session.change_db(conn_str).await {
255-
Ok(_) => {}
256-
Err(err) => {
257-
self.client
258-
.show_message(
259-
MessageType::ERROR,
260-
format!("Pulled Client Options but failed to set them: {}", err),
261-
)
262-
.await
263-
}
264-
}
265-
return;
266-
}
267-
}
268-
269-
// if we couldn't pull settings from the client,
270-
// we'll try parsing the passed in params.
271-
let opts = self.parse_config_from_client(params.settings).await;
272-
273-
if opts
274-
.as_ref()
275-
.is_some_and(|o| o.db_connection_string.is_some())
276-
{
277-
let conn_str = opts.unwrap().db_connection_string.unwrap();
278-
match self.session.change_db(conn_str).await {
279-
Ok(_) => {}
280-
Err(err) => {
281-
self.client
282-
.show_message(
283-
MessageType::ERROR,
284-
format!(
285-
"Used Client Options from params but failed to set them: {}",
286-
err
287-
),
288-
)
289-
.await
290-
}
291-
}
292-
}
290+
self.request_and_handle_config_from_client().await
291+
} else {
292+
self.parse_and_handle_config_from_client(params.settings)
293+
.await
294+
};
293295
}
294296

295297
#[tracing::instrument(
@@ -332,13 +334,9 @@ impl LanguageServer for LspServer {
332334

333335
self.publish_diagnostics(uri).await;
334336

335-
// TODO: "Compute Now"
336337
let changed_urls = self.session.recompute_and_get_changed_files().await;
337338
for url in changed_urls {
338339
let url = Url::from_file_path(url.as_path()).expect("Expected absolute File Path");
339-
340-
tracing::info!("publishing diagnostics: {}", url);
341-
342340
self.publish_diagnostics(url).await;
343341
}
344342
}

crates/pg_lsp/src/session.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ impl Session {
4343
/// If the passed-in connection string is the same that we're already connected to, it's a noop.
4444
/// Otherwise, it'll first open a new connection, replace `Self`'s connection, and then close
4545
/// the old one.
46+
#[tracing::instrument(name = "Updating DB Connection", skip(self))]
4647
pub async fn change_db(&self, connection_string: String) -> anyhow::Result<()> {
4748
if self
4849
.db
@@ -55,17 +56,20 @@ impl Session {
5556
return Ok(());
5657
}
5758

59+
tracing::info!("Setting up new Database connection");
5860
let new_db = DbConnection::new(connection_string, Arc::clone(&self.ide)).await?;
61+
tracing::info!("Set up new connection, trying to acquire write lock…");
5962

6063
let mut current_db = self.db.write().await;
6164
let old_db = current_db.replace(new_db);
62-
drop(current_db);
6365

6466
if old_db.is_some() {
67+
tracing::info!("Dropping previous Database Connection.");
6568
let old_db = old_db.unwrap();
6669
old_db.close().await;
6770
}
6871

72+
tracing::info!("Successfully set up new connection.");
6973
Ok(())
7074
}
7175

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
version: "3.8"
22
services:
33
db:
4+
# postgres://postgres:[email protected]:5432/postgres
45
image: postgres
56
restart: always
67
environment:

editors/code/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,13 @@
8484
],
8585
"default": "off",
8686
"description": "Traces the communication between VS Code and the language server."
87+
},
88+
"pglsp.databaseUrl": {
89+
"type": "string",
90+
"default": "",
91+
"description": "Your Postgres Database URL"
8792
}
8893
}
8994
}
9095
}
91-
}
96+
}

0 commit comments

Comments
 (0)